diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 60821829451..097f2079005 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3159,6 +3159,19 @@ android:value="true" /> + + + + + + + + + diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index 5f90353b9c9..eb79c251710 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -20,7 +20,6 @@ package com.android.settings; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; -import android.app.DialogFragment; import android.app.FragmentManager; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; @@ -35,7 +34,6 @@ import android.os.Bundle; import android.os.PersistableBundle; import android.os.UserHandle; import android.os.UserManager; -import android.os.storage.StorageManager; import android.provider.SearchIndexableResource; import android.provider.Settings; import android.security.KeyStore; @@ -52,11 +50,14 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; + import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; import com.android.settings.TrustAgentUtils.TrustAgentComponentInfo; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.fingerprint.FingerprintSettings; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Index; import com.android.settings.search.Indexable; @@ -64,6 +65,9 @@ import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.RestrictedSwitchPreference; +import com.android.settingslib.drawer.CategoryKey; +import com.android.settingslib.drawer.DashboardCategory; +import com.android.settingslib.drawer.Tile; import java.util.ArrayList; import java.util.List; @@ -79,6 +83,7 @@ public class SecuritySettings extends SettingsPreferenceFragment GearPreference.OnGearClickListener { private static final String TAG = "SecuritySettings"; + private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent"; private static final Intent TRUST_AGENT_INTENT = new Intent(TrustAgentService.SERVICE_INTERFACE); @@ -125,6 +130,7 @@ public class SecuritySettings extends SettingsPreferenceFragment private static final int MY_USER_ID = UserHandle.myUserId(); + private DashboardFeatureProvider mDashboardFeatureProvider; private DevicePolicyManager mDPM; private SubscriptionManager mSubscriptionManager; private UserManager mUm; @@ -162,17 +168,22 @@ public class SecuritySettings extends SettingsPreferenceFragment public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mSubscriptionManager = SubscriptionManager.from(getActivity()); + final Activity activity = getActivity(); - mLockPatternUtils = new LockPatternUtils(getActivity()); + mSubscriptionManager = SubscriptionManager.from(activity); - mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), MY_USER_ID); + mLockPatternUtils = new LockPatternUtils(activity); + + mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, MY_USER_ID); mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); - mUm = UserManager.get(getActivity()); + mUm = UserManager.get(activity); - mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity()); + mChooseLockSettingsHelper = new ChooseLockSettingsHelper(activity); + + mDashboardFeatureProvider = FeatureFactory.getFactory(activity) + .getDashboardFeatureProvider(activity); if (savedInstanceState != null && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) { @@ -399,6 +410,13 @@ public class SecuritySettings extends SettingsPreferenceFragment Index.getInstance(getActivity()) .updateFromClassNameResource(SecuritySettings.class.getName(), true, true); + final List tilePrefs = getDynamicTilesForSecurity(); + if (tilePrefs != null && !tilePrefs.isEmpty()) { + for (Preference preference : tilePrefs) { + root.addPreference(preference); + } + } + for (int i = 0; i < SWITCH_PREFERENCE_KEYS.length; i++) { final Preference pref = findPreference(SWITCH_PREFERENCE_KEYS[i]); if (pref != null) pref.setOnPreferenceChangeListener(this); @@ -745,6 +763,31 @@ public class SecuritySettings extends SettingsPreferenceFragment SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE, extras); } + private List getDynamicTilesForSecurity() { + if (!mDashboardFeatureProvider.isEnabled()) { + return null; + } + final DashboardCategory category = + mDashboardFeatureProvider.getTilesForCategory(CategoryKey.CATEGORY_SECURITY); + if (category == null) { + Log.d(TAG, "NO dashboard tiles for " + TAG); + return null; + } + final List tiles = category.tiles; + if (tiles == null) { + Log.d(TAG, "tile list is empty, skipping category " + category.title); + return null; + } + final List preferences = new ArrayList<>(); + for (Tile tile : tiles) { + final Preference pref = new Preference(getPrefContext()); + mDashboardFeatureProvider + .bindPreferenceToTile(getActivity(), pref, tile, null /* key */); + preferences.add(pref); + } + return preferences; + } + @Override public boolean onPreferenceChange(Preference preference, Object value) { boolean result = true; @@ -1053,7 +1096,6 @@ public class SecuritySettings extends SettingsPreferenceFragment if (root != null) { root.removeAll(); } - root = null; final int resid = getResIdForLockUnlockSubScreen(getActivity(), new LockPatternUtils(getContext()), diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 432dec34c7a..eff20047f48 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -289,6 +289,8 @@ public class SettingsActivity extends SettingsDrawerActivity // Home page > Network & Internet "com.android.settings.Settings.WifiDashboardAlias", "com.android.settings.Settings.DataUsageDashboardAlias", + // Home page > Security + "com.android.settings.Settings.LocationDashboardAlias", // Home page > System "com.android.settings.Settings.LanguageAndInputDashboardAlias", "com.android.settings.Settings.DateTimeDashboardAlias", diff --git a/src/com/android/settings/dashboard/DashboardFeatureProvider.java b/src/com/android/settings/dashboard/DashboardFeatureProvider.java index 0a8dbbfb97e..8601f1d73ff 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProvider.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProvider.java @@ -15,6 +15,7 @@ */ package com.android.settings.dashboard; +import android.app.Activity; import android.content.Context; import android.support.v7.preference.Preference; @@ -55,6 +56,16 @@ public interface DashboardFeatureProvider { */ String getDashboardKeyForTile(Tile tile); + /** + * Binds preference to data provided by tile. + * + * @param activity If tile contains intent to launch, it will be launched from this activity + * @param pref The preference to bind data + * @param tile The binding data + * @param key They key for preference. If null, we will generate one from tile data + */ + void bindPreferenceToTile(Activity activity, Preference pref, Tile tile, String key); + /** * Returns a {@link ProgressiveDisclosureMixin} for specified fragment. */ diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java index ed0520af511..448028124e7 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java @@ -16,10 +16,15 @@ package com.android.settings.dashboard; +import android.app.Activity; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.os.Bundle; import android.support.v7.preference.Preference; +import android.text.TextUtils; +import com.android.settings.SettingsActivity; import com.android.settingslib.drawer.CategoryManager; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; @@ -73,6 +78,40 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { return sb.toString(); } + @Override + public void bindPreferenceToTile(Activity activity, Preference pref, Tile tile, String key) { + pref.setTitle(tile.title); + if (!TextUtils.isEmpty(key)) { + pref.setKey(key); + } else { + pref.setKey(getDashboardKeyForTile(tile)); + } + pref.setSummary(tile.summary); + if (tile.icon != null) { + pref.setIcon(tile.icon.loadDrawable(activity)); + } + final Bundle metadata = tile.metaData; + String clsName = null; + if (metadata != null) { + clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS); + } + if (!TextUtils.isEmpty(clsName)) { + pref.setFragment(clsName); + } else if (tile.intent != null) { + final Intent intent = new Intent(tile.intent); + pref.setOnPreferenceClickListener(preference -> { + activity.startActivityForResult(intent, 0); + return true; + }); + } + // Use negated priority for order, because tile priority is based on intent-filter + // (larger value has higher priority). However pref order defines smaller value has + // higher priority. + if (tile.priority != 0) { + pref.setOrder(-tile.priority); + } + } + @Override public ProgressiveDisclosureMixin getProgressiveDisclosureMixin(Context context, DashboardFragment fragment) { diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java index d76fe7ad732..3bbec09c912 100644 --- a/src/com/android/settings/dashboard/DashboardFragment.java +++ b/src/com/android/settings/dashboard/DashboardFragment.java @@ -17,7 +17,6 @@ package com.android.settings.dashboard; import android.app.Activity; import android.content.Context; -import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -34,7 +33,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.core.PreferenceController; import com.android.settings.overlay.FeatureFactory; @@ -322,11 +320,12 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment // Have the key already, will rebind. final Preference preference = mProgressiveDisclosureMixin.findPreference( screen, key); - bindPreferenceToTile(context, preference, tile, key); + mDashboardFeatureProvider.bindPreferenceToTile( + getActivity(), preference, tile, key); } else { // Don't have this key, add it. final Preference pref = new DashboardTilePreference(context); - bindPreferenceToTile(context, pref, tile, key); + mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), pref, tile, key); mProgressiveDisclosureMixin.addPreference(screen, pref); mDashboardTilePrefKeys.add(key); } @@ -338,32 +337,4 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment mProgressiveDisclosureMixin.removePreference(screen, key); } } - - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - void bindPreferenceToTile(Context context, Preference pref, Tile tile, String key) { - pref.setTitle(tile.title); - pref.setKey(key); - pref.setSummary(tile.summary); - if (tile.icon != null) { - pref.setIcon(tile.icon.loadDrawable(context)); - } - final Bundle metadata = tile.metaData; - String clsName = null; - if (metadata != null) { - clsName = metadata.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS); - } - if (!TextUtils.isEmpty(clsName)) { - pref.setFragment(clsName); - } else if (tile.intent != null) { - final Intent intent = new Intent(tile.intent); - pref.setOnPreferenceClickListener(preference -> { - getActivity().startActivityForResult(intent, 0); - return true; - }); - } - // Use negated priority for order, because tile priority is based on intent-filter - // (larger value has higher priority). However pref order defines smaller value has - // higher priority. - pref.setOrder(-tile.priority); - } } diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java new file mode 100644 index 00000000000..66f2289122f --- /dev/null +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.dashboard; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.Icon; +import android.os.Bundle; +import android.support.v7.preference.Preference; + +import com.android.settings.SettingsActivity; +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settingslib.drawer.Tile; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowApplication; + +import static com.google.common.truth.Truth.assertThat; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class DashboardFeatureProviderImplTest { + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Activity mActivity; + + private DashboardFeatureProviderImpl mImpl; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mImpl = new DashboardFeatureProviderImpl(mActivity); + } + + @Test + public void bindPreference_shouldBindAllData() { + final Preference preference = new Preference( + ShadowApplication.getInstance().getApplicationContext()); + final Tile tile = new Tile(); + tile.title = "title"; + tile.summary = "summary"; + tile.icon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)); + tile.metaData = new Bundle(); + tile.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI"); + tile.priority = 10; + mImpl.bindPreferenceToTile(mActivity, preference, tile, "123"); + + assertThat(preference.getTitle()).isEqualTo(tile.title); + assertThat(preference.getSummary()).isEqualTo(tile.summary); + assertThat(preference.getIcon()).isNotNull(); + assertThat(preference.getFragment()) + .isEqualTo(tile.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS)); + assertThat(preference.getOrder()).isEqualTo(-tile.priority); + } + + @Test + public void bindPreference_noFragmentMetadata_shouldBindIntent() { + final Preference preference = new Preference( + ShadowApplication.getInstance().getApplicationContext()); + final Tile tile = new Tile(); + tile.metaData = new Bundle(); + tile.priority = 10; + tile.intent = new Intent(); + mImpl.bindPreferenceToTile(mActivity, preference, tile, "123"); + + assertThat(preference.getFragment()).isNull(); + assertThat(preference.getOnPreferenceClickListener()).isNotNull(); + assertThat(preference.getOrder()).isEqualTo(-tile.priority); + } + + @Test + public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() { + final Preference preference = new Preference( + ShadowApplication.getInstance().getApplicationContext()); + final Tile tile = new Tile(); + tile.intent = new Intent(); + tile.intent.setComponent(new ComponentName("pkg", "class")); + mImpl.bindPreferenceToTile(mActivity, preference, tile, null /* key */); + + assertThat(preference.getKey()).isNotNull(); + assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER); + } +} diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java index f47a244d2d8..ce4dd682f0b 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java @@ -119,42 +119,6 @@ public class DashboardFragmentTest { verify(mTestFragment.mScreen, never()).addPreference(any(DashboardTilePreference.class)); } - @Test - public void bindPreference_shouldBindAllData() { - final Preference preference = new Preference( - ShadowApplication.getInstance().getApplicationContext()); - final Tile tile = new Tile(); - tile.title = "title"; - tile.summary = "summary"; - tile.icon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)); - tile.metaData = new Bundle(); - tile.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI"); - tile.priority = 10; - mTestFragment.bindPreferenceToTile(mContext, preference, tile, "123"); - - assertThat(preference.getTitle()).isEqualTo(tile.title); - assertThat(preference.getSummary()).isEqualTo(tile.summary); - assertThat(preference.getIcon()).isNotNull(); - assertThat(preference.getFragment()) - .isEqualTo(tile.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS)); - assertThat(preference.getOrder()).isEqualTo(-tile.priority); - } - - @Test - public void bindPreference_noFragmentMetadata_shouldBindIntent() { - final Preference preference = new Preference( - ShadowApplication.getInstance().getApplicationContext()); - final Tile tile = new Tile(); - tile.metaData = new Bundle(); - tile.priority = 10; - tile.intent = new Intent(); - mTestFragment.bindPreferenceToTile(mContext, preference, tile, "123"); - - assertThat(preference.getFragment()).isNull(); - assertThat(preference.getOnPreferenceClickListener()).isNotNull(); - assertThat(preference.getOrder()).isEqualTo(-tile.priority); - } - @Test public void updateState_skipUnavailablePrefs() { List preferenceControllers = mTestFragment.mControllers;