package com.mapbox.mapboxsdk.testapp.activity; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.adapter.FeatureAdapter; import com.mapbox.mapboxsdk.testapp.adapter.FeatureSectionAdapter; import com.mapbox.mapboxsdk.testapp.model.activity.Feature; import com.mapbox.mapboxsdk.testapp.utils.ItemClickSupport; import com.mapbox.services.android.telemetry.permissions.PermissionsListener; import com.mapbox.services.android.telemetry.permissions.PermissionsManager; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import timber.log.Timber; /** * Activity shown when application is started *

* This activity will generate data for RecyclerView based on the AndroidManifest entries. * It uses tags as category and description to order the different entries. *

*/ public class FeatureOverviewActivity extends AppCompatActivity implements PermissionsListener { private static final String KEY_STATE_FEATURES = "featureList"; private PermissionsManager permissionsManager; private RecyclerView recyclerView; private FeatureSectionAdapter sectionAdapter; private List features; private int locationActivityInList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_feature_overview); permissionsManager = new PermissionsManager(this); recyclerView = (RecyclerView) findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener()); recyclerView.setHasFixedSize(true); ItemClickSupport.addTo(recyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() { @Override public void onItemClicked(RecyclerView recyclerView, int position, View view) { if (!sectionAdapter.isSectionHeaderPosition(position)) { int itemPosition = sectionAdapter.getConvertedPosition(position); Feature feature = features.get(itemPosition); if (feature.isRequiresLocationPermission()) { if (requestLocationPermission(itemPosition)) { return; } } startFeature(feature); } } }); if (savedInstanceState == null) { loadFeatures(); } else { features = savedInstanceState.getParcelableArrayList(KEY_STATE_FEATURES); onFeaturesLoaded(features); } } private void loadFeatures() { try { new LoadFeatureTask().execute( getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA)); } catch (PackageManager.NameNotFoundException exception) { Timber.e("Could not resolve package info", exception); } } private void onFeaturesLoaded(List featuresList) { features = featuresList; List sections = new ArrayList<>(); String currentCat = ""; for (int i = 0; i < features.size(); i++) { String category = features.get(i).getCategory(); if (!currentCat.equals(category)) { sections.add(new FeatureSectionAdapter.Section(i, category)); currentCat = category; } } FeatureSectionAdapter.Section[] dummy = new FeatureSectionAdapter.Section[sections.size()]; sectionAdapter = new FeatureSectionAdapter( this, R.layout.section_main_layout, R.id.section_text, new FeatureAdapter(features)); sectionAdapter.setSections(sections.toArray(dummy)); recyclerView.setAdapter(sectionAdapter); } private void startFeature(Feature feature) { Intent intent = new Intent(); intent.setComponent(new ComponentName(getPackageName(), feature.getName())); startActivity(intent); } private boolean requestLocationPermission(final int positionInList) { if (isRuntimePermissionsRequired()) { locationActivityInList = positionInList; permissionsManager.requestLocationPermissions(this); return true; } return false; } @Override public void onExplanationNeeded(List list) { Snackbar.make( findViewById(android.R.id.content), TextUtils.join("", list.toArray()), Snackbar.LENGTH_SHORT).show(); } @Override public void onPermissionResult(boolean isPermissionGranted) { if (isPermissionGranted) { startFeature(features.get(locationActivityInList)); } else { Snackbar.make( findViewById(android.R.id.content), "Can't open without accepting the location permission.", Snackbar.LENGTH_SHORT).show(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults); } private boolean isRuntimePermissionsRequired() { return android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelableArrayList(KEY_STATE_FEATURES, (ArrayList) features); } private class LoadFeatureTask extends AsyncTask> { @Override protected List doInBackground(PackageInfo... params) { List features = new ArrayList<>(); PackageInfo app = params[0]; String packageName = getApplicationContext().getPackageName(); String metaDataKey = getString(R.string.category); for (ActivityInfo info : app.activities) { if (info.labelRes != 0 && info.name.startsWith(packageName) && !info.name.equals(FeatureOverviewActivity.class.getName())) { String label = getString(info.labelRes); String description = resolveString(info.descriptionRes); String category = resolveMetaData(info.metaData, metaDataKey); boolean requiresLocationPermission = requiresLocationPermission(label, category); features.add(new Feature(info.name, label, description, category, requiresLocationPermission)); } } if (!features.isEmpty()) { Comparator comparator = new Comparator() { @Override public int compare(Feature lhs, Feature rhs) { int result = lhs.getCategory().compareToIgnoreCase(rhs.getCategory()); if (result == 0) { result = lhs.getLabel().compareToIgnoreCase(rhs.getLabel()); } return result; } }; Collections.sort(features, comparator); } return features; } private String resolveMetaData(Bundle bundle, String key) { String category = null; if (bundle != null) { category = bundle.getString(key); } return category; } private String resolveString(@StringRes int stringRes) { try { return getString(stringRes); } catch (Resources.NotFoundException exception) { return "-"; } } private boolean requiresLocationPermission(String name, String category) { final Resources resources = getResources(); List requiresPermissionCategories = new ArrayList() { { add(resources.getString(R.string.category_userlocation)); } }; List requiresPermissionActivities = new ArrayList() { { add(resources.getString(R.string.activity_double_map)); } }; return requiresPermissionCategories.contains(category) || requiresPermissionActivities.contains(name); } @Override protected void onPostExecute(List features) { super.onPostExecute(features); onFeaturesLoaded(features); } } }