blob: 5f95779cfbbb220fd9211a315b9e5408419ac83b [file] [log] [blame]
/*
* Copyright (C) 2022 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.turnscreenon;
import android.Manifest;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.IconDrawableFactory;
import android.util.Pair;
import android.view.View;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.EmptyTextSettings;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.AppPreference;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* Settings page for providing special app access to turn the screen of the device on.
*/
@SearchIndexable
public class TurnScreenOnSettings extends EmptyTextSettings {
@VisibleForTesting
static final List<String> IGNORE_PACKAGE_LIST = new ArrayList<>();
static {
IGNORE_PACKAGE_LIST.add(Utils.SYSTEMUI_PACKAGE_NAME);
}
/**
* Comparator by name, then user id.
* {@see PackageItemInfo#DisplayNameComparator}
*/
static class AppComparator implements Comparator<Pair<ApplicationInfo, Integer>> {
private final Collator mCollator = Collator.getInstance();
private final PackageManager mPm;
AppComparator(PackageManager pm) {
mPm = pm;
}
public final int compare(Pair<ApplicationInfo, Integer> a,
Pair<ApplicationInfo, Integer> b) {
CharSequence sa = a.first.loadLabel(mPm);
if (sa == null) sa = a.first.name;
CharSequence sb = b.first.loadLabel(mPm);
if (sb == null) sb = b.first.name;
int nameCmp = mCollator.compare(sa.toString(), sb.toString());
if (nameCmp != 0) {
return nameCmp;
} else {
return a.second - b.second;
}
}
}
private AppOpsManager mAppOpsManager;
private Context mContext;
private PackageManager mPackageManager;
private UserManager mUserManager;
private IconDrawableFactory mIconDrawableFactory;
public TurnScreenOnSettings() {
// Do nothing
}
public TurnScreenOnSettings(PackageManager pm, UserManager um) {
mPackageManager = pm;
mUserManager = um;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mContext = getActivity();
mPackageManager = mContext.getPackageManager();
mUserManager = mContext.getSystemService(UserManager.class);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
}
@Override
public void onResume() {
super.onResume();
// Clear the prefs
final PreferenceScreen screen = getPreferenceScreen();
screen.removeAll();
// Fetch the set of applications for each profile which have the permission required to turn
// the screen on with a wake lock.
final ArrayList<Pair<ApplicationInfo, Integer>> apps = collectTurnScreenOnApps(
UserHandle.myUserId());
apps.sort(new AppComparator(mPackageManager));
// Rebuild the list of prefs
final Context prefContext = getPrefContext();
for (final Pair<ApplicationInfo, Integer> appData : apps) {
final ApplicationInfo appInfo = appData.first;
final int userId = appData.second;
final UserHandle user = UserHandle.of(userId);
final String packageName = appInfo.packageName;
final CharSequence label = appInfo.loadLabel(mPackageManager);
final Preference pref = new AppPreference(prefContext);
pref.setIcon(mIconDrawableFactory.getBadgedIcon(appInfo, userId));
pref.setTitle(mPackageManager.getUserBadgedLabel(label, user));
pref.setSummary(TurnScreenOnDetails.getPreferenceSummary(mAppOpsManager,
appInfo.uid, packageName));
pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
AppInfoBase.startAppInfoFragment(TurnScreenOnDetails.class,
getString(R.string.turn_screen_on_title),
packageName, appInfo.uid,
TurnScreenOnSettings.this, -1, getMetricsCategory());
return true;
}
});
screen.addPreference(pref);
}
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setEmptyText(R.string.no_applications);
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.turn_screen_on_settings;
}
@Override
public int getMetricsCategory() {
return SettingsEnums.SETTINGS_MANAGE_TURN_SCREEN_ON;
}
/**
* @return the list of applications for the given user and all their profiles that can turn on
* the screen with wake locks.
*/
@VisibleForTesting
ArrayList<Pair<ApplicationInfo, Integer>> collectTurnScreenOnApps(int userId) {
final ArrayList<Pair<ApplicationInfo, Integer>> apps = new ArrayList<>();
final ArrayList<Integer> userIds = new ArrayList<>();
for (UserInfo user : mUserManager.getProfiles(userId)) {
userIds.add(user.id);
}
for (int id : userIds) {
final List<PackageInfo> installedPackages = mPackageManager.getInstalledPackagesAsUser(
/* flags= */ 0, id);
for (PackageInfo packageInfo : installedPackages) {
if (hasTurnScreenOnPermission(mPackageManager, packageInfo.packageName)) {
apps.add(new Pair<>(packageInfo.applicationInfo, id));
}
}
}
return apps;
}
/**
* @return true if the package has the permission to turn the screen on.
*/
@VisibleForTesting
static boolean hasTurnScreenOnPermission(PackageManager packageManager, String packageName) {
if (IGNORE_PACKAGE_LIST.contains(packageName)) {
return false;
}
return packageManager.checkPermission(Manifest.permission.WAKE_LOCK, packageName)
== PackageManager.PERMISSION_GRANTED;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.turn_screen_on_settings);
}