diff --git a/res/layout/manage_applications_apps_unsupported.xml b/res/layout/manage_applications_apps_unsupported.xml new file mode 100644 index 00000000000..d7c6726e377 --- /dev/null +++ b/res/layout/manage_applications_apps_unsupported.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 90b72e16395..1058c2825ec 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10183,6 +10183,10 @@ This feature is not available on this device + + This feature is not available + + It will slow down this phone Force full GNSS measurements diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml index 4417d0ffb43..05f4a81ef2a 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -42,7 +42,8 @@ android:key="system_alert_window" android:title="@string/system_alert_window_settings" android:fragment="com.android.settings.applications.manageapplications.ManageApplications" - settings:keywords="@string/keywords_system_alert_window"> + settings:keywords="@string/keywords_system_alert_window" + settings:controller="com.android.settings.applications.specialaccess.SystemAlertWindowPreferenceController"> diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 804c7830d20..69b8c569a60 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -55,6 +55,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.wifi.WifiManager; import android.os.BatteryManager; +import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.INetworkManagementService; @@ -1007,4 +1008,14 @@ public final class Utils extends com.android.settingslib.Utils { return context.getResources(); } } + + /** + * Returns true if SYSTEM_ALERT_WINDOW permission is available. + * Starting from Q, SYSTEM_ALERT_WINDOW is disabled on low ram phones. + */ + public static boolean isSystemAlertWindowEnabled(Context context) { + // SYSTEM_ALERT_WINDOW is disabled on on low ram devices starting from Q + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + return !(am.isLowRamDevice() && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)); + } } diff --git a/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java b/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java index 9cf57bd1f65..d0b26a53328 100644 --- a/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java +++ b/src/com/android/settings/applications/appinfo/DrawOverlayDetails.java @@ -17,6 +17,7 @@ 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; @@ -25,6 +26,9 @@ 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; @@ -36,6 +40,7 @@ import androidx.preference.Preference.OnPreferenceClickListener; import androidx.preference.SwitchPreference; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.applications.AppInfoWithHeader; import com.android.settings.applications.AppStateAppOpsBridge.PermissionState; import com.android.settings.applications.AppStateOverlayBridge; @@ -70,6 +75,11 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc mOverlayBridge = new AppStateOverlayBridge(context, mState, null); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + if (!Utils.isSystemAlertWindowEnabled(context)) { + mPackageInfo = null; + return; + } + // find preferences addPreferencesFromResource(R.xml.draw_overlay_permissions_details); mSwitchPref = (SwitchPreference) findPreference(KEY_APP_OPS_SETTINGS_SWITCH); @@ -81,6 +91,18 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc .setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); } + // Override here so we don't have an empty screen + @Override + public View onCreateView (LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + // if we don't have a package info, show a page saying this is unsupported + if (mPackageInfo == null) { + return inflater.inflate(R.layout.manage_applications_apps_unsupported, null); + } + return super.onCreateView(inflater, container, savedInstanceState); + } + @Override public void onResume() { super.onResume(); @@ -142,6 +164,8 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc @Override protected boolean refreshUi() { + if (mPackageInfo == null) return true; + mOverlayState = mOverlayBridge.getOverlayInfo(mPackageName, mPackageInfo.applicationInfo.uid); diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index a9de206a0da..9586be01be1 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -33,6 +33,7 @@ import static com.android.settings.applications.manageapplications.AppFilterRegi import android.annotation.Nullable; import android.annotation.StringRes; import android.app.Activity; +import android.app.ActivityManager; import android.app.settings.SettingsEnums; import android.app.usage.IUsageStatsManager; import android.content.Context; @@ -49,18 +50,22 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.IconDrawableFactory; import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.Filter; import android.widget.FrameLayout; import android.widget.SearchView; import android.widget.Spinner; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -79,6 +84,7 @@ import com.android.settings.Settings.StorageUseActivity; import com.android.settings.Settings.UsageAccessSettingsActivity; import com.android.settings.Settings.WriteSettingsActivity; import com.android.settings.SettingsActivity; +import com.android.settings.Utils; import com.android.settings.applications.AppInfoBase; import com.android.settings.applications.AppStateAppOpsBridge.PermissionState; import com.android.settings.applications.AppStateBaseBridge; @@ -327,12 +333,19 @@ public class ManageApplications extends InstrumentedFragment @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (mListType == LIST_TYPE_OVERLAY && !Utils.isSystemAlertWindowEnabled(getContext())) { + mRootView = inflater.inflate(R.layout.manage_applications_apps_unsupported, null); + setHasOptionsMenu(false); + return mRootView; + } + mRootView = inflater.inflate(R.layout.manage_applications_apps, null); mLoadingContainer = mRootView.findViewById(R.id.loading_container); mListContainer = mRootView.findViewById(R.id.list_container); if (mListContainer != null) { // Create adapter and list view here mEmptyView = mListContainer.findViewById(android.R.id.empty); + mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter, savedInstanceState); if (savedInstanceState != null) { diff --git a/src/com/android/settings/applications/specialaccess/SystemAlertWindowPreferenceController.java b/src/com/android/settings/applications/specialaccess/SystemAlertWindowPreferenceController.java new file mode 100644 index 00000000000..5d9e8b612b8 --- /dev/null +++ b/src/com/android/settings/applications/specialaccess/SystemAlertWindowPreferenceController.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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.applications.specialaccess; + +import static com.android.settings.Utils.isSystemAlertWindowEnabled; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; + +import com.android.settings.core.BasePreferenceController; + +public class SystemAlertWindowPreferenceController extends BasePreferenceController { + public SystemAlertWindowPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return isSystemAlertWindowEnabled(mContext) + ? AVAILABLE_UNSEARCHABLE : UNSUPPORTED_ON_DEVICE ; + } +} diff --git a/tests/robotests/src/com/android/settings/applications/specialaccess/SystemAlertWindowPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/specialaccess/SystemAlertWindowPreferenceControllerTest.java new file mode 100644 index 00000000000..bc90f2bead0 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/specialaccess/SystemAlertWindowPreferenceControllerTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 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.applications.specialaccess; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import com.android.settings.testutils.shadow.ShadowUtils; + +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; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowUtils.class}) +public class SystemAlertWindowPreferenceControllerTest { + + private Context mContext; + private SystemAlertWindowPreferenceController mController; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mController = new SystemAlertWindowPreferenceController(mContext, "key"); + } + + @Test + public void systemAlertWindow_byDefault_shouldBeShown() { + ShadowUtils.setIsSystemAlertWindowEnabled(true); + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void systemAlertWindow_lowMemory_shouldNotBeShown() { + ShadowUtils.setIsSystemAlertWindowEnabled(false); + assertThat(mController.isAvailable()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java index 4797e8c68fb..f8644d9e712 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java @@ -38,6 +38,7 @@ public class ShadowUtils { private static boolean sIsDemoUser; private static ComponentName sDeviceOwnerComponentName; private static Map sAppNameMap; + private static boolean sIsSystemAlertWindowEnabled; @Implementation protected static int enforceSameOwner(Context context, int userId) { @@ -113,4 +114,13 @@ public class ShadowUtils { } sAppNameMap.put(packageName, appLabel); } + + @Implementation + protected static boolean isSystemAlertWindowEnabled(Context context) { + return sIsSystemAlertWindowEnabled; + } + + public static void setIsSystemAlertWindowEnabled(boolean enabled) { + sIsSystemAlertWindowEnabled = enabled; + } }