From 4b78bcd5cdff81168b5b08f72764ec9a5c0405c3 Mon Sep 17 00:00:00 2001 From: Christopher Dombroski Date: Tue, 16 Apr 2019 12:22:56 -0700 Subject: [PATCH 01/22] Treat mode_default as denied for install_unknown_apps Test: atest SettingsRoboTests Bug: 123700348 Change-Id: Ieeb6456854cc3d0faa0e9c407accd94f56a25813 Merged-In: Ieeb6456854cc3d0faa0e9c407accd94f56a25813 --- .../applications/AppStateInstallAppsBridge.java | 13 +++---------- .../applications/AppStateInstallAppsBridgeTest.java | 4 +++- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/applications/AppStateInstallAppsBridge.java b/src/com/android/settings/applications/AppStateInstallAppsBridge.java index cc7fb62c40c..ea27f3d039e 100644 --- a/src/com/android/settings/applications/AppStateInstallAppsBridge.java +++ b/src/com/android/settings/applications/AppStateInstallAppsBridge.java @@ -94,8 +94,6 @@ public class AppStateInstallAppsBridge extends AppStateBaseBridge { final InstallAppsState appState = new InstallAppsState(); appState.permissionRequested = hasRequestedAppOpPermission( Manifest.permission.REQUEST_INSTALL_PACKAGES, packageName); - appState.permissionGranted = hasPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES, - uid); appState.appOpMode = getAppOpMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, uid, packageName); return appState; @@ -106,7 +104,6 @@ public class AppStateInstallAppsBridge extends AppStateBaseBridge { */ public static class InstallAppsState { boolean permissionRequested; - boolean permissionGranted; int appOpMode; public InstallAppsState() { @@ -114,11 +111,7 @@ public class AppStateInstallAppsBridge extends AppStateBaseBridge { } public boolean canInstallApps() { - if (appOpMode == AppOpsManager.MODE_DEFAULT) { - return permissionGranted; - } else { - return appOpMode == AppOpsManager.MODE_ALLOWED; - } + return appOpMode == AppOpsManager.MODE_ALLOWED; } public boolean isPotentialAppSource() { @@ -127,8 +120,8 @@ public class AppStateInstallAppsBridge extends AppStateBaseBridge { @Override public String toString() { - StringBuilder sb = new StringBuilder("[permissionGranted: " + permissionGranted); - sb.append(", permissionRequested: " + permissionRequested); + StringBuilder sb = new StringBuilder(); + sb.append("[permissionRequested: " + permissionRequested); sb.append(", appOpMode: " + appOpMode); sb.append("]"); return sb.toString(); diff --git a/tests/robotests/src/com/android/settings/applications/AppStateInstallAppsBridgeTest.java b/tests/robotests/src/com/android/settings/applications/AppStateInstallAppsBridgeTest.java index 3076080060c..7618d447f90 100644 --- a/tests/robotests/src/com/android/settings/applications/AppStateInstallAppsBridgeTest.java +++ b/tests/robotests/src/com/android/settings/applications/AppStateInstallAppsBridgeTest.java @@ -38,8 +38,10 @@ public class AppStateInstallAppsBridgeTest { .InstallAppsState(); assertThat(appState.canInstallApps()).isFalse(); - appState.permissionGranted = true; appState.permissionRequested = true; + assertThat(appState.canInstallApps()).isFalse(); + + appState.appOpMode = AppOpsManager.MODE_ALLOWED; assertThat(appState.canInstallApps()).isTrue(); appState.appOpMode = AppOpsManager.MODE_ERRORED; From eb2e8dd22c43429e8925a178db43559b4c000f54 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 29 Apr 2019 10:21:18 -0700 Subject: [PATCH 02/22] Add an interface that returns time spent text for app. Bug: 129266977 Test: robotest Change-Id: Iaa5b4c5504eccbe0290b1014bd8e25aa3d4c3dd8 --- .../applications/ApplicationFeatureProvider.java | 8 ++++++++ .../ApplicationFeatureProviderImpl.java | 2 +- .../appinfo/TimeSpentInAppPreferenceController.java | 11 ++++++++++- .../TimeSpentInAppPreferenceControllerTest.java | 13 +++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/applications/ApplicationFeatureProvider.java b/src/com/android/settings/applications/ApplicationFeatureProvider.java index 3ffacb0bc16..e9f877e79bf 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProvider.java +++ b/src/com/android/settings/applications/ApplicationFeatureProvider.java @@ -81,6 +81,14 @@ public interface ApplicationFeatureProvider { */ Set getKeepEnabledPackages(); + /** + * Returns a user readable text explaining how much time user has spent in an app at a + * pre-specified duration. + */ + default CharSequence getTimeSpentInApp(String packageName) { + return null; + } + /** * Callback that receives the number of packages installed on the device. */ diff --git a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java index 7027239f52e..1fd79971c80 100644 --- a/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java +++ b/src/com/android/settings/applications/ApplicationFeatureProviderImpl.java @@ -41,7 +41,7 @@ import java.util.Set; public class ApplicationFeatureProviderImpl implements ApplicationFeatureProvider { - private final Context mContext; + protected final Context mContext; private final PackageManager mPm; private final IPackageManager mPms; private final DevicePolicyManager mDpm; diff --git a/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java b/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java index 70ffcb3f8e5..b1bbd06e9d6 100644 --- a/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceController.java @@ -28,7 +28,9 @@ import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import com.android.settings.applications.ApplicationFeatureProvider; import com.android.settings.core.BasePreferenceController; +import com.android.settings.overlay.FeatureFactory; import java.util.List; @@ -38,13 +40,15 @@ public class TimeSpentInAppPreferenceController extends BasePreferenceController static final Intent SEE_TIME_IN_APP_TEMPLATE = new Intent(Settings.ACTION_APP_USAGE_SETTINGS); private final PackageManager mPackageManager; - + private final ApplicationFeatureProvider mAppFeatureProvider; private Intent mIntent; private String mPackageName; public TimeSpentInAppPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mPackageManager = context.getPackageManager(); + mAppFeatureProvider = FeatureFactory.getFactory(context) + .getApplicationFeatureProvider(context); } public void setPackageName(String packageName) { @@ -80,6 +84,11 @@ public class TimeSpentInAppPreferenceController extends BasePreferenceController } } + @Override + public CharSequence getSummary() { + return mAppFeatureProvider.getTimeSpentInApp(mPackageName); + } + private boolean isSystemApp(ResolveInfo info) { return info != null && info.activityInfo != null diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceControllerTest.java index 94d12288d28..e1da707e543 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/TimeSpentInAppPreferenceControllerTest.java @@ -20,6 +20,8 @@ import static android.content.Intent.EXTRA_PACKAGE_NAME; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; @@ -32,6 +34,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; import org.junit.Test; @@ -58,10 +61,12 @@ public class TimeSpentInAppPreferenceControllerTest { private ShadowPackageManager mPackageManager; private TimeSpentInAppPreferenceController mController; private Preference mPreference; + private FakeFeatureFactory mFeatureFactory; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mFeatureFactory = FakeFeatureFactory.setupForTest(); mContext = RuntimeEnvironment.application; mPackageManager = Shadows.shadowOf(mContext.getPackageManager()); mController = new TimeSpentInAppPreferenceController(mContext, TEST_KEY); @@ -112,4 +117,12 @@ public class TimeSpentInAppPreferenceControllerTest { assertThat(intent.getStringExtra(EXTRA_PACKAGE_NAME)) .isEqualTo(TEST_INTENT.getStringExtra(EXTRA_PACKAGE_NAME)); } + + @Test + public void getSummary_shouldQueryAppFeatureProvider() { + mController.getSummary(); + + verify(mFeatureFactory.applicationFeatureProvider).getTimeSpentInApp( + nullable(String.class)); + } } From 608ad6f632f3ee8787ee59cf8c56cb8c592c506b Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Thu, 11 Apr 2019 19:24:39 -0700 Subject: [PATCH 03/22] Hide display white balance setting depending on accessibility To avoid conflicting with display accessibility features, hide the display white balance setting when these features are active. Bug: 130263943 Test: make ROBOTEST_FILTER=DisplayWhiteBalancePreferenceControllerTest RunSettingsRoboTests -j32 Change-Id: I9936a657521287a7a0482f2a934430bd79013cf3 --- ...splayWhiteBalancePreferenceController.java | 84 +++++++++- ...yWhiteBalancePreferenceControllerTest.java | 144 +++++++++++++++--- 2 files changed, 203 insertions(+), 25 deletions(-) diff --git a/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java b/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java index dc569aaa1da..6fc0b0e10e4 100644 --- a/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java +++ b/src/com/android/settings/display/DisplayWhiteBalancePreferenceController.java @@ -13,17 +13,34 @@ */ package com.android.settings.display; +import android.app.ActivityManager; +import android.content.ContentResolver; import android.content.Context; +import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.provider.Settings.Secure; +import android.provider.Settings.System; import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settings.core.TogglePreferenceController; -public class DisplayWhiteBalancePreferenceController extends TogglePreferenceController { +public class DisplayWhiteBalancePreferenceController extends TogglePreferenceController + implements LifecycleObserver, OnStart, OnStop { private ColorDisplayManager mColorDisplayManager; + @VisibleForTesting + ContentObserver mContentObserver; + private Preference mPreference; public DisplayWhiteBalancePreferenceController(Context context, String key) { super(context, key); @@ -31,12 +48,8 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon @Override public int getAvailabilityStatus() { - // Display white balance is only valid in linear light space. COLOR_MODE_SATURATED implies - // unmanaged color mode, and hence unknown color processing conditions. - return ColorDisplayManager.isDisplayWhiteBalanceAvailable(mContext) && - getColorDisplayManager().getColorMode() != - ColorDisplayManager.COLOR_MODE_SATURATED ? - AVAILABLE : DISABLED_FOR_USER; + return getColorDisplayManager().isDisplayWhiteBalanceAvailable(mContext) ? + AVAILABLE : DISABLED_FOR_USER; } @Override @@ -49,6 +62,50 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon return getColorDisplayManager().setDisplayWhiteBalanceEnabled(isChecked); } + @Override + public void onStart() { + if (!isAvailable()) { + return; + } + + final ContentResolver cr = mContext.getContentResolver(); + mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange, Uri uri) { + super.onChange(selfChange, uri); + updateVisibility(); + } + }; + cr.registerContentObserver( + Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED), + false /* notifyForDescendants */, mContentObserver, + ActivityManager.getCurrentUser()); + cr.registerContentObserver( + Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED), + false /* notifyForDescendants */, mContentObserver, + ActivityManager.getCurrentUser()); + cr.registerContentObserver( + System.getUriFor(System.DISPLAY_COLOR_MODE), + false /* notifyForDescendants */, mContentObserver, + ActivityManager.getCurrentUser()); + + updateVisibility(); + } + + @Override + public void onStop() { + if (mContentObserver != null) { + mContext.getContentResolver().unregisterContentObserver(mContentObserver); + mContentObserver = null; + } + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + @VisibleForTesting ColorDisplayManager getColorDisplayManager() { if (mColorDisplayManager == null) { @@ -56,4 +113,17 @@ public class DisplayWhiteBalancePreferenceController extends TogglePreferenceCon } return mColorDisplayManager; } + + @VisibleForTesting + void updateVisibility() { + if (mPreference != null) { + ColorDisplayManager cdm = getColorDisplayManager(); + + // Display white balance is only valid in linear light space. COLOR_MODE_SATURATED + // implies unmanaged color mode, and hence unknown color processing conditions. + // We also disallow display white balance when color accessibility features are enabled. + mPreference.setVisible(cdm.getColorMode() != ColorDisplayManager.COLOR_MODE_SATURATED && + !cdm.areAccessibilityTransformsEnabled(mContext)); + } + } } diff --git a/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java index d0dbc0bb5e0..dfc13de8e14 100644 --- a/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/DisplayWhiteBalancePreferenceControllerTest.java @@ -1,16 +1,27 @@ package com.android.settings.display; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static com.google.common.truth.Truth.assertThat; + +import android.content.ContentResolver; +import android.content.Context; import android.hardware.display.ColorDisplayManager; +import android.provider.Settings; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.After; 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.RobolectricTestRunner; @@ -27,6 +38,15 @@ public class DisplayWhiteBalancePreferenceControllerTest { @Mock private ColorDisplayManager mColorDisplayManager; + private ContentResolver mContentResolver; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private PreferenceScreen mScreen; + @Mock + private Preference mPreference; + + private final String PREFERENCE_KEY = "display_white_balance"; @After public void tearDown() { @@ -36,17 +56,21 @@ public class DisplayWhiteBalancePreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mController = spy(new DisplayWhiteBalancePreferenceController(RuntimeEnvironment.application, - "display_white_balance")); + + mContentResolver = RuntimeEnvironment.application.getContentResolver(); + when(mContext.getContentResolver()).thenReturn(mContentResolver); + when(mContext.getResources()).thenReturn(RuntimeEnvironment.application.getResources()); + when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mPreference); + + mController = spy(new DisplayWhiteBalancePreferenceController(mContext, PREFERENCE_KEY)); doReturn(mColorDisplayManager).when(mController).getColorDisplayManager(); } @Test - public void isAvailable_configuredAvailable() { + public void isAvailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); - when(mColorDisplayManager.getColorMode()) - .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); + assertThat(mController.isAvailable()).isTrue(); } @@ -54,20 +78,7 @@ public class DisplayWhiteBalancePreferenceControllerTest { public void isAvailable_configuredUnavailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); - when(mColorDisplayManager.getColorMode()) - .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); - assertThat(mController.isAvailable()).isFalse(); - SettingsShadowResources.overrideResource( - com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); - when(mColorDisplayManager.getColorMode()) - .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); - assertThat(mController.isAvailable()).isFalse(); - - SettingsShadowResources.overrideResource( - com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); - when(mColorDisplayManager.getColorMode()) - .thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); assertThat(mController.isAvailable()).isFalse(); } @@ -94,4 +105,101 @@ public class DisplayWhiteBalancePreferenceControllerTest { when(mColorDisplayManager.isDisplayWhiteBalanceEnabled()).thenReturn(false); assertThat(mController.isChecked()).isFalse(); } + + @Test + public void onStart_configuredUnavailable() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_displayWhiteBalanceAvailable, false); + mController.displayPreference(mScreen); + mController.onStart(); + assertThat(mController.mContentObserver).isNull(); + } + + @Test + public void onStart_configuredAvailable() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); + when(mColorDisplayManager.getColorMode()) + .thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); + toggleAccessibilityInversion(false); + toggleAccessibilityDaltonizer(false); + + mController.displayPreference(mScreen); + mController.onStart(); + assertThat(mController.mContentObserver).isNotNull(); + } + + @Test + public void visibility_configuredAvailableAccessibilityToggled() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); + mController.displayPreference(mScreen); + + // Accessibility features disabled + toggleAccessibilityInversion(false); + reset(mPreference); + mController.updateVisibility(); + verify(mPreference).setVisible(true); + + toggleAccessibilityDaltonizer(false); + reset(mPreference); + mController.updateVisibility(); + verify(mPreference).setVisible(true); + + // Accessibility features enabled one by one + toggleAccessibilityInversion(true); + mController.updateVisibility(); + verify(mPreference).setVisible(false); + + toggleAccessibilityDaltonizer(true); + reset(mPreference); + mController.updateVisibility(); + verify(mPreference).setVisible(false); + + // Accessibility features disabled one by one + toggleAccessibilityInversion(false); + reset(mPreference); + mController.updateVisibility(); + // Daltonizer is still enabled, so we expect the preference to still be invisible + verify(mPreference).setVisible(false); + + // Now both a11y features are disabled, so we expect the preference to become visible + toggleAccessibilityDaltonizer(false); + mController.updateVisibility(); + verify(mPreference).setVisible(true); + } + + @Test + public void visibility_configuredAvailableColorModeChanged() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_displayWhiteBalanceAvailable, true); + mController.displayPreference(mScreen); + + // Non-Saturated color mode selected + when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); + reset(mPreference); + mController.updateVisibility(); + verify(mPreference).setVisible(true); + + // Saturated color mode selected + when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_SATURATED); + mController.updateVisibility(); + verify(mPreference).setVisible(false); + + // Switch back to non-Saturated color mode + when(mColorDisplayManager.getColorMode()).thenReturn(ColorDisplayManager.COLOR_MODE_NATURAL); + reset(mPreference); + mController.updateVisibility(); + verify(mPreference).setVisible(true); + } + + private void toggleAccessibilityInversion(boolean enable) { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, enable ? 1 : 0); + } + + private void toggleAccessibilityDaltonizer(boolean enable) { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, enable ? 1 : 0); + } } From 7bc5f91289e4179a84bd9a6ec7d62d9abc681053 Mon Sep 17 00:00:00 2001 From: JeiFeng Lee Date: Thu, 2 May 2019 08:32:01 +0800 Subject: [PATCH 04/22] [PATCH] Buttons in storage settings Due to changes in layout of storage wizard base, 2 extra buttons are shown on progress screen while formatting SD card and also on other screens which have storage wizard base as their super class. Hence when these buttons were clicked unsupported exception takes place. Hide these unnecessary next/back buttons from all screen so that user cannot click these. Fixes: 131779469 Test: manual Change-Id: I235a180627e68bbb38f4ed4e7ac58ae38838c8d7 Signed-off-by: JeiFeng Lee --- .../android/settings/deviceinfo/StorageWizardBase.java | 8 ++++++++ .../settings/deviceinfo/StorageWizardFormatProgress.java | 4 +++- .../android/settings/deviceinfo/StorageWizardInit.java | 2 +- .../settings/deviceinfo/StorageWizardMigrateProgress.java | 4 +++- .../settings/deviceinfo/StorageWizardMoveConfirm.java | 1 + .../settings/deviceinfo/StorageWizardMoveProgress.java | 4 +++- .../android/settings/deviceinfo/StorageWizardReady.java | 1 + 7 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/deviceinfo/StorageWizardBase.java b/src/com/android/settings/deviceinfo/StorageWizardBase.java index 38733891901..92afa56cc0a 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardBase.java +++ b/src/com/android/settings/deviceinfo/StorageWizardBase.java @@ -187,6 +187,14 @@ public abstract class StorageWizardBase extends FragmentActivity { mNext.setVisibility(View.VISIBLE); } + protected void setBackButtonVisibility(int visible) { + mBack.setVisibility(visible); + } + + protected void setNextButtonVisibility(int visible) { + mNext.setVisibility(visible); + } + protected void setIcon(int resId) { final GlifLayout layout = getGlifLayout(); final Drawable icon = getDrawable(resId).mutate(); diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java index 1e8c1691bc2..88968b3bd2a 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java +++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java @@ -30,6 +30,7 @@ import android.os.SystemProperties; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.util.Log; +import android.view.View; import android.widget.Toast; import com.android.settings.R; @@ -59,7 +60,8 @@ public class StorageWizardFormatProgress extends StorageWizardBase { setHeaderText(R.string.storage_wizard_format_progress_title, getDiskShortDescription()); setBodyText(R.string.storage_wizard_format_progress_body, getDiskDescription()); - + setBackButtonVisibility(View.INVISIBLE); + setNextButtonVisibility(View.INVISIBLE); mTask = (PartitionTask) getLastCustomNonConfigurationInstance(); if (mTask == null) { mTask = new PartitionTask(); diff --git a/src/com/android/settings/deviceinfo/StorageWizardInit.java b/src/com/android/settings/deviceinfo/StorageWizardInit.java index 4f9c5e7aba0..426395c24fe 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardInit.java +++ b/src/com/android/settings/deviceinfo/StorageWizardInit.java @@ -51,7 +51,7 @@ public class StorageWizardInit extends StorageWizardBase { mInternal = requireViewById(R.id.storage_wizard_init_internal); setBackButtonText(R.string.storage_wizard_init_v2_later); - + setNextButtonVisibility(View.INVISIBLE); if (!mDisk.isAdoptable()) { // If not adoptable, we only have one choice mInternal.setEnabled(false); diff --git a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java index 60f3cb5d4cb..b6f2a8d2fa4 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java +++ b/src/com/android/settings/deviceinfo/StorageWizardMigrateProgress.java @@ -28,6 +28,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.storage.DiskInfo; import android.util.Log; +import android.view.View; import android.widget.Toast; import com.android.settings.R; @@ -51,7 +52,8 @@ public class StorageWizardMigrateProgress extends StorageWizardBase { setIcon(R.drawable.ic_swap_horiz); setHeaderText(R.string.storage_wizard_migrate_progress_v2_title); setAuxChecklist(); - + setBackButtonVisibility(View.INVISIBLE); + setNextButtonVisibility(View.INVISIBLE); // Register for updates and push through current status getPackageManager().registerMoveCallback(mCallback, new Handler()); mCallback.onStatusChanged(mMoveId, getPackageManager().getMoveStatus(mMoveId), -1); diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java index 10b78af0d7a..8dc878e24af 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java +++ b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java @@ -73,6 +73,7 @@ public class StorageWizardMoveConfirm extends StorageWizardBase { setBodyText(R.string.storage_wizard_move_confirm_body, appName, volumeName); setNextButtonText(R.string.move_app); + setBackButtonVisibility(View.INVISIBLE); } @Override diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java index 27fa9beb532..1966c9534ae 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java +++ b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java @@ -26,6 +26,7 @@ import android.content.pm.PackageManager.MoveCallback; import android.os.Bundle; import android.os.Handler; import android.util.Log; +import android.view.View; import android.widget.Toast; import com.android.settings.R; @@ -49,7 +50,8 @@ public class StorageWizardMoveProgress extends StorageWizardBase { setIcon(R.drawable.ic_swap_horiz); setHeaderText(R.string.storage_wizard_move_progress_title, appName); setBodyText(R.string.storage_wizard_move_progress_body, volumeName, appName); - + setBackButtonVisibility(View.INVISIBLE); + setNextButtonVisibility(View.INVISIBLE); // Register for updates and push through current status getPackageManager().registerMoveCallback(mCallback, new Handler()); mCallback.onStatusChanged(mMoveId, getPackageManager().getMoveStatus(mMoveId), -1); diff --git a/src/com/android/settings/deviceinfo/StorageWizardReady.java b/src/com/android/settings/deviceinfo/StorageWizardReady.java index fdb8d8a4938..813bcc6e201 100644 --- a/src/com/android/settings/deviceinfo/StorageWizardReady.java +++ b/src/com/android/settings/deviceinfo/StorageWizardReady.java @@ -50,6 +50,7 @@ public class StorageWizardReady extends StorageWizardBase { } setNextButtonText(R.string.done); + setBackButtonVisibility(View.INVISIBLE); } @Override From 133ffc9c57b89ee998a64365ab82105017608cdf Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Tue, 30 Apr 2019 11:58:32 +0800 Subject: [PATCH 05/22] Show admin dialog when preference is disabled by Device Admin Fixes: 130694312 Test: manual & robotest Change-Id: I9c6487ac056ec3d784bd6f6901e96869e27e0b3e --- .../RoamingPreferenceController.java | 7 +++--- .../RoamingPreferenceControllerTest.java | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.java b/src/com/android/settings/network/telephony/RoamingPreferenceController.java index 4140d5d9709..dd5fd0e8fef 100644 --- a/src/com/android/settings/network/telephony/RoamingPreferenceController.java +++ b/src/com/android/settings/network/telephony/RoamingPreferenceController.java @@ -33,7 +33,6 @@ import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settings.core.TogglePreferenceController; import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; @@ -114,8 +113,10 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro public void updateState(Preference preference) { super.updateState(preference); final RestrictedSwitchPreference switchPreference = (RestrictedSwitchPreference) preference; - switchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID); - switchPreference.setChecked(isChecked()); + if (!switchPreference.isDisabledByAdmin()) { + switchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID); + switchPreference.setChecked(isChecked()); + } } @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java index ce61a898a6e..a883c51075b 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java @@ -18,9 +18,12 @@ package com.android.settings.network.telephony; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; import android.os.PersistableBundle; @@ -76,7 +79,7 @@ public class RoamingPreferenceControllerTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID); doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction(); - mPreference = new RestrictedSwitchPreference(mContext); + mPreference = spy(new RestrictedSwitchPreference(mContext)); mController = new RoamingPreferenceController(mContext, "roaming"); mController.init(mFragmentManager, SUB_ID); mPreference.setKey(mController.getPreferenceKey()); @@ -140,4 +143,22 @@ public class RoamingPreferenceControllerTest { assertThat(mPreference.isEnabled()).isTrue(); assertThat(mPreference.isChecked()).isTrue(); } + + @Test + public void updateState_isNotDisabledByAdmin_shouldInvokeSetEnabled() { + when(mPreference.isDisabledByAdmin()).thenReturn(false); + + mController.updateState(mPreference); + + verify(mPreference).setEnabled(anyBoolean()); + } + + @Test + public void updateState_isDisabledByAdmin_shouldNotInvokeSetEnabled() { + when(mPreference.isDisabledByAdmin()).thenReturn(true); + + mController.updateState(mPreference); + + verify(mPreference, never()).setEnabled(anyBoolean()); + } } From 45423baaae6126a5b2cdc03cd24c9b375dd63ed9 Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Tue, 7 May 2019 12:50:30 -0700 Subject: [PATCH 06/22] Increate max height of sliceView To make sure it can have 8 devices at maximum. Fixes: 130357332 Test: Manual Change-Id: I4274a04d1dd8447b9b5904a77af2723e4637f22a --- res/values/dimens.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index a348f8ad4fc..09ab682cde9 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -409,5 +409,5 @@ 80dp - 360dp + 480dp From cfd0a66f7bcc65cc40aa456a365809db0f529424 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 2 May 2019 16:43:34 -0700 Subject: [PATCH 07/22] Disable settings preferences when the packages do not exist Bug: 131273934 Test: make RunSettingsRoboTests ROBOTEST_FILTER=SystemNavigationLegacyPreferenceControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=SystemNavigationSwipeUpPreferenceControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=SystemNavigationEdgeToEdgePreferenceControllerTest Change-Id: I5b12831d0eacbaa9c8b13d7a7b380b8c99f20009 --- ...igationEdgeToEdgePreferenceController.java | 2 +- ...mNavigationLegacyPreferenceController.java | 2 +- .../SystemNavigationPreferenceController.java | 30 ++++++++++++++++--- ...NavigationSwipeUpPreferenceController.java | 2 +- ...ionEdgeToEdgePreferenceControllerTest.java | 6 ++++ ...igationLegacyPreferenceControllerTest.java | 6 ++++ ...gationSwipeUpPreferenceControllerTest.java | 6 ++++ 7 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceController.java b/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceController.java index 11ff0949b05..959b6ca8ab3 100644 --- a/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceController.java +++ b/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceController.java @@ -39,7 +39,7 @@ public class SystemNavigationEdgeToEdgePreferenceController extends @VisibleForTesting public SystemNavigationEdgeToEdgePreferenceController(Context context, IOverlayManager overlayManager, String key) { - super(context, overlayManager, key); + super(context, overlayManager, key, NAV_BAR_MODE_GESTURAL_OVERLAY); } @Override diff --git a/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceController.java b/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceController.java index 0b197845599..1adf8ef6cfa 100644 --- a/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceController.java +++ b/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceController.java @@ -39,7 +39,7 @@ public class SystemNavigationLegacyPreferenceController extends @VisibleForTesting public SystemNavigationLegacyPreferenceController(Context context, IOverlayManager overlayManager, String key) { - super(context, overlayManager, key); + super(context, overlayManager, key, NAV_BAR_MODE_3BUTTON_OVERLAY); } @Override diff --git a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java index f2c8252be39..664e7bb2b42 100644 --- a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java +++ b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java @@ -52,16 +52,18 @@ public abstract class SystemNavigationPreferenceController extends GesturePrefer protected final IOverlayManager mOverlayManager; protected PreferenceScreen mPreferenceScreen; + private final String mOverlayPackage; public SystemNavigationPreferenceController(Context context, IOverlayManager overlayManager, - String key) { + String key, String overlayPackage) { super(context, key); mOverlayManager = overlayManager; + mOverlayPackage = overlayPackage; } @Override public int getAvailabilityStatus() { - return isGestureAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return isGestureAvailable(mContext, mOverlayPackage) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override @@ -105,23 +107,43 @@ public abstract class SystemNavigationPreferenceController extends GesturePrefer return PREF_KEY_VIDEO; } + static boolean isGestureAvailable(Context context) { + return isGestureAvailable(context, null /* overlayPackage */); + } + + static boolean isGestureAvailable(Context context, String overlayPackage) { + // Skip if the swipe up settings are not available if (!context.getResources().getBoolean( com.android.internal.R.bool.config_swipe_up_gesture_setting_available)) { return false; } + // Skip if the recents component is not defined final ComponentName recentsComponentName = ComponentName.unflattenFromString( context.getString(com.android.internal.R.string.config_recentsComponentName)); if (recentsComponentName == null) { return false; } + + // Skip if the overview proxy service exists + final PackageManager pm = context.getPackageManager(); final Intent quickStepIntent = new Intent(ACTION_QUICKSTEP) .setPackage(recentsComponentName.getPackageName()); - if (context.getPackageManager().resolveService(quickStepIntent, - PackageManager.MATCH_SYSTEM_ONLY) == null) { + if (pm.resolveService(quickStepIntent, PackageManager.MATCH_SYSTEM_ONLY) == null) { return false; } + + // Skip if the required overlay package is defined but doesn't exist + if (overlayPackage != null) { + try { + return pm.getPackageInfo(overlayPackage, 0 /* flags */) != null; + } catch (PackageManager.NameNotFoundException e) { + // Not found, just return unavailable + return false; + } + } + return true; } diff --git a/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceController.java b/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceController.java index 26c2201a1e5..5db16726aa3 100644 --- a/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceController.java +++ b/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceController.java @@ -39,7 +39,7 @@ public class SystemNavigationSwipeUpPreferenceController extends @VisibleForTesting public SystemNavigationSwipeUpPreferenceController(Context context, IOverlayManager overlayManager, String key) { - super(context, overlayManager, key); + super(context, overlayManager, key, NAV_BAR_MODE_2BUTTON_OVERLAY); } @Override diff --git a/tests/robotests/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceControllerTest.java index 740ff2cae29..03c0b7364d3 100644 --- a/tests/robotests/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/SystemNavigationEdgeToEdgePreferenceControllerTest.java @@ -130,6 +130,12 @@ public class SystemNavigationEdgeToEdgePreferenceControllerTest { .isFalse(); } + @Test + public void testIsGestureAvailable_noOverlayPackage_shouldReturnFalse() { + assertThat(SystemNavigationEdgeToEdgePreferenceController.isGestureAvailable(mContext, + "com.package.fake")).isFalse(); + } + @Test public void testIsChecked_defaultIsEdgeToEdge_shouldReturnTrue() { SettingsShadowResources.overrideResource(R.integer.config_navBarInteractionMode, diff --git a/tests/robotests/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceControllerTest.java index 2c4f88a09ad..4f9e9f14b85 100644 --- a/tests/robotests/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/SystemNavigationLegacyPreferenceControllerTest.java @@ -130,6 +130,12 @@ public class SystemNavigationLegacyPreferenceControllerTest { SystemNavigationLegacyPreferenceController.isGestureAvailable(mContext)).isFalse(); } + @Test + public void testIsGestureAvailable_noOverlayPackage_shouldReturnFalse() { + assertThat(SystemNavigationLegacyPreferenceController.isGestureAvailable(mContext, + "com.package.fake")).isFalse(); + } + @Test public void testIsChecked_defaultIsLegacy_shouldReturnTrue() { SettingsShadowResources.overrideResource(R.integer.config_navBarInteractionMode, diff --git a/tests/robotests/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceControllerTest.java index 177d4987d1d..509080bc3a5 100644 --- a/tests/robotests/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/SystemNavigationSwipeUpPreferenceControllerTest.java @@ -130,6 +130,12 @@ public class SystemNavigationSwipeUpPreferenceControllerTest { .isFalse(); } + @Test + public void testIsGestureAvailable_noOverlayPackage_shouldReturnFalse() { + assertThat(SystemNavigationSwipeUpPreferenceController.isGestureAvailable(mContext, + "com.package.fake")).isFalse(); + } + @Test public void testIsChecked_defaultIsSwipeUp_shouldReturnTrue() { SettingsShadowResources.overrideResource(R.integer.config_navBarInteractionMode, From 2659c0f61bd96136ff92341e3e5a5ae3cc929fcd Mon Sep 17 00:00:00 2001 From: Aaron Heuckroth Date: Thu, 2 May 2019 11:04:42 -0400 Subject: [PATCH 08/22] Create Settings preference for Global Actions Panel. Test: Automated tests pass. Bug: 127295457 Change-Id: I6502d4c8541a3f279fb96d5f050f13890db8f376 --- res/raw/gesture_global_actions_panel.mp4 | 0 res/values/strings.xml | 11 +++ res/xml/gestures.xml | 6 ++ res/xml/global_actions_panel_settings.xml | 40 +++++++++ ...lobalActionsPanelPreferenceController.java | 69 +++++++++++++++ .../gestures/GlobalActionsPanelSettings.java | 62 +++++++++++++ ...lActionsPanelPreferenceControllerTest.java | 88 +++++++++++++++++++ 7 files changed, 276 insertions(+) create mode 100644 res/raw/gesture_global_actions_panel.mp4 create mode 100644 res/xml/global_actions_panel_settings.xml create mode 100644 src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java create mode 100644 src/com/android/settings/gestures/GlobalActionsPanelSettings.java create mode 100644 tests/robotests/src/com/android/settings/gestures/GlobalActionsPanelPreferenceControllerTest.java diff --git a/res/raw/gesture_global_actions_panel.mp4 b/res/raw/gesture_global_actions_panel.mp4 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/res/values/strings.xml b/res/values/strings.xml index a31de98fb42..af94db3a358 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7264,6 +7264,8 @@ work challenge, work, profile work profile, managed profile, unify, unification, work, profile gestures + + global actions pay, tap, payments backup, back up gesture @@ -10148,6 +10150,15 @@ To check time, notifications, and other info, tap your screen. + + To show the global actions panel, press & hold Power button + + Show global actions + + Global actions + + The global actions panel can be accessed even when the device is locked. + Swipe fingerprint for notifications diff --git a/res/xml/gestures.xml b/res/xml/gestures.xml index 8515bd71892..5dcb1b02d01 100644 --- a/res/xml/gestures.xml +++ b/res/xml/gestures.xml @@ -75,4 +75,10 @@ android:fragment="com.android.settings.gestures.PreventRingingGestureSettings" settings:controller="com.android.settings.gestures.PreventRingingParentPreferenceController" /> + + diff --git a/res/xml/global_actions_panel_settings.xml b/res/xml/global_actions_panel_settings.xml new file mode 100644 index 00000000000..af155bc74fc --- /dev/null +++ b/res/xml/global_actions_panel_settings.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java b/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java new file mode 100644 index 00000000000..07d303ba0ad --- /dev/null +++ b/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 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.gestures; + +import android.content.Context; +import android.provider.Settings; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; + +public class GlobalActionsPanelPreferenceController extends GesturePreferenceController { + private static final String PREF_KEY_VIDEO = "global_actions_panel_video"; + + // TODO (b/132182180) -- Use Secure Settings constants instead of hard-coded strings + @VisibleForTesting + protected static final String ENABLED_SETTING = "global_actions_panel_enabled"; + // TODO (b/132182180) -- Use Secure Settings constants instead of hard-coded strings + @VisibleForTesting + protected static final String AVAILABLE_SETTING = "global_actions_panel_available"; + + @VisibleForTesting + protected static final String TOGGLE_KEY = "gesture_global_actions_panel_switch"; + + public GlobalActionsPanelPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + int enabled = Settings.Secure.getInt(mContext.getContentResolver(), AVAILABLE_SETTING, 0); + return enabled == 1 ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public boolean setChecked(boolean isChecked) { + return Settings.Secure.putInt(mContext.getContentResolver(), ENABLED_SETTING, + isChecked ? 1 : 0); + } + + @Override + protected String getVideoPrefKey() { + return PREF_KEY_VIDEO; + } + + @Override + public boolean isSliceable() { + return TextUtils.equals(getPreferenceKey(), TOGGLE_KEY); + } + + @Override + public boolean isChecked() { + int enabled = Settings.Secure.getInt(mContext.getContentResolver(), ENABLED_SETTING, 0); + return enabled == 1; + } +} diff --git a/src/com/android/settings/gestures/GlobalActionsPanelSettings.java b/src/com/android/settings/gestures/GlobalActionsPanelSettings.java new file mode 100644 index 00000000000..0ace61f0c05 --- /dev/null +++ b/src/com/android/settings/gestures/GlobalActionsPanelSettings.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 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.gestures; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.provider.SearchIndexableResource; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.SearchIndexable; + +import java.util.Arrays; +import java.util.List; + +@SearchIndexable +public class GlobalActionsPanelSettings extends DashboardFragment { + + private static final String TAG = "GlobalActionsPanelSettings"; + + // TODO (132184167): Use correct settings constant + @Override + public int getMetricsCategory() { + return SettingsEnums.SETTINGS_GESTURES; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.global_actions_panel_settings; + } + + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.global_actions_panel_settings; + return Arrays.asList(sir); + } + }; +} diff --git a/tests/robotests/src/com/android/settings/gestures/GlobalActionsPanelPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/GlobalActionsPanelPreferenceControllerTest.java new file mode 100644 index 00000000000..1fed7df6059 --- /dev/null +++ b/tests/robotests/src/com/android/settings/gestures/GlobalActionsPanelPreferenceControllerTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 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.gestures; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.provider.Settings; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class GlobalActionsPanelPreferenceControllerTest { + + private Context mContext; + private GlobalActionsPanelPreferenceController mController; + + private static final String KEY_GESTURE_PANEL = "gesture_global_actions_panel"; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new GlobalActionsPanelPreferenceController(mContext, KEY_GESTURE_PANEL); + } + + @Test + public void testIsChecked_panelEnabled() { + Settings.Secure.putInt( + mContext.getContentResolver(), mController.ENABLED_SETTING, 1); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void testIsChecked_panelDisabled() { + Settings.Secure.putInt( + mContext.getContentResolver(), mController.ENABLED_SETTING, 0); + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void getAvailabilityStatus_panelAvailable() { + Settings.Secure.putInt( + mContext.getContentResolver(), mController.AVAILABLE_SETTING, 1); + assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_panelUnavailable() { + Settings.Secure.putInt( + mContext.getContentResolver(), mController.AVAILABLE_SETTING, 0); + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(mController.CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void isSliceable_correctKey() { + final GlobalActionsPanelPreferenceController controller = + new GlobalActionsPanelPreferenceController(mContext, mController.TOGGLE_KEY); + assertThat(controller.isSliceable()).isTrue(); + } + + @Test + public void isSliceable_incorrectKey() { + final GlobalActionsPanelPreferenceController controller = + new GlobalActionsPanelPreferenceController(mContext, "bad_key"); + assertThat(controller.isSliceable()).isFalse(); + } +} From b8e81544ef5f4ad0c33c1a542b64853f2aebac08 Mon Sep 17 00:00:00 2001 From: Aran Ink Date: Tue, 7 May 2019 16:36:56 -0400 Subject: [PATCH 09/22] Use correct constants for Global Actions Panel settings. Test: Automated tests pass. Manual testing allows enabling/disabling of secure setting via Settings preference. Fixes: 132182180 Fixes: 132184167 Change-Id: I62caccfe64e073c95b0c0f8a42e5728cf7f3c1ca --- .../gestures/GlobalActionsPanelPreferenceController.java | 7 +++---- .../settings/gestures/GlobalActionsPanelSettings.java | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java b/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java index 07d303ba0ad..b980499ef90 100644 --- a/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java +++ b/src/com/android/settings/gestures/GlobalActionsPanelPreferenceController.java @@ -25,12 +25,11 @@ import com.android.internal.annotations.VisibleForTesting; public class GlobalActionsPanelPreferenceController extends GesturePreferenceController { private static final String PREF_KEY_VIDEO = "global_actions_panel_video"; - // TODO (b/132182180) -- Use Secure Settings constants instead of hard-coded strings @VisibleForTesting - protected static final String ENABLED_SETTING = "global_actions_panel_enabled"; - // TODO (b/132182180) -- Use Secure Settings constants instead of hard-coded strings + protected static final String ENABLED_SETTING = Settings.Secure.GLOBAL_ACTIONS_PANEL_ENABLED; @VisibleForTesting - protected static final String AVAILABLE_SETTING = "global_actions_panel_available"; + protected static final String AVAILABLE_SETTING = + Settings.Secure.GLOBAL_ACTIONS_PANEL_AVAILABLE; @VisibleForTesting protected static final String TOGGLE_KEY = "gesture_global_actions_panel_switch"; diff --git a/src/com/android/settings/gestures/GlobalActionsPanelSettings.java b/src/com/android/settings/gestures/GlobalActionsPanelSettings.java index 0ace61f0c05..fe9a9e80cba 100644 --- a/src/com/android/settings/gestures/GlobalActionsPanelSettings.java +++ b/src/com/android/settings/gestures/GlobalActionsPanelSettings.java @@ -33,10 +33,9 @@ public class GlobalActionsPanelSettings extends DashboardFragment { private static final String TAG = "GlobalActionsPanelSettings"; - // TODO (132184167): Use correct settings constant @Override public int getMetricsCategory() { - return SettingsEnums.SETTINGS_GESTURES; + return SettingsEnums.GLOBAL_ACTIONS_PANEL_SETTINGS; } @Override From 547c975bcc4c169ec586fad26d3c2bf7ddc3816a Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 7 May 2019 13:43:38 -0700 Subject: [PATCH 10/22] Add flag to disable part of event_logging in Settings. - Fork SettingsEventLogWriter from EventLogWritter. This is identical to the base class except it overrides some logging method with a flag check. We can't entirely disable event_log logging because some of the stuff being logged will not exist in stats_log, for example paired metadata. Bug: 129697155 Test: robotest Change-Id: I9cd46bbb54cb85737bbf7760e315c1fe34f77498 --- .../settings/core/SettingsUIDeviceConfig.java | 5 + .../SettingsEventLogWriter.java | 71 ++++++++++ .../SettingsMetricsFeatureProvider.java | 17 ++- .../SettingsEventLogWriterTest.java | 122 ++++++++++++++++++ 4 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/core/instrumentation/SettingsEventLogWriter.java create mode 100644 tests/robotests/src/com/android/settings/core/instrumentation/SettingsEventLogWriterTest.java diff --git a/src/com/android/settings/core/SettingsUIDeviceConfig.java b/src/com/android/settings/core/SettingsUIDeviceConfig.java index b7aa281408d..8c85c82340c 100644 --- a/src/com/android/settings/core/SettingsUIDeviceConfig.java +++ b/src/com/android/settings/core/SettingsUIDeviceConfig.java @@ -33,4 +33,9 @@ public class SettingsUIDeviceConfig { * {@code true} if near by device suggestion is enabled in connected device page */ public static final String BT_NEAR_BY_SUGGESTION_ENABLED = "bt_near_by_suggestion_enabled"; + + /** + * {@code true} whether or not event_log for generic actions is enabled. Default is true. + */ + public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled"; } diff --git a/src/com/android/settings/core/instrumentation/SettingsEventLogWriter.java b/src/com/android/settings/core/instrumentation/SettingsEventLogWriter.java new file mode 100644 index 00000000000..a58555fe11f --- /dev/null +++ b/src/com/android/settings/core/instrumentation/SettingsEventLogWriter.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 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.core.instrumentation; + +import android.content.Context; +import android.provider.DeviceConfig; + +import com.android.settings.core.SettingsUIDeviceConfig; +import com.android.settingslib.core.instrumentation.EventLogWriter; + +public class SettingsEventLogWriter extends EventLogWriter { + + @Override + public void visible(Context context, int source, int category) { + if (shouldDisableGenericEventLogging()) { + return; + } + super.visible(context, source, category); + } + + @Override + public void hidden(Context context, int category) { + if (shouldDisableGenericEventLogging()) { + return; + } + super.hidden(context, category); + } + + @Override + public void action(Context context, int category, String pkg) { + if (shouldDisableGenericEventLogging()) { + return; + } + super.action(context, category, pkg); + } + + @Override + public void action(Context context, int category, int value) { + if (shouldDisableGenericEventLogging()) { + return; + } + super.action(context, category, value); + } + + @Override + public void action(Context context, int category, boolean value) { + if (shouldDisableGenericEventLogging()) { + return; + } + super.action(context, category, value); + } + + private static boolean shouldDisableGenericEventLogging() { + return !DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI, + SettingsUIDeviceConfig.GENERIC_EVENT_LOGGING_ENABLED, true /* default */); + } +} diff --git a/src/com/android/settings/core/instrumentation/SettingsMetricsFeatureProvider.java b/src/com/android/settings/core/instrumentation/SettingsMetricsFeatureProvider.java index ec057572053..01927fd2d53 100644 --- a/src/com/android/settings/core/instrumentation/SettingsMetricsFeatureProvider.java +++ b/src/com/android/settings/core/instrumentation/SettingsMetricsFeatureProvider.java @@ -17,14 +17,29 @@ package com.android.settings.core.instrumentation; import android.content.Context; +import android.util.Log; +import android.util.Pair; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class SettingsMetricsFeatureProvider extends MetricsFeatureProvider { + private static final String TAG = "SettingsMetricsFeature"; + @Override protected void installLogWriters() { - super.installLogWriters(); mLoggerWriters.add(new StatsLogWriter()); + mLoggerWriters.add(new SettingsEventLogWriter()); mLoggerWriters.add(new SettingsIntelligenceLogWriter()); } + + /** + * @deprecated Use {@link #action(int, int, int, String, int)} instead. + */ + @Deprecated + @Override + public void action(Context context, int category, Pair... taggedData) { + Log.w(TAG, "action(Pair... taggedData) is deprecated, " + + "Use action(int, int, int, String, int) instead."); + super.action(context, category, taggedData); + } } diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/SettingsEventLogWriterTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/SettingsEventLogWriterTest.java new file mode 100644 index 00000000000..ba2553de517 --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/instrumentation/SettingsEventLogWriterTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2019 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.core.instrumentation; + + +import static com.google.common.truth.Truth.assertThat; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.metrics.LogMaker; +import android.provider.DeviceConfig; + +import com.android.internal.logging.MetricsLogger; +import com.android.settings.core.SettingsUIDeviceConfig; +import com.android.settings.testutils.shadow.ShadowDeviceConfig; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowDeviceConfig.class, SettingsEventLogWriterTest.ShadowMetricsLogger.class}) +public class SettingsEventLogWriterTest { + + private SettingsEventLogWriter mWriter; + + @Before + public void setUp() { + mWriter = new SettingsEventLogWriter(); + } + + @After + public void tearDown() { + ShadowDeviceConfig.reset(); + ShadowMetricsLogger.reset(); + } + + @Test + public void visible_eventLogEnabled_shouldLog() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, + SettingsUIDeviceConfig.GENERIC_EVENT_LOGGING_ENABLED, "true", true); + + mWriter.visible(RuntimeEnvironment.application, SettingsEnums.PAGE_UNKNOWN, + SettingsEnums.SETTINGS_HOMEPAGE); + + assertThat(ShadowMetricsLogger.sActionLoggedCount).isEqualTo(1); + } + + @Test + public void hidden_eventLogEnabled_shouldLog() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, + SettingsUIDeviceConfig.GENERIC_EVENT_LOGGING_ENABLED, "true", true); + + mWriter.hidden(RuntimeEnvironment.application, SettingsEnums.SETTINGS_HOMEPAGE); + + assertThat(ShadowMetricsLogger.sActionLoggedCount).isEqualTo(1); + } + + @Test + public void visible_eventLogDisabled_shouldNotLog() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, + SettingsUIDeviceConfig.GENERIC_EVENT_LOGGING_ENABLED, "false", true); + + mWriter.visible(RuntimeEnvironment.application, SettingsEnums.PAGE_UNKNOWN, + SettingsEnums.SETTINGS_HOMEPAGE); + + assertThat(ShadowMetricsLogger.sActionLoggedCount).isEqualTo(0); + } + + @Test + public void hidden_eventLogDisabled_shouldNotLog() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, + SettingsUIDeviceConfig.GENERIC_EVENT_LOGGING_ENABLED, "false", true); + + mWriter.hidden(RuntimeEnvironment.application, SettingsEnums.SETTINGS_HOMEPAGE); + + assertThat(ShadowMetricsLogger.sActionLoggedCount).isEqualTo(0); + } + + @Implements(MetricsLogger.class) + public static class ShadowMetricsLogger { + + public static int sActionLoggedCount = 0; + + @Resetter + public static void reset() { + sActionLoggedCount = 0; + } + + @Implementation + protected static void action(LogMaker content) { + sActionLoggedCount++; + } + + @Implementation + public static void hidden(Context context, int category) throws IllegalArgumentException { + sActionLoggedCount++; + } + } + +} From 687b18067cb3bf28282376b311ece73b1c893254 Mon Sep 17 00:00:00 2001 From: Jonathan Scott Date: Tue, 30 Apr 2019 15:52:52 +0100 Subject: [PATCH 11/22] [RESTRICT AUTOMERGE] Make ScreenPinningSettings behaviour consistent with LockTaskController. Bug: 127605586 Test: Manual Change-Id: Id85632b5e6975fc5f92d6e8126a6603a07f097e1 --- .../settings/security/ScreenPinningSettings.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/security/ScreenPinningSettings.java b/src/com/android/settings/security/ScreenPinningSettings.java index 6e4856ee423..0af7b7273df 100644 --- a/src/com/android/settings/security/ScreenPinningSettings.java +++ b/src/com/android/settings/security/ScreenPinningSettings.java @@ -115,9 +115,13 @@ public class ScreenPinningSettings extends SettingsPreferenceFragment } private boolean isScreenLockUsed() { - int def = getCurrentSecurityTitle() != R.string.screen_pinning_unlock_none ? 1 : 0; - return Settings.Secure.getInt(getContentResolver(), - Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, def) != 0; + // This functionality should be kept consistent with + // com.android.server.wm.LockTaskController (see b/127605586) + int defaultValueIfSettingNull = mLockPatternUtils.isSecure(UserHandle.myUserId()) ? 1 : 0; + return Settings.Secure.getInt( + getContentResolver(), + Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, + defaultValueIfSettingNull) != 0; } private boolean setScreenLockUsed(boolean isEnabled) { From ac653b983821393b3f3255929e4534157fc48e03 Mon Sep 17 00:00:00 2001 From: joshmccloskey Date: Mon, 6 May 2019 15:11:34 -0700 Subject: [PATCH 12/22] Updated Face Enroll Introduction Test: Builds. Bug: 131774204 Change-Id: Ibccd54185b9d8ffbfd2678be1c8680ffb1699425 --- .../ic_face_enroll_introduction_people.xml | 42 +++++++++ .../ic_face_enroll_introduction_shield.xml | 45 +++++++++ ...ic_face_enroll_introduction_visibility.xml | 45 +++++++++ res/layout/face_enroll_introduction.xml | 92 +++++++++++-------- res/values/strings.xml | 8 +- .../face/FaceEnrollIntroduction.java | 44 --------- 6 files changed, 192 insertions(+), 84 deletions(-) create mode 100644 res/drawable/ic_face_enroll_introduction_people.xml create mode 100644 res/drawable/ic_face_enroll_introduction_shield.xml create mode 100644 res/drawable/ic_face_enroll_introduction_visibility.xml diff --git a/res/drawable/ic_face_enroll_introduction_people.xml b/res/drawable/ic_face_enroll_introduction_people.xml new file mode 100644 index 00000000000..b452efe14fd --- /dev/null +++ b/res/drawable/ic_face_enroll_introduction_people.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/ic_face_enroll_introduction_shield.xml b/res/drawable/ic_face_enroll_introduction_shield.xml new file mode 100644 index 00000000000..09d3909cbe1 --- /dev/null +++ b/res/drawable/ic_face_enroll_introduction_shield.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/ic_face_enroll_introduction_visibility.xml b/res/drawable/ic_face_enroll_introduction_visibility.xml new file mode 100644 index 00000000000..04ff21f4cac --- /dev/null +++ b/res/drawable/ic_face_enroll_introduction_visibility.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml index 3115bb4ca2f..535a531ba9f 100644 --- a/res/layout/face_enroll_introduction.xml +++ b/res/layout/face_enroll_introduction.xml @@ -1,6 +1,6 @@ Use your face to unlock your phone, authorize purchases, or sign in to apps - - + + + + + + Center your face in the circle diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index 6887d51e598..a5434a9aed1 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -23,9 +23,6 @@ import android.content.Intent; import android.hardware.face.FaceManager; import android.os.Bundle; import android.text.TextUtils; -import android.view.View; -import android.widget.Button; -import android.widget.CompoundButton; import android.widget.TextView; import com.android.settings.R; @@ -38,51 +35,18 @@ import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.template.FooterButton; import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.span.LinkSpan; -import com.google.android.setupdesign.view.IllustrationVideoView; public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { private static final String TAG = "FaceIntro"; private FaceManager mFaceManager; - private FaceEnrollAccessibilityToggle mSwitchDiversity; - - private IllustrationVideoView mIllustrationNormal; - private View mIllustrationAccessibility; - - private CompoundButton.OnCheckedChangeListener mSwitchDiversityListener = - new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - mIllustrationNormal.stop(); - mIllustrationNormal.setVisibility(View.INVISIBLE); - mIllustrationAccessibility.setVisibility(View.VISIBLE); - } else { - mIllustrationNormal.setVisibility(View.VISIBLE); - mIllustrationNormal.start(); - mIllustrationAccessibility.setVisibility(View.INVISIBLE); - } - } - }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mFaceManager = Utils.getFaceManagerOrNull(this); - final Button accessibilityButton = findViewById(R.id.accessibility_button); - accessibilityButton.setOnClickListener(view -> { - mSwitchDiversity.setChecked(true); - accessibilityButton.setVisibility(View.GONE); - mSwitchDiversity.setVisibility(View.VISIBLE); - }); - - mSwitchDiversity = findViewById(R.id.toggle_diversity); - mSwitchDiversity.setListener(mSwitchDiversityListener); - - mIllustrationNormal = findViewById(R.id.illustration_normal); - mIllustrationAccessibility = findViewById(R.id.illustration_accessibility); mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class); if (WizardManagerHelper.isAnySetupWizard(getIntent())) { @@ -115,13 +79,6 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { ); } - @Override - protected void onResume() { - super.onResume(); - mSwitchDiversityListener.onCheckedChanged(mSwitchDiversity.getSwitch(), - mSwitchDiversity.isChecked()); - } - @Override protected boolean isDisabledByAdmin() { return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled( @@ -209,7 +166,6 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { } else { intent.setClass(this, FaceEnrollEnrolling.class); } - intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, !mSwitchDiversity.isChecked()); WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent); return intent; } From 4bb253358be93ae3c881cb7d9e77cc22ddfa3353 Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Tue, 7 May 2019 16:01:09 -0700 Subject: [PATCH 13/22] Fix two problems related to data connectivity in the multi-SIM header When you have multiple active SIMs, the Network & internet page has a header showing entries for each one, with summary text indicating which one is used for data (and whether it is just set as the default, or actively using data). We were not properly setting this text when either data wasn't being used, eg when connected to wifi, or mobile data was disabled for this SIM. This CL fixes both these problems by adding new helper classes to listen for relevant events. Test: make RunSettingsRoboTests Fixes: 124394250 Fixes: 128857712 Change-Id: I34f2679752fa41a50247dd0b12581cbfd77a34f6 --- .../network/MobileDataEnabledListener.java | 69 +++++++++++ .../SubscriptionsPreferenceController.java | 52 +++++++- .../telephony/DataConnectivityListener.java | 73 +++++++++++ .../network/DataConnectivityListenerTest.java | 116 ++++++++++++++++++ .../MobileDataEnabledListenerTest.java | 78 ++++++++++++ ...SubscriptionsPreferenceControllerTest.java | 38 +++++- 6 files changed, 419 insertions(+), 7 deletions(-) create mode 100644 src/com/android/settings/network/MobileDataEnabledListener.java create mode 100644 src/com/android/settings/network/telephony/DataConnectivityListener.java create mode 100644 tests/robotests/src/com/android/settings/network/DataConnectivityListenerTest.java create mode 100644 tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java diff --git a/src/com/android/settings/network/MobileDataEnabledListener.java b/src/com/android/settings/network/MobileDataEnabledListener.java new file mode 100644 index 00000000000..8344f886f7f --- /dev/null +++ b/src/com/android/settings/network/MobileDataEnabledListener.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 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.network; + +import android.content.Context; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; +import android.provider.Settings; +import android.telephony.SubscriptionManager; + +/** Helper class to listen for changes in the enabled state of mobile data. */ +public class MobileDataEnabledListener extends ContentObserver { + private Context mContext; + private Client mClient; + private int mSubId; + + public interface Client { + void onMobileDataEnabledChange(); + } + + public MobileDataEnabledListener(Context context, Client client) { + super(new Handler()); + mContext = context; + mClient = client; + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + /** Starts listening to changes in the enabled state for data on the given subscription id. */ + public void start(int subId) { + mSubId = subId; + Uri uri; + if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA); + } else { + uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + mSubId); + } + mContext.getContentResolver().registerContentObserver(uri, true /*notifyForDescendants*/, + this); + } + + public int getSubId() { + return mSubId; + } + + public MobileDataEnabledListener stop() { + mContext.getContentResolver().unregisterContentObserver(this); + return this; + } + + @Override + public void onChange(boolean selfChange) { + mClient.onMobileDataEnabledChange(); + } +} diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java index 88ff5cf247f..ae31b5643a9 100644 --- a/src/com/android/settings/network/SubscriptionsPreferenceController.java +++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java @@ -21,6 +21,9 @@ import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; import android.content.Context; import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -35,6 +38,7 @@ import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.network.telephony.DataConnectivityListener; import com.android.settings.network.telephony.MobileNetworkActivity; import com.android.settingslib.core.AbstractPreferenceController; @@ -46,14 +50,18 @@ import java.util.Map; * available if there are 2 or more subscriptions. */ public class SubscriptionsPreferenceController extends AbstractPreferenceController implements - LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient { + LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient, + MobileDataEnabledListener.Client, DataConnectivityListener.Client { private static final String TAG = "SubscriptionsPrefCntrlr"; private UpdateListener mUpdateListener; private String mPreferenceGroupKey; private PreferenceGroup mPreferenceGroup; private SubscriptionManager mManager; + private ConnectivityManager mConnectivityManager; private SubscriptionsChangeListener mSubscriptionsListener; + private MobileDataEnabledListener mDataEnabledListener; + private DataConnectivityListener mConnectivityListener; // Map of subscription id to Preference private Map mSubscriptionPreferences; @@ -89,20 +97,27 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mPreferenceGroupKey = preferenceGroupKey; mStartOrder = startOrder; mManager = context.getSystemService(SubscriptionManager.class); + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mSubscriptionPreferences = new ArrayMap<>(); mSubscriptionsListener = new SubscriptionsChangeListener(context, this); + mDataEnabledListener = new MobileDataEnabledListener(context, this); + mConnectivityListener = new DataConnectivityListener(context, this); lifecycle.addObserver(this); } @OnLifecycleEvent(ON_RESUME) public void onResume() { mSubscriptionsListener.start(); + mDataEnabledListener.start(SubscriptionManager.getDefaultDataSubscriptionId()); + mConnectivityListener.start(); update(); } @OnLifecycleEvent(ON_PAUSE) public void onPause() { mSubscriptionsListener.stop(); + mDataEnabledListener.stop(); + mConnectivityListener.stop(); } @Override @@ -158,6 +173,19 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mUpdateListener.onChildrenUpdated(); } + private boolean activeNetworkIsCellular() { + final Network activeNetwork = mConnectivityManager.getActiveNetwork(); + if (activeNetwork == null) { + return false; + } + final NetworkCapabilities networkCapabilities = mConnectivityManager.getNetworkCapabilities( + activeNetwork); + if (networkCapabilities == null) { + return false; + } + return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); + } + /** * The summary can have either 1 or 2 lines depending on which services (calls, SMS, data) this * subscription is the default for. @@ -187,10 +215,10 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl if (subId == dataDefaultSubId) { final TelephonyManager telMgrForSub = mContext.getSystemService( TelephonyManager.class).createForSubscriptionId(subId); - final int dataState = telMgrForSub.getDataState(); - if (dataState == TelephonyManager.DATA_CONNECTED) { + boolean dataEnabled = telMgrForSub.isDataEnabled(); + if (dataEnabled && activeNetworkIsCellular()) { line2 = mContext.getString(R.string.mobile_data_active); - } else if (!telMgrForSub.isDataEnabled()) { + } else if (!dataEnabled) { line2 = mContext.getString(R.string.mobile_data_off); } else { line2 = mContext.getString(R.string.default_for_mobile_data); @@ -231,6 +259,22 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl @Override public void onSubscriptionsChanged() { + // See if we need to change which sub id we're using to listen for enabled/disabled changes. + int defaultDataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + if (defaultDataSubId != mDataEnabledListener.getSubId()) { + mDataEnabledListener.stop(); + mDataEnabledListener.start(defaultDataSubId); + } + update(); + } + + @Override + public void onMobileDataEnabledChange() { + update(); + } + + @Override + public void onDataConnectivityChange() { update(); } } diff --git a/src/com/android/settings/network/telephony/DataConnectivityListener.java b/src/com/android/settings/network/telephony/DataConnectivityListener.java new file mode 100644 index 00000000000..adb39c64be0 --- /dev/null +++ b/src/com/android/settings/network/telephony/DataConnectivityListener.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 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.network.telephony; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; + +/** A helper class to listen to a few different kinds of connectivity changes that could be relevant + * to changes in which network is active, and whether the active network has internet data + * connectivity. */ +public class DataConnectivityListener extends ConnectivityManager.NetworkCallback { + private Context mContext; + private ConnectivityManager mConnectivityManager; + private final NetworkRequest mNetworkRequest; + private Client mClient; + + public interface Client { + void onDataConnectivityChange(); + } + + public DataConnectivityListener(Context context, Client client) { + mContext = context; + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); + mClient = client; + mNetworkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + } + + public void start() { + mConnectivityManager.registerNetworkCallback(mNetworkRequest, this, + mContext.getMainThreadHandler()); + } + + public void stop() { + mConnectivityManager.unregisterNetworkCallback(this); + } + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { + final Network activeNetwork = mConnectivityManager.getActiveNetwork(); + if (activeNetwork != null && activeNetwork.equals(network)) { + mClient.onDataConnectivityChange(); + } + } + + @Override + public void onLosing(Network network, int maxMsToLive) { + mClient.onDataConnectivityChange(); + } + + @Override + public void onLost(Network network) { + mClient.onDataConnectivityChange(); + } +} diff --git a/tests/robotests/src/com/android/settings/network/DataConnectivityListenerTest.java b/tests/robotests/src/com/android/settings/network/DataConnectivityListenerTest.java new file mode 100644 index 00000000000..b45e28c554c --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/DataConnectivityListenerTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2019 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.network; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Handler; + +import com.android.settings.network.telephony.DataConnectivityListener; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class DataConnectivityListenerTest { + @Mock + private DataConnectivityListener.Client mClient; + @Mock + private ConnectivityManager mConnectivityManager; + @Mock + private Network mActiveNetwork; + + private Context mContext; + private DataConnectivityListener mListener; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager); + when(mConnectivityManager.getActiveNetwork()).thenReturn(mActiveNetwork); + mListener = new DataConnectivityListener(mContext, mClient); + } + + @Test + public void noStart_doesNotRegister() { + verify(mConnectivityManager, never()).registerNetworkCallback(any(NetworkRequest.class), + any(ConnectivityManager.NetworkCallback.class), any(Handler.class)); + } + + @Test + public void start_doesRegister() { + mListener.start(); + verify(mConnectivityManager).registerNetworkCallback(any(NetworkRequest.class), + eq(mListener), any(Handler.class)); + } + + @Test + public void onCapabilitiesChanged_notActiveNetwork_noCallback() { + Network changedNetwork = mock(Network.class); + mListener.onCapabilitiesChanged(changedNetwork, mock(NetworkCapabilities.class)); + verify(mClient, never()).onDataConnectivityChange(); + } + + @Test + public void onCapabilitiesChanged_activeNetwork_onDataConnectivityChangeFires() { + mListener.onCapabilitiesChanged(mActiveNetwork, mock(NetworkCapabilities.class)); + verify(mClient).onDataConnectivityChange(); + } + + @Test + public void onLosing_notActiveNetwork_onDataConnectivityChangeFires() { + Network changedNetwork = mock(Network.class); + mListener.onLosing(changedNetwork, 500); + verify(mClient).onDataConnectivityChange(); + } + + @Test + public void onLosing_activeNetwork_onDataConnectivityChangeFires() { + mListener.onLosing(mActiveNetwork, 500); + verify(mClient).onDataConnectivityChange(); + } + + @Test + public void onLost_notActiveNetwork_onDataConnectivityChangeFires() { + Network changedNetwork = mock(Network.class); + mListener.onLost(changedNetwork); + verify(mClient).onDataConnectivityChange(); + } + + @Test + public void onLost_activeNetwork_onDataConnectivityChangeFires() { + mListener.onLost(mActiveNetwork); + verify(mClient).onDataConnectivityChange(); + } +} diff --git a/tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java b/tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java new file mode 100644 index 00000000000..0824680bf88 --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/MobileDataEnabledListenerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2019 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.network; + +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.net.Uri; +import android.provider.Settings; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class MobileDataEnabledListenerTest { + private static final int SUB_ID_ONE = 111; + private static final int SUB_ID_TWO = 222; + + @Mock + private MobileDataEnabledListener.Client mClient; + + private Context mContext; + private MobileDataEnabledListener mListener; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mListener = new MobileDataEnabledListener(mContext, mClient); + } + + @Test + public void onMobileDataEnabledChange_firesCorrectly() { + mListener.start(SUB_ID_ONE); + final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + SUB_ID_ONE); + mContext.getContentResolver().notifyChange(uri, null); + verify(mClient).onMobileDataEnabledChange(); + } + + @Test + public void onMobileDataEnabledChange_doesNotFireAfterStop() { + mListener.start(SUB_ID_ONE); + mListener.stop(); + final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + SUB_ID_ONE); + mContext.getContentResolver().notifyChange(uri, null); + verify(mClient, never()).onMobileDataEnabledChange(); + } + + @Test + public void onMobileDataEnabledChange_changedToDifferentId_firesCorrectly() { + mListener.start(SUB_ID_ONE); + mListener.stop(); + mListener.start(SUB_ID_TWO); + final Uri uri = Settings.Global.getUriFor(Settings.Global.MOBILE_DATA + SUB_ID_TWO); + mContext.getContentResolver().notifyChange(uri, null); + verify(mClient).onMobileDataEnabledChange(); + } +} diff --git a/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java index 26f26ff5505..d6edcc72a87 100644 --- a/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java @@ -33,6 +33,9 @@ import static org.mockito.Mockito.when; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; import android.provider.Settings; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -74,7 +77,13 @@ public class SubscriptionsPreferenceControllerTest { @Mock private SubscriptionManager mSubscriptionManager; @Mock + private ConnectivityManager mConnectivityManager; + @Mock private TelephonyManager mTelephonyManager; + @Mock + private Network mActiveNetwork; + @Mock + private NetworkCapabilities mCapabilities; private Context mContext; private LifecycleOwner mLifecycleOwner; @@ -90,7 +99,10 @@ public class SubscriptionsPreferenceControllerTest { mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); + when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager); when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + when(mConnectivityManager.getActiveNetwork()).thenReturn(mActiveNetwork); + when(mConnectivityManager.getNetworkCapabilities(mActiveNetwork)).thenReturn(mCapabilities); when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); when(mScreen.findPreference(eq(KEY))).thenReturn(mPreferenceCategory); when(mPreferenceCategory.getContext()).thenReturn(mContext); @@ -308,7 +320,8 @@ public class SubscriptionsPreferenceControllerTest { ShadowSubscriptionManager.setDefaultDataSubscriptionId(11); ShadowSubscriptionManager.setDefaultSmsSubscriptionId(11); ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(11); - when(mTelephonyManager.getDataState()).thenReturn(TelephonyManager.DATA_CONNECTED); + when(mTelephonyManager.isDataEnabled()).thenReturn(true); + when(mCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true); assertThat(mController.getSummary(11)).isEqualTo( mContext.getString(R.string.default_for_calls_and_sms) + System.lineSeparator() @@ -318,6 +331,27 @@ public class SubscriptionsPreferenceControllerTest { mContext.getString(R.string.subscription_available)); } + @Test + public void getSummary_twoSubsOneDefaultForEverythingDataNotActive() { + final SubscriptionInfo sub1 = mock(SubscriptionInfo.class); + final SubscriptionInfo sub2 = mock(SubscriptionInfo.class); + when(sub1.getSubscriptionId()).thenReturn(11); + when(sub2.getSubscriptionId()).thenReturn(22); + SubscriptionUtil.setActiveSubscriptionsForTesting(Arrays.asList(sub1, sub2)); + + ShadowSubscriptionManager.setDefaultDataSubscriptionId(11); + ShadowSubscriptionManager.setDefaultSmsSubscriptionId(11); + ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(11); + when(mTelephonyManager.isDataEnabled()).thenReturn(true); + + assertThat(mController.getSummary(11)).isEqualTo( + mContext.getString(R.string.default_for_calls_and_sms) + System.lineSeparator() + + mContext.getString(R.string.default_for_mobile_data)); + + assertThat(mController.getSummary(22)).isEqualTo( + mContext.getString(R.string.subscription_available)); + } + @Test public void getSummary_twoSubsOneDefaultForEverythingDataDisabled() { final SubscriptionInfo sub1 = mock(SubscriptionInfo.class); @@ -329,7 +363,6 @@ public class SubscriptionsPreferenceControllerTest { ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(11); ShadowSubscriptionManager.setDefaultSmsSubscriptionId(11); ShadowSubscriptionManager.setDefaultDataSubscriptionId(11); - when(mTelephonyManager.getDataState()).thenReturn(TelephonyManager.DATA_DISCONNECTED); when(mTelephonyManager.isDataEnabled()).thenReturn(false); assertThat(mController.getSummary(11)).isEqualTo( @@ -351,7 +384,6 @@ public class SubscriptionsPreferenceControllerTest { ShadowSubscriptionManager.setDefaultDataSubscriptionId(11); ShadowSubscriptionManager.setDefaultSmsSubscriptionId(22); ShadowSubscriptionManager.setDefaultVoiceSubscriptionId(11); - when(mTelephonyManager.getDataState()).thenReturn(TelephonyManager.DATA_DISCONNECTED); when(mTelephonyManager.isDataEnabled()).thenReturn(true); assertThat(mController.getSummary(11)).isEqualTo( From 0f75eb550e337c6c99b0158ce6997f17bd7ce1a1 Mon Sep 17 00:00:00 2001 From: Yi-Ling Chuang Date: Wed, 8 May 2019 11:34:40 +0800 Subject: [PATCH 14/22] Add null check before setting the visibility of swipe background Some contextual cards does not allow card dismissal, so they won't have swipe background declared in the layout file. Add null check to prevent from NPE. Fixes: 132209310 Test: robotests & launch Settings Change-Id: I31f897f445c4901d007c8187fe69aea416b915d1 --- .../slices/SliceContextualCardRenderer.java | 11 +++++---- .../SliceContextualCardRendererTest.java | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java index f9753484180..b83a712bc54 100644 --- a/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java +++ b/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRenderer.java @@ -112,8 +112,10 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life final View swipeBackground = holder.itemView.findViewById(R.id.dismissal_swipe_background); sliceLiveData.removeObservers(mLifecycleOwner); - // set the background to Gone in case the holder is reused. - swipeBackground.setVisibility(View.GONE); + // set the background to GONE in case the holder is reused. + if (swipeBackground != null) { + swipeBackground.setVisibility(View.GONE); + } sliceLiveData.observe(mLifecycleOwner, slice -> { if (slice == null) { Log.w(TAG, "Slice is null"); @@ -140,8 +142,9 @@ public class SliceContextualCardRenderer implements ContextualCardRenderer, Life default: mFullCardHelper.bindView(holder, card, slice); } - - swipeBackground.setVisibility(View.VISIBLE); + if (swipeBackground != null) { + swipeBackground.setVisibility(View.VISIBLE); + } }); switch (holder.getItemViewType()) { diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java index 70761cf52d5..fb04dac9dd2 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/SliceContextualCardRendererTest.java @@ -16,11 +16,13 @@ package com.android.settings.homepage.contextualcards.slices; +import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_DEFERRED_SETUP; import static com.android.settings.homepage.contextualcards.slices.SliceContextualCardRenderer.VIEW_TYPE_FULL_WIDTH; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.app.Activity; @@ -160,6 +162,15 @@ public class SliceContextualCardRendererTest { assertThat(swipeBg.getVisibility()).isEqualTo(View.GONE); } + @Test + public void bindView_deferredSetupCard_shouldNotCrash() { + final RecyclerView.ViewHolder viewHolder = getDeferredSetupViewHolder(); + final ContextualCard card = buildContextualCard(TEST_SLICE_URI); + mRenderer.mSliceLiveDataMap.put(TEST_SLICE_URI, mSliceLiveData); + + mRenderer.bindView(viewHolder, card); + } + @Test public void viewClick_keepCard_shouldShowSlice() { final RecyclerView.ViewHolder viewHolder = getSliceViewHolder(); @@ -246,6 +257,18 @@ public class SliceContextualCardRendererTest { return mRenderer.createViewHolder(view, VIEW_TYPE_FULL_WIDTH); } + private RecyclerView.ViewHolder getDeferredSetupViewHolder() { + final RecyclerView recyclerView = new RecyclerView(mActivity); + recyclerView.setLayoutManager(new LinearLayoutManager(mActivity)); + final View view = LayoutInflater.from(mActivity) + .inflate(VIEW_TYPE_DEFERRED_SETUP, recyclerView, false); + final RecyclerView.ViewHolder viewHolder = spy( + new SliceDeferredSetupCardRendererHelper.DeferredSetupCardViewHolder(view)); + doReturn(VIEW_TYPE_DEFERRED_SETUP).when(viewHolder).getItemViewType(); + + return viewHolder; + } + private ContextualCard buildContextualCard(Uri sliceUri) { return new ContextualCard.Builder() .setName("test_name") From 9bc32734893f74bc8122ebc9da2f3c2de5099c69 Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Mon, 6 May 2019 16:35:19 -0700 Subject: [PATCH 15/22] Update datausage for DataUsagePreferenceController Data usage number was wrong because we didn't set correct subId, this CL fixes this issue. Bug: 132113657 Test: RunSettingsRoboTests Change-Id: If7c9cf2f4709d9a8e5f9a154c02de9484800d6d5 --- .../android/settings/datausage/DataUsageUtils.java | 5 +++-- .../telephony/DataUsagePreferenceController.java | 13 ++----------- .../settings/datausage/DataUsageSummaryTest.java | 9 ++++++++- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/com/android/settings/datausage/DataUsageUtils.java b/src/com/android/settings/datausage/DataUsageUtils.java index 283c84f6ec7..68657a48f8e 100644 --- a/src/com/android/settings/datausage/DataUsageUtils.java +++ b/src/com/android/settings/datausage/DataUsageUtils.java @@ -178,9 +178,10 @@ public final class DataUsageUtils { * Returns the default network template based on the availability of mobile data, Wifi. Returns * ethernet template if both mobile data and Wifi are not available. */ - static NetworkTemplate getDefaultTemplate(Context context, int defaultSubId) { + public static NetworkTemplate getDefaultTemplate(Context context, int defaultSubId) { if (hasMobileData(context) && defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - TelephonyManager telephonyManager = TelephonyManager.from(context); + TelephonyManager telephonyManager = TelephonyManager.from(context) + .createForSubscriptionId(defaultSubId); NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( telephonyManager.getSubscriberId(defaultSubId)); return NetworkTemplate.normalize(mobileAll, diff --git a/src/com/android/settings/network/telephony/DataUsagePreferenceController.java b/src/com/android/settings/network/telephony/DataUsagePreferenceController.java index 3f55003801f..b8a31fe1852 100644 --- a/src/com/android/settings/network/telephony/DataUsagePreferenceController.java +++ b/src/com/android/settings/network/telephony/DataUsagePreferenceController.java @@ -21,9 +21,7 @@ import android.content.Intent; import android.net.NetworkTemplate; import android.provider.Settings; import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.text.format.Formatter; import androidx.preference.Preference; @@ -87,9 +85,10 @@ public class DataUsagePreferenceController extends TelephonyBasePreferenceContro mSubId = subId; if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - mTemplate = getNetworkTemplate(mContext, subId); + mTemplate = DataUsageUtils.getDefaultTemplate(mContext, mSubId); final DataUsageController controller = new DataUsageController(mContext); + controller.setSubscriptionId(mSubId); mDataUsageInfo = controller.getDataUsageInfo(mTemplate); mIntent = new Intent(Settings.ACTION_MOBILE_DATA_USAGE); @@ -97,12 +96,4 @@ public class DataUsagePreferenceController extends TelephonyBasePreferenceContro mIntent.putExtra(Settings.EXTRA_SUB_ID, mSubId); } } - - private NetworkTemplate getNetworkTemplate(Context context, int subId) { - final TelephonyManager tm = TelephonyManager.from(context).createForSubscriptionId(subId); - NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll(tm.getSubscriberId()); - - return NetworkTemplate.normalize(mobileAll, tm.getMergedSubscriberIds()); - } - } diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java index 79c3ad10cbf..b9bfcc1e66a 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java @@ -27,11 +27,13 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.NetworkPolicyManager; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import androidx.fragment.app.FragmentActivity; @@ -44,6 +46,7 @@ import com.android.settings.testutils.shadow.ShadowUtils; 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.Robolectric; @@ -68,6 +71,8 @@ public class DataUsageSummaryTest { private NetworkPolicyManager mNetworkPolicyManager; @Mock private NetworkStatsManager mNetworkStatsManager; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private TelephonyManager mTelephonyManager; private Context mContext; private FragmentActivity mActivity; private SummaryLoader.SummaryProvider mSummaryProvider; @@ -84,7 +89,9 @@ public class DataUsageSummaryTest { ShadowUserManager.getShadow().setIsAdminUser(true); shadowContext.setSystemService(Context.NETWORK_POLICY_SERVICE, mNetworkPolicyManager); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); mActivity = spy(Robolectric.buildActivity(FragmentActivity.class).get()); doReturn(mNetworkStatsManager).when(mActivity).getSystemService(NetworkStatsManager.class); From 83a63abd2d29ed9c5e692a56e09463806f721b7f Mon Sep 17 00:00:00 2001 From: Alex Salo Date: Wed, 1 May 2019 10:10:21 -0700 Subject: [PATCH 16/22] Re-enable the test Update the test to handle new API and simplify the logic in the controller. Bug: 130897305 Test: make RunSettingsRoboTests -j64 Change-Id: I0c46ff22d4a3bf913add753f85a24af9aeee0a33 --- .../AdaptiveSleepPreferenceController.java | 24 +++++-------------- ...AdaptiveSleepPreferenceControllerTest.java | 24 ++++++++++++------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java index 6aa71873c4d..fab3efad39e 100644 --- a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java @@ -20,9 +20,6 @@ import android.content.Context; import android.content.pm.PackageManager; import android.provider.Settings; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; @@ -60,10 +57,12 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle @Override @AvailabilityStatus public int getAvailabilityStatus() { - return mContext.getResources().getBoolean( - com.android.internal.R.bool.config_adaptive_sleep_available) - ? AVAILABLE - : UNSUPPORTED_ON_DEVICE; + final boolean supportedOnDevice = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_adaptive_sleep_available); + if (!supportedOnDevice) { + return UNSUPPORTED_ON_DEVICE; + } + return hasSufficientPermissions ? AVAILABLE : DISABLED_DEPENDENT_SETTING; } @Override @@ -77,15 +76,4 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle ? R.string.adaptive_sleep_summary_on : R.string.adaptive_sleep_summary_off); } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - final Preference preference = screen.findPreference(SYSTEM_KEY); - - if (preference != null) { - preference.setEnabled(hasSufficientPermissions); - } - - } } diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java index 89388730742..69d1cbc8048 100644 --- a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java @@ -21,6 +21,8 @@ import static android.provider.Settings.System.ADAPTIVE_SLEEP; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.ContentResolver; @@ -28,11 +30,12 @@ import android.content.Context; import android.content.pm.PackageManager; import android.provider.Settings; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settings.R; -import com.android.settingslib.RestrictedPreference; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -41,7 +44,6 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) -@Ignore("b/130897305") public class AdaptiveSleepPreferenceControllerTest { private static final String PREFERENCE_KEY = "adaptive_sleep"; @@ -52,18 +54,25 @@ public class AdaptiveSleepPreferenceControllerTest { @Mock private PackageManager mPackageManager; + @Mock + private PreferenceScreen mScreen; + @Mock + private Preference mPreference; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); mContentResolver = mContext.getContentResolver(); - mController = new AdaptiveSleepPreferenceController(mContext, PREFERENCE_KEY); - + doReturn(mPackageManager).when(mContext).getPackageManager(); + when(mPackageManager.getAttentionServicePackageName()).thenReturn("some.package"); when(mPackageManager.checkPermission(any(), any())).thenReturn( PackageManager.PERMISSION_GRANTED); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + + mController = new AdaptiveSleepPreferenceController(mContext, PREFERENCE_KEY); } @Test @@ -145,8 +154,7 @@ public class AdaptiveSleepPreferenceControllerTest { PackageManager.PERMISSION_DENIED); mController.setChecked(true); - final RestrictedPreference mPreference = new RestrictedPreference(mContext); - mController.updateState(mPreference); + mController.displayPreference(mScreen); assertThat(mPreference.isEnabled()).isFalse(); } } From b47b99ed38c0e3705c70f350f10d4828824ff533 Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Wed, 8 May 2019 11:12:55 -0700 Subject: [PATCH 17/22] Add null check when restart batteryinfo loader Even though we unregister contentObserver in onPause and register in onResume, callback still be called while fragment is detached. Anyhow add a null check in settings to stop crash Fixes: 131905853 Test: RunSettingsRoboTests Change-Id: I8c0c2c04c3b8d942e0c97cf71a7d3e735a24b467 --- .../settings/fuelgauge/PowerUsageSummary.java | 3 +++ .../settings/fuelgauge/PowerUsageSummaryTest.java | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index 85a08793b42..880255b212c 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -378,6 +378,9 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList @VisibleForTesting void restartBatteryInfoLoader() { + if (getContext() == null) { + return; + } getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY, mBatteryInfoLoaderCallbacks); if (mPowerFeatureProvider.isEstimateDebugEnabled()) { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java index 2dd0d9be71e..4d77bddc45f 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java @@ -15,6 +15,7 @@ */ package com.android.settings.fuelgauge; +import static com.android.settings.fuelgauge.PowerUsageSummary.BATTERY_INFO_LOADER; import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_ADVANCED_BATTERY; import static com.google.common.truth.Truth.assertThat; @@ -373,6 +374,17 @@ public class PowerUsageSummaryTest { mFragment.mSettingsObserver); } + @Test + public void restartBatteryInfoLoader_contextNull_doNothing() { + when(mFragment.getContext()).thenReturn(null); + when(mFragment.getLoaderManager()).thenReturn(mLoaderManager); + + mFragment.restartBatteryInfoLoader(); + + verify(mLoaderManager, never()).restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY, + mFragment.mBatteryInfoLoaderCallbacks); + } + public static class TestFragment extends PowerUsageSummary { private Context mContext; From 3e14383a283e100cdc14818b2084026f2df22dbe Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 7 May 2019 15:14:09 -0700 Subject: [PATCH 18/22] Display settings homepage content fully edge-to-edge This is needed to support fully gesture navigation. Bug: 132182711 Test: visual Change-Id: Ifaf15ecec73b974356355a74e73754f95b84ad3e --- res/layout/settings_homepage_container.xml | 4 ++- res/values-night/colors.xml | 26 +++++++++---------- res/values/colors.xml | 7 +++-- res/values/themes.xml | 3 +-- .../homepage/SettingsHomepageActivity.java | 23 +++++----------- .../SettingsHomepageActivityTest.java | 5 +--- 6 files changed, 26 insertions(+), 42 deletions(-) diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml index 856bd8085b7..7f1954b6465 100644 --- a/res/layout/settings_homepage_container.xml +++ b/res/layout/settings_homepage_container.xml @@ -18,6 +18,8 @@ @@ -57,7 +59,7 @@ diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml index 4c432576120..f7612173840 100644 --- a/res/values-night/colors.xml +++ b/res/values-night/colors.xml @@ -15,19 +15,17 @@ --> - #82000000 - @android:color/black - #783BE5 - #3F5FBD - - #cc000000 - @*android:color/material_grey_900 - @*android:color/material_grey_900 - @*android:color/material_grey_800 - - @*android:color/material_grey_800 - @*android:color/material_grey_800 - #AECBFA - #5F6368 + #82000000 + @android:color/black + #783BE5 + #3F5FBD + @*android:color/material_grey_900 + @*android:color/material_grey_900 + @*android:color/material_grey_800 + + @*android:color/material_grey_800 + @*android:color/material_grey_800 + #AECBFA + #5F6368 diff --git a/res/values/colors.xml b/res/values/colors.xml index 42fa3f97fe7..4a4c896a770 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -23,7 +23,9 @@ #20ffffff @android:color/holo_blue_light - @color/lock_pattern_view_regular_color + + @color/lock_pattern_view_regular_color + #ff84ffff @color/sud_color_accent_light #fff44336 @@ -133,9 +135,6 @@ @*android:color/accent_device_default_light - - #ccFFFFFF - #ffdadce0 #ff1a73e8 diff --git a/res/values/themes.xml b/res/values/themes.xml index 951bb048960..4edd943a224 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -197,9 +197,8 @@ @*android:color/primary_dark_device_default_settings_light true @*android:color/ripple_material_light - @android:color/white + @android:color/transparent @android:color/white - true diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index 6d16d7f56cb..e7676649f3f 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -42,8 +42,11 @@ public class SettingsHomepageActivity extends SettingsBaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - updateWindowProperties(); setContentView(R.layout.settings_homepage_container); + final View root = findViewById(R.id.settings_homepage_container); + root.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); + setHomepageContainerPaddingTop(); final Toolbar toolbar = findViewById(R.id.search_action_bar); @@ -76,29 +79,15 @@ public class SettingsHomepageActivity extends SettingsBaseActivity { fragmentTransaction.commit(); } - private void updateWindowProperties() { - final View decorView = getWindow().getDecorView(); - decorView.setSystemUiVisibility( - decorView.getSystemUiVisibility() | - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - ); - - getWindow().setStatusBarColor(getColor(R.color.homepage_status_bar_color)); - } - @VisibleForTesting void setHomepageContainerPaddingTop() { final View view = this.findViewById(R.id.homepage_container); - final int statusBarHeight = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height); final int searchBarMargin = getResources().getDimensionPixelSize(R.dimen.search_bar_margin); - // The top padding is the height of status bar + height of action bar(48dp) + top/bottom - // margins(16dp) - final int paddingTop = statusBarHeight + searchBarHeight + searchBarMargin * 2; + // The top padding is the height of action bar(48dp) + top/bottom margins(16dp) + final int paddingTop = searchBarHeight + searchBarMargin * 2; view.setPadding(0 /* left */, paddingTop, 0 /* right */, 0 /* bottom */); } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 50a798f744b..dcb32c4c475 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -35,8 +35,6 @@ public class SettingsHomepageActivityTest { public void setHomepageContainerPaddingTop_shouldBeSetPaddingTop() { final SettingsHomepageActivity activity = Robolectric.buildActivity( SettingsHomepageActivity.class).create().get(); - final int statusBarHeight = activity.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); final int searchBarHeight = activity.getResources().getDimensionPixelSize( R.dimen.search_bar_height); final int searchBarMargin = activity.getResources().getDimensionPixelSize( @@ -46,8 +44,7 @@ public class SettingsHomepageActivityTest { activity.setHomepageContainerPaddingTop(); final int actualPaddingTop = view.getPaddingTop(); - assertThat(actualPaddingTop).isEqualTo( - statusBarHeight + searchBarHeight + searchBarMargin * 2); + assertThat(actualPaddingTop).isEqualTo(searchBarHeight + searchBarMargin * 2); } @Test From 4765faa9cfb973c481240ab9c54db9a600f59e71 Mon Sep 17 00:00:00 2001 From: Beth Thibodeau Date: Wed, 8 May 2019 15:01:32 -0400 Subject: [PATCH 19/22] Increase char limit as requested by i18n team Fixes: 132257773 Test: mp settingsg Change-Id: I4c5c21899bb9fa61f8f8b32cd56dc57288e282bd --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index af94db3a358..7efbd8d346a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2895,7 +2895,7 @@ Choose wallpaper from Customize your Pixel - + Try different styles, wallpapers, clocks, and more Screen saver From 0458262fb346832582b0413b5a593ae0381288e0 Mon Sep 17 00:00:00 2001 From: joshmccloskey Date: Mon, 6 May 2019 21:42:14 -0700 Subject: [PATCH 20/22] Added Face Enroll Education Screen Test: Builds Bug: 131774352 Fixes: 131857742 Change-Id: Ib384b9efaf053b405ce3f55e449dd6abb9e75296 --- AndroidManifest.xml | 4 + res/layout/face_enroll_education.xml | 103 +++++++++++ res/raw/face_education.mp4 | 0 res/values/strings.xml | 6 + .../biometrics/face/FaceEnrollEducation.java | 175 ++++++++++++++++++ .../face/FaceEnrollIntroduction.java | 12 +- 6 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 res/layout/face_enroll_education.xml create mode 100644 res/raw/face_education.mp4 create mode 100644 src/com/android/settings/biometrics/face/FaceEnrollEducation.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9dd4732072f..12562969335 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1570,6 +1570,10 @@ android:exported="false" android:screenOrientation="portrait"/> + + diff --git a/res/layout/face_enroll_education.xml b/res/layout/face_enroll_education.xml new file mode 100644 index 00000000000..c41c724cf3c --- /dev/null +++ b/res/layout/face_enroll_education.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + +