diff --git a/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java b/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java index d0b26a53328..0f90c69c9ae 100644 --- a/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java +++ b/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java @@ -15,22 +15,13 @@ */ package com.android.settings.applications.appinfo; -import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - -import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.settings.SettingsEnums; import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.os.Bundle; -import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; @@ -55,16 +46,11 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc private static final String KEY_APP_OPS_SETTINGS_SWITCH = "app_ops_settings_switch"; private static final String LOG_TAG = "DrawOverlayDetails"; - private static final int[] APP_OPS_OP_CODE = { - AppOpsManager.OP_SYSTEM_ALERT_WINDOW - }; - // Use a bridge to get the overlay details but don't initialize it to connect with all state. // TODO: Break out this functionality into its own class. private AppStateOverlayBridge mOverlayBridge; private AppOpsManager mAppOpsManager; private SwitchPreference mSwitchPref; - private Intent mSettingsIntent; private OverlayState mOverlayState; @Override @@ -82,18 +68,15 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc // find preferences addPreferencesFromResource(R.xml.draw_overlay_permissions_details); - mSwitchPref = (SwitchPreference) findPreference(KEY_APP_OPS_SETTINGS_SWITCH); + mSwitchPref = findPreference(KEY_APP_OPS_SETTINGS_SWITCH); // install event listeners mSwitchPref.setOnPreferenceChangeListener(this); - - mSettingsIntent = new Intent(Intent.ACTION_MAIN) - .setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); } // Override here so we don't have an empty screen @Override - public View onCreateView (LayoutInflater inflater, + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // if we don't have a package info, show a page saying this is unsupported @@ -103,21 +86,6 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc return super.onCreateView(inflater, container, savedInstanceState); } - @Override - public void onResume() { - super.onResume(); - getActivity().getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); - } - - @Override - public void onPause() { - super.onPause(); - Window window = getActivity().getWindow(); - WindowManager.LayoutParams attrs = window.getAttributes(); - attrs.privateFlags &= ~SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - window.setAttributes(attrs); - } - @Override public void onDestroy() { super.onDestroy(); @@ -164,7 +132,9 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc @Override protected boolean refreshUi() { - if (mPackageInfo == null) return true; + if (mPackageInfo == null) { + return true; + } mOverlayState = mOverlayBridge.getOverlayInfo(mPackageName, mPackageInfo.applicationInfo.uid); @@ -174,9 +144,6 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc // you cannot ask a user to grant you a permission you did not have! mSwitchPref.setEnabled(mOverlayState.permissionDeclared && mOverlayState.controlEnabled); - ResolveInfo resolveInfo = mPm.resolveActivityAsUser(mSettingsIntent, - PackageManager.GET_META_DATA, mUserId); - return true; } diff --git a/src/com/android/settings/core/HideNonSystemOverlayMixin.java b/src/com/android/settings/core/HideNonSystemOverlayMixin.java new file mode 100644 index 00000000000..59cef3bea17 --- /dev/null +++ b/src/com/android/settings/core/HideNonSystemOverlayMixin.java @@ -0,0 +1,64 @@ +/* + * 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; + +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + +import static androidx.lifecycle.Lifecycle.Event.ON_START; +import static androidx.lifecycle.Lifecycle.Event.ON_STOP; + +import android.app.Activity; +import android.view.Window; +import android.view.WindowManager; + +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; + + +/** + * A mixin that adds window flag to prevent non-system overlays showing on top of Settings + * activities. + */ +public class HideNonSystemOverlayMixin implements LifecycleObserver { + + private final Activity mActivity; + + public HideNonSystemOverlayMixin(Activity activity) { + mActivity = activity; + } + + @OnLifecycleEvent(ON_START) + public void onStart() { + if (mActivity == null) { + return; + } + mActivity.getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + android.util.EventLog.writeEvent(0x534e4554, "120484087", -1, ""); + } + + + @OnLifecycleEvent(ON_STOP) + public void onStop() { + if (mActivity == null) { + return; + } + final Window window = mActivity.getWindow(); + final WindowManager.LayoutParams attrs = window.getAttributes(); + attrs.privateFlags &= ~SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + window.setAttributes(attrs); + } +} diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java index 294e7542d90..cd1365404c8 100644 --- a/src/com/android/settings/core/SettingsBaseActivity.java +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -32,7 +32,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; -import android.view.WindowManager.LayoutParams; import android.widget.Toolbar; import androidx.fragment.app.FragmentActivity; @@ -59,8 +58,8 @@ public class SettingsBaseActivity extends FragmentActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final long startTime = System.currentTimeMillis(); + getLifecycle().addObserver(new HideNonSystemOverlayMixin(this)); final TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme); if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) { diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java index 5fd26a64c95..3ccca000406 100644 --- a/src/com/android/settings/notification/AppNotificationSettings.java +++ b/src/com/android/settings/notification/AppNotificationSettings.java @@ -16,8 +16,6 @@ package com.android.settings.notification; -import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.settings.SettingsEnums; @@ -26,8 +24,6 @@ import android.os.AsyncTask; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; -import android.view.Window; -import android.view.WindowManager; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; @@ -88,8 +84,6 @@ public class AppNotificationSettings extends NotificationSettingsBase { public void onResume() { super.onResume(); - getActivity().getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); - if (mUid < 0 || TextUtils.isEmpty(mPkg) || mPkgInfo == null) { Log.w(TAG, "Missing package or uid or packageinfo"); finish(); @@ -123,15 +117,6 @@ public class AppNotificationSettings extends NotificationSettingsBase { updatePreferenceStates(); } - @Override - public void onPause() { - super.onPause(); - final Window window = getActivity().getWindow(); - final WindowManager.LayoutParams attrs = window.getAttributes(); - attrs.privateFlags &= ~SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - window.setAttributes(attrs); - } - @Override protected String getLogTag() { return TAG; diff --git a/tests/robotests/src/com/android/settings/core/HideNonSystemOverlayMixinTest.java b/tests/robotests/src/com/android/settings/core/HideNonSystemOverlayMixinTest.java new file mode 100644 index 00000000000..579cba09c14 --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/HideNonSystemOverlayMixinTest.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.core; + +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Bundle; +import android.view.WindowManager; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import com.android.settings.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.android.controller.ActivityController; + +@RunWith(RobolectricTestRunner.class) +public class HideNonSystemOverlayMixinTest { + + private ActivityController mActivityController; + + @Before + public void setUp() { + RuntimeEnvironment.application.setTheme(R.style.Theme_AppCompat); + mActivityController = Robolectric.buildActivity(TestActivity.class); + } + + @Test + public void startActivity_shouldHideNonSystemOverlay() { + mActivityController.setup(); + TestActivity activity = mActivityController.get(); + + // Activity start: HIDE_NON_SYSTEM_OVERLAY should be set. + final WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); + assertThat(attrs.privateFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) + .isNotEqualTo(0); + } + + @Test + public void stopActivity_shouldUnhideNonSystemOverlay() { + mActivityController.setup().stop(); + TestActivity activity = mActivityController.get(); + + final WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); + assertThat(attrs.privateFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) + .isEqualTo(0); + } + + public static class TestActivity extends AppCompatActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getLifecycle().addObserver(new HideNonSystemOverlayMixin(this)); + } + } +}