Disable system alert window permissions on low ram devices

Bug: 63697002
Bug: 117832554
Test: adb am start-activity -a
android.settings.action.MANAGE_OVERLAY_PERMISSION
Change-Id: I44c64001cd07fd4934cdc55f455384cebd5c9cfb
This commit is contained in:
Ng Zhi An
2019-02-01 12:39:31 -08:00
parent d3824aa426
commit b97bdc38da
9 changed files with 212 additions and 1 deletions

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/empty_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/disabled_feature"
android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
android:id="@+id/empty_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/disabled_feature_reason_slow_down_phone"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/pinned_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
settings:layout_scrollFlags="scroll|enterAlways"/>
</com.google.android.material.appbar.AppBarLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -10183,6 +10183,10 @@
<!-- Note displayed when certain features are not available on low ram devices. [CHAR LIMIT=NONE] -->
<string name="disabled_low_ram_device">This feature is not available on this device</string>
<!-- Note displayed when certain features are not available. [CHAR LIMIT=NONE] -->
<string name="disabled_feature">This feature is not available</string>
<!-- Note displayed to explain that a feature is not available because it will slow down the phone. [CHAR LIMIT=NONE] -->
<string name="disabled_feature_reason_slow_down_phone">It will slow down this phone</string>
<!-- UI debug setting: preference title - enforce full raw GNSS satellite measurements [CHAR LIMIT=60] -->
<string name="enable_gnss_raw_meas_full_tracking">Force full GNSS measurements</string>

View File

@@ -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">
<extra
android:name="classname"
android:value="com.android.settings.Settings$OverlaySettingsActivity" />

View File

@@ -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));
}
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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 ;
}
}

View File

@@ -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();
}
}

View File

@@ -38,6 +38,7 @@ public class ShadowUtils {
private static boolean sIsDemoUser;
private static ComponentName sDeviceOwnerComponentName;
private static Map<String, String> 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;
}
}