From a74060c1b7002edcc6d2747addc1dfb61aa98cbb Mon Sep 17 00:00:00 2001 From: Sunny Shao Date: Wed, 31 Jul 2019 13:19:23 +0800 Subject: [PATCH] Add Tapjacking Protection for SettingsHomepageActivity Add/remove the SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS flag into/from SettingsHomepageActivity and SettingsPanelActivity with lifecycle. Bug: 138442483 Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.homepage make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.panel manual test Change-Id: I72f9a947f57f74a8c09127d6c39173594c248ddc Merged-In: I72f9a947f57f74a8c09127d6c39173594c248ddc --- .../homepage/SettingsHomepageActivity.java | 5 +- .../settings/panel/SettingsPanelActivity.java | 2 + .../SettingsHomepageActivityTest.java | 73 +++++++++++++++++++ .../panel/SettingsPanelActivityTest.java | 56 +++++++++++++- 4 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index fa231012f96..5e6c54bb7c2 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -33,6 +33,7 @@ import androidx.fragment.app.FragmentTransaction; import com.android.settings.R; import com.android.settings.accounts.AvatarViewMixin; +import com.android.settings.core.HideNonSystemOverlayMixin; import com.android.settings.homepage.contextualcards.ContextualCardsFragment; import com.android.settings.overlay.FeatureFactory; @@ -54,8 +55,8 @@ public class SettingsHomepageActivity extends FragmentActivity { .initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE); final ImageView avatarView = findViewById(R.id.account_avatar); - final AvatarViewMixin avatarViewMixin = new AvatarViewMixin(this, avatarView); - getLifecycle().addObserver(avatarViewMixin); + getLifecycle().addObserver(new AvatarViewMixin(this, avatarView)); + getLifecycle().addObserver(new HideNonSystemOverlayMixin(this)); if (!getSystemService(ActivityManager.class).isLowRamDevice()) { // Only allow contextual feature on high ram devices. diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java index 749a46e0cde..86931866afc 100644 --- a/src/com/android/settings/panel/SettingsPanelActivity.java +++ b/src/com/android/settings/panel/SettingsPanelActivity.java @@ -32,6 +32,7 @@ import androidx.fragment.app.FragmentManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; +import com.android.settings.core.HideNonSystemOverlayMixin; /** * Dialog Activity to host Settings Slices. @@ -62,6 +63,7 @@ public class SettingsPanelActivity extends FragmentActivity { protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); createOrUpdatePanel(true /* shouldForceCreation */); + getLifecycle().addObserver(new HideNonSystemOverlayMixin(this)); } @Override diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index dcb32c4c475..db12580e169 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -16,20 +16,42 @@ package com.android.settings.homepage; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.Build; import android.view.View; +import android.view.Window; +import android.view.WindowManager; import android.widget.FrameLayout; import com.android.settings.R; +import com.android.settings.core.HideNonSystemOverlayMixin; +import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import org.robolectric.android.controller.ActivityController; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; @RunWith(RobolectricTestRunner.class) public class SettingsHomepageActivityTest { + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } @Test public void setHomepageContainerPaddingTop_shouldBeSetPaddingTop() { @@ -55,4 +77,55 @@ public class SettingsHomepageActivityTest { assertThat(frameLayout.getLayoutTransition()).isNotNull(); } + + @Test + @Config(shadows = { + BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, + BatteryFixSliceTest.ShadowBatteryTipLoader.class + }) + public void onStart_isNotDebuggable_shouldHideSystemOverlay() { + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false); + + final ActivityController activityController = + Robolectric.buildActivity(SettingsHomepageActivity.class).create(); + final SettingsHomepageActivity activity = spy(activityController.get()); + final Window window = mock(Window.class); + when(activity.getWindow()).thenReturn(window); + activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity)); + + activityController.start(); + + verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + } + + @Test + @Config(shadows = { + BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, + BatteryFixSliceTest.ShadowBatteryTipLoader.class, + }) + public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() { + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false); + + final ActivityController activityController = + Robolectric.buildActivity(SettingsHomepageActivity.class).create(); + final SettingsHomepageActivity activity = spy(activityController.get()); + final Window window = mock(Window.class); + when(activity.getWindow()).thenReturn(window); + activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity)); + + activityController.start(); + + verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); + when(window.getAttributes()).thenReturn(layoutParams); + + activityController.stop(); + final ArgumentCaptor paramCaptor = ArgumentCaptor.forClass( + WindowManager.LayoutParams.class); + + verify(window).setAttributes(paramCaptor.capture()); + assertThat(paramCaptor.getValue().privateFlags + & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0); + } } diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java index 8ad21569401..a4b7aa551bb 100644 --- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java +++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java @@ -16,6 +16,8 @@ package com.android.settings.panel; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + import static com.android.settings.panel.SettingsPanelActivity.KEY_MEDIA_PACKAGE_NAME; import static com.android.settings.panel.SettingsPanelActivity.KEY_PANEL_TYPE_ARGUMENT; @@ -28,17 +30,23 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.app.settings.SettingsEnums; import android.content.Intent; -import android.view.MotionEvent; +import android.os.Build; +import android.view.Window; +import android.view.WindowManager; +import com.android.settings.core.HideNonSystemOverlayMixin; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import org.robolectric.android.controller.ActivityController; +import org.robolectric.util.ReflectionHelpers; @RunWith(RobolectricTestRunner.class) public class SettingsPanelActivityTest { @@ -50,6 +58,7 @@ public class SettingsPanelActivityTest { @Before public void setUp() { + MockitoAnnotations.initMocks(this); mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mSettingsPanelActivity = spy( Robolectric.buildActivity(FakeSettingsPanelActivity.class).create().get()); @@ -87,4 +96,47 @@ public class SettingsPanelActivityTest { assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT)) .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT"); } + + @Test + public void onStart_isNotDebuggable_shouldHideSystemOverlay() { + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false); + + final ActivityController activityController = + Robolectric.buildActivity(SettingsPanelActivity.class).create(); + final SettingsPanelActivity activity = spy(activityController.get()); + final Window window = mock(Window.class); + when(activity.getWindow()).thenReturn(window); + activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity)); + + activityController.start(); + + verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + } + + @Test + public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() { + ReflectionHelpers.setStaticField(Build.class, "IS_DEBUGGABLE", false); + + final ActivityController activityController = + Robolectric.buildActivity(SettingsPanelActivity.class).create(); + final SettingsPanelActivity activity = spy(activityController.get()); + final Window window = mock(Window.class); + when(activity.getWindow()).thenReturn(window); + activity.getLifecycle().addObserver(new HideNonSystemOverlayMixin(activity)); + + activityController.start(); + + verify(window).addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); + when(window.getAttributes()).thenReturn(layoutParams); + + activityController.stop(); + final ArgumentCaptor paramCaptor = ArgumentCaptor.forClass( + WindowManager.LayoutParams.class); + + verify(window).setAttributes(paramCaptor.capture()); + assertThat(paramCaptor.getValue().privateFlags + & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(0); + } }