Merge "AppClone: Changes to display app list on Cloned Apps page."
This commit is contained in:
@@ -6366,6 +6366,9 @@
|
|||||||
<string name="app_default_dashboard_title">Default apps</string>
|
<string name="app_default_dashboard_title">Default apps</string>
|
||||||
<!-- Title for setting tile leading to App Clones menu under the Apps page [CHAR LIMIT=40] -->
|
<!-- Title for setting tile leading to App Clones menu under the Apps page [CHAR LIMIT=40] -->
|
||||||
<string name="cloned_apps_dashboard_title">Cloned Apps</string>
|
<string name="cloned_apps_dashboard_title">Cloned Apps</string>
|
||||||
|
<!-- Description for introduction of the cloned apps page [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="desc_cloned_apps_intro_text">Create a second instance of an app so that you can use two accounts at the same time.</string>
|
||||||
|
<string name="cloned_apps_summary"><xliff:g id="cloned_apps_count">%1$s</xliff:g> cloned, <xliff:g id="allowed_apps_count">%2$d</xliff:g> available to clone</string>
|
||||||
<!-- Summary text for system preference title, showing important setting items under system setting [CHAR LIMIT=NONE]-->
|
<!-- Summary text for system preference title, showing important setting items under system setting [CHAR LIMIT=NONE]-->
|
||||||
<string name="system_dashboard_summary">Languages, gestures, time, backup</string>
|
<string name="system_dashboard_summary">Languages, gestures, time, backup</string>
|
||||||
<!-- Summary text for language preference title, showing important setting items under language setting [CHAR LIMIT=NONE]-->
|
<!-- Summary text for language preference title, showing important setting items under language setting [CHAR LIMIT=NONE]-->
|
||||||
|
@@ -65,6 +65,7 @@
|
|||||||
<Preference
|
<Preference
|
||||||
android:key="cloned_apps"
|
android:key="cloned_apps"
|
||||||
android:title="@string/cloned_apps_dashboard_title"
|
android:title="@string/cloned_apps_dashboard_title"
|
||||||
|
android:summary="@string/summary_placeholder"
|
||||||
android:order="-995"
|
android:order="-995"
|
||||||
settings:controller="com.android.settings.applications.ClonedAppsPreferenceController"
|
settings:controller="com.android.settings.applications.ClonedAppsPreferenceController"
|
||||||
android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
|
android:fragment="com.android.settings.applications.manageapplications.ManageApplications">
|
||||||
|
@@ -164,6 +164,11 @@ public final class Utils extends com.android.settingslib.Utils {
|
|||||||
public static final String PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS =
|
public static final String PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS =
|
||||||
"app_hibernation_targets_pre_s_apps";
|
"app_hibernation_targets_pre_s_apps";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not Cloned Apps menu is available in Apps page. Default is false.
|
||||||
|
*/
|
||||||
|
public static final String PROPERTY_CLONED_APPS_ENABLED = "cloned_apps_enabled";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a matching activity for a preference's intent. If a matching
|
* Finds a matching activity for a preference's intent. If a matching
|
||||||
* activity is not found, it will remove the preference.
|
* activity is not found, it will remove the preference.
|
||||||
@@ -1252,4 +1257,17 @@ public final class Utils extends com.android.settingslib.Utils {
|
|||||||
public static int getHomepageIconColorHighlight(Context context) {
|
public static int getHomepageIconColorHighlight(Context context) {
|
||||||
return context.getColor(R.color.accent_select_primary_text);
|
return context.getColor(R.color.accent_select_primary_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns user id of clone profile if present, else returns -1.
|
||||||
|
*/
|
||||||
|
public static int getCloneUserId(Context context) {
|
||||||
|
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
|
||||||
|
for (UserHandle userHandle : userManager.getUserProfiles()) {
|
||||||
|
if (userManager.getUserInfo(userHandle.getIdentifier()).isCloneProfile()) {
|
||||||
|
return userHandle.getIdentifier();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.GET_ACTIVITIES;
|
||||||
|
|
||||||
|
import static com.android.settingslib.applications.ApplicationsState.AppEntry;
|
||||||
|
import static com.android.settingslib.applications.ApplicationsState.AppFilter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to display only allowlisted apps on Cloned Apps page.
|
||||||
|
*/
|
||||||
|
public class AppStateClonedAppsBridge extends AppStateBaseBridge{
|
||||||
|
|
||||||
|
private static final String TAG = "ClonedAppsBridge";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final List<String> mAllowedApps;
|
||||||
|
private List<String> mCloneProfileApps = new ArrayList<>();
|
||||||
|
|
||||||
|
public AppStateClonedAppsBridge(Context context, ApplicationsState appState,
|
||||||
|
Callback callback) {
|
||||||
|
super(appState, callback);
|
||||||
|
mContext = context;
|
||||||
|
mAllowedApps = Arrays.asList(mContext.getResources()
|
||||||
|
.getStringArray(com.android.internal.R.array.cloneable_apps));
|
||||||
|
|
||||||
|
int cloneUserId = Utils.getCloneUserId(mContext);
|
||||||
|
if (cloneUserId != -1) {
|
||||||
|
mCloneProfileApps = mContext.getPackageManager()
|
||||||
|
.getInstalledPackagesAsUser(GET_ACTIVITIES,
|
||||||
|
cloneUserId).stream().map(x -> x.packageName).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadAllExtraInfo() {
|
||||||
|
final List<ApplicationsState.AppEntry> allApps = mAppSession.getAllApps();
|
||||||
|
for (int i = 0; i < allApps.size(); i++) {
|
||||||
|
ApplicationsState.AppEntry app = allApps.get(i);
|
||||||
|
this.updateExtraInfo(app, app.info.packageName, app.info.uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
|
||||||
|
// Display package if allowlisted but not yet cloned.
|
||||||
|
// Or if the app is present in clone profile alongwith being in allowlist.
|
||||||
|
if (mAllowedApps.contains(pkg) && ((!mCloneProfileApps.contains(pkg) || (app.isCloned)))) {
|
||||||
|
app.extraInfo = Boolean.TRUE;
|
||||||
|
} else {
|
||||||
|
app.extraInfo = Boolean.FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final AppFilter FILTER_APPS_CLONE =
|
||||||
|
new AppFilter() {
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filterApp(AppEntry entry) {
|
||||||
|
if (entry.extraInfo == null) {
|
||||||
|
Log.d(TAG, "[" + entry.info.packageName + "]" + " has No extra info.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (Boolean) entry.extraInfo;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -16,31 +16,100 @@
|
|||||||
|
|
||||||
package com.android.settings.applications;
|
package com.android.settings.applications;
|
||||||
|
|
||||||
import static com.android.settings.core.SettingsUIDeviceConfig.CLONED_APPS_ENABLED;
|
import static android.content.pm.PackageManager.GET_ACTIVITIES;
|
||||||
|
|
||||||
|
import static com.android.settings.Utils.PROPERTY_CLONED_APPS_ENABLED;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
|
|
||||||
|
import androidx.lifecycle.Lifecycle;
|
||||||
|
import androidx.lifecycle.LifecycleObserver;
|
||||||
|
import androidx.lifecycle.OnLifecycleEvent;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.core.BasePreferenceController;
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A preference controller handling the logic for updating the summary of cloned apps.
|
* A preference controller handling the logic for updating the summary of cloned apps.
|
||||||
*/
|
*/
|
||||||
public class ClonedAppsPreferenceController extends BasePreferenceController {
|
public class ClonedAppsPreferenceController extends BasePreferenceController
|
||||||
|
implements LifecycleObserver {
|
||||||
|
private Preference mPreference;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
public ClonedAppsPreferenceController(Context context, String preferenceKey) {
|
public ClonedAppsPreferenceController(Context context, String preferenceKey) {
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence getSummary() {
|
|
||||||
// todo(b/249916469): Update summary once we have mechanism of allowlisting available
|
|
||||||
// for cloned apps.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public int getAvailabilityStatus() {
|
public int getAvailabilityStatus() {
|
||||||
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_APP_CLONING,
|
||||||
CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
PROPERTY_CLONED_APPS_ENABLED, false) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* On lifecycle resume event.
|
||||||
|
*/
|
||||||
|
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||||
|
public void onResume() {
|
||||||
|
updatePreferenceSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePreferenceSummary() {
|
||||||
|
new AsyncTask<Void, Void, Integer[]>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Integer[] doInBackground(Void... unused) {
|
||||||
|
// Get list of allowlisted cloneable apps.
|
||||||
|
List<String> cloneableApps = Arrays.asList(
|
||||||
|
mContext.getResources().getStringArray(
|
||||||
|
com.android.internal.R.array.cloneable_apps));
|
||||||
|
List<String> primaryUserApps = mContext.getPackageManager()
|
||||||
|
.getInstalledPackagesAsUser(GET_ACTIVITIES,
|
||||||
|
UserHandle.myUserId()).stream().map(x -> x.packageName).toList();
|
||||||
|
// Count number of installed apps in system user.
|
||||||
|
int availableAppsCount = (int) cloneableApps.stream()
|
||||||
|
.filter(x -> primaryUserApps.contains(x)).count();
|
||||||
|
|
||||||
|
int cloneUserId = Utils.getCloneUserId(mContext);
|
||||||
|
if (cloneUserId == -1) {
|
||||||
|
return new Integer[]{0, availableAppsCount};
|
||||||
|
}
|
||||||
|
// Get all apps in clone profile if present.
|
||||||
|
List<String> cloneProfileApps = mContext.getPackageManager()
|
||||||
|
.getInstalledPackagesAsUser(GET_ACTIVITIES,
|
||||||
|
cloneUserId).stream().map(x -> x.packageName).toList();
|
||||||
|
// Count number of allowlisted app present in clone profile.
|
||||||
|
int clonedAppsCount = (int) cloneableApps.stream()
|
||||||
|
.filter(x -> cloneProfileApps.contains(x)).count();
|
||||||
|
|
||||||
|
return new Integer[]{clonedAppsCount, availableAppsCount - clonedAppsCount};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Integer[] countInfo) {
|
||||||
|
updateSummary(countInfo[0], countInfo[1]);
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSummary(int clonedAppsCount, int availableAppsCount) {
|
||||||
|
mPreference.setSummary(mContext.getResources().getString(
|
||||||
|
R.string.cloned_apps_summary, clonedAppsCount, availableAppsCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ import androidx.annotation.IntDef;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
|
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
|
||||||
import com.android.settings.applications.AppStateAppBatteryUsageBridge;
|
import com.android.settings.applications.AppStateAppBatteryUsageBridge;
|
||||||
|
import com.android.settings.applications.AppStateClonedAppsBridge;
|
||||||
import com.android.settings.applications.AppStateInstallAppsBridge;
|
import com.android.settings.applications.AppStateInstallAppsBridge;
|
||||||
import com.android.settings.applications.AppStateLocaleBridge;
|
import com.android.settings.applications.AppStateLocaleBridge;
|
||||||
import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
|
import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
|
||||||
@@ -63,6 +64,7 @@ public class AppFilterRegistry {
|
|||||||
FILTER_APPS_BATTERY_OPTIMIZED,
|
FILTER_APPS_BATTERY_OPTIMIZED,
|
||||||
FILTER_APPS_BATTERY_RESTRICTED,
|
FILTER_APPS_BATTERY_RESTRICTED,
|
||||||
FILTER_LONG_BACKGROUND_TASKS,
|
FILTER_LONG_BACKGROUND_TASKS,
|
||||||
|
FILTER_APPS_CLONE,
|
||||||
})
|
})
|
||||||
@interface FilterType {}
|
@interface FilterType {}
|
||||||
|
|
||||||
@@ -92,8 +94,9 @@ public class AppFilterRegistry {
|
|||||||
public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
|
public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
|
||||||
public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
|
public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
|
||||||
public static final int FILTER_LONG_BACKGROUND_TASKS = 24;
|
public static final int FILTER_LONG_BACKGROUND_TASKS = 24;
|
||||||
// Next id: 25. If you add an entry here, please change NUM_FILTER_ENTRIES.
|
public static final int FILTER_APPS_CLONE = 25;
|
||||||
private static final int NUM_FILTER_ENTRIES = 25;
|
// Next id: 26. If you add an entry here, please change NUM_FILTER_ENTRIES.
|
||||||
|
private static final int NUM_FILTER_ENTRIES = 26;
|
||||||
|
|
||||||
private static AppFilterRegistry sRegistry;
|
private static AppFilterRegistry sRegistry;
|
||||||
|
|
||||||
@@ -251,10 +254,15 @@ public class AppFilterRegistry {
|
|||||||
AppStateLongBackgroundTasksBridge.FILTER_LONG_JOBS_APPS,
|
AppStateLongBackgroundTasksBridge.FILTER_LONG_JOBS_APPS,
|
||||||
FILTER_LONG_BACKGROUND_TASKS,
|
FILTER_LONG_BACKGROUND_TASKS,
|
||||||
R.string.long_background_tasks_title);
|
R.string.long_background_tasks_title);
|
||||||
|
|
||||||
|
// Apps that are cloneable or cloned.
|
||||||
|
mFilters[FILTER_APPS_CLONE] =
|
||||||
|
new AppFilterItem(
|
||||||
|
AppStateClonedAppsBridge.FILTER_APPS_CLONE,
|
||||||
|
FILTER_APPS_CLONE,
|
||||||
|
R.string.cloned_apps_dashboard_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static AppFilterRegistry getInstance() {
|
public static AppFilterRegistry getInstance() {
|
||||||
if (sRegistry == null) {
|
if (sRegistry == null) {
|
||||||
sRegistry = new AppFilterRegistry();
|
sRegistry = new AppFilterRegistry();
|
||||||
@@ -291,6 +299,8 @@ public class AppFilterRegistry {
|
|||||||
return FILTER_APPS_BATTERY_OPTIMIZED;
|
return FILTER_APPS_BATTERY_OPTIMIZED;
|
||||||
case ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS:
|
case ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS:
|
||||||
return FILTER_LONG_BACKGROUND_TASKS;
|
return FILTER_LONG_BACKGROUND_TASKS;
|
||||||
|
case ManageApplications.LIST_TYPE_CLONED_APPS:
|
||||||
|
return FILTER_APPS_CLONE;
|
||||||
default:
|
default:
|
||||||
return FILTER_APPS_ALL;
|
return FILTER_APPS_ALL;
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.applications.manageapplications;
|
package com.android.settings.applications.manageapplications;
|
||||||
|
|
||||||
|
import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -49,6 +52,8 @@ public class ApplicationViewHolder extends RecyclerView.ViewHolder {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
final Switch mSwitch;
|
final Switch mSwitch;
|
||||||
|
|
||||||
|
private static int sListType;
|
||||||
|
|
||||||
private final ImageView mAppIcon;
|
private final ImageView mAppIcon;
|
||||||
|
|
||||||
ApplicationViewHolder(View itemView) {
|
ApplicationViewHolder(View itemView) {
|
||||||
@@ -65,15 +70,31 @@ public class ApplicationViewHolder extends RecyclerView.ViewHolder {
|
|||||||
return newView(parent, false /* twoTarget */);
|
return newView(parent, false /* twoTarget */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static View newView(ViewGroup parent , boolean twoTarget, int listType, Context context) {
|
||||||
|
sListType = listType;
|
||||||
|
return newView(parent, twoTarget);
|
||||||
|
}
|
||||||
|
|
||||||
static View newView(ViewGroup parent, boolean twoTarget) {
|
static View newView(ViewGroup parent, boolean twoTarget) {
|
||||||
ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext())
|
ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.preference_app, parent, false);
|
.inflate(R.layout.preference_app, parent, false);
|
||||||
final ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
|
final ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
|
||||||
if (twoTarget) {
|
if (twoTarget) {
|
||||||
if (widgetFrame != null) {
|
if (widgetFrame != null) {
|
||||||
|
if (sListType == LIST_TYPE_CLONED_APPS) {
|
||||||
|
LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.preference_widget_add, widgetFrame, true);
|
||||||
|
//todo(b/259022623): Invoke the clone backend flow i.e.
|
||||||
|
// i) upon onclick of add icon, create new clone profile the first time
|
||||||
|
// and clone an app.
|
||||||
|
// ii) Show progress bar while app is being cloned
|
||||||
|
// iii) And upon onClick of trash icon, delete the cloned app instance
|
||||||
|
// from clone profile.
|
||||||
|
// iv) Log metrics
|
||||||
|
} else {
|
||||||
LayoutInflater.from(parent.getContext())
|
LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.preference_widget_primary_switch, widgetFrame, true);
|
.inflate(R.layout.preference_widget_primary_switch, widgetFrame, true);
|
||||||
|
}
|
||||||
View divider = LayoutInflater.from(parent.getContext()).inflate(
|
View divider = LayoutInflater.from(parent.getContext()).inflate(
|
||||||
R.layout.preference_two_target_divider, view, false);
|
R.layout.preference_two_target_divider, view, false);
|
||||||
// second to last, before widget frame
|
// second to last, before widget frame
|
||||||
|
@@ -92,6 +92,7 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.Settings.AlarmsAndRemindersActivity;
|
import com.android.settings.Settings.AlarmsAndRemindersActivity;
|
||||||
import com.android.settings.Settings.AppBatteryUsageActivity;
|
import com.android.settings.Settings.AppBatteryUsageActivity;
|
||||||
import com.android.settings.Settings.ChangeWifiStateActivity;
|
import com.android.settings.Settings.ChangeWifiStateActivity;
|
||||||
|
import com.android.settings.Settings.ClonedAppsListActivity;
|
||||||
import com.android.settings.Settings.HighPowerApplicationsActivity;
|
import com.android.settings.Settings.HighPowerApplicationsActivity;
|
||||||
import com.android.settings.Settings.LongBackgroundTasksActivity;
|
import com.android.settings.Settings.LongBackgroundTasksActivity;
|
||||||
import com.android.settings.Settings.ManageExternalSourcesActivity;
|
import com.android.settings.Settings.ManageExternalSourcesActivity;
|
||||||
@@ -109,6 +110,7 @@ import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
|
|||||||
import com.android.settings.applications.AppStateAppBatteryUsageBridge;
|
import com.android.settings.applications.AppStateAppBatteryUsageBridge;
|
||||||
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
|
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
|
||||||
import com.android.settings.applications.AppStateBaseBridge;
|
import com.android.settings.applications.AppStateBaseBridge;
|
||||||
|
import com.android.settings.applications.AppStateClonedAppsBridge;
|
||||||
import com.android.settings.applications.AppStateInstallAppsBridge;
|
import com.android.settings.applications.AppStateInstallAppsBridge;
|
||||||
import com.android.settings.applications.AppStateLocaleBridge;
|
import com.android.settings.applications.AppStateLocaleBridge;
|
||||||
import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
|
import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
|
||||||
@@ -250,6 +252,7 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
public static final int LIST_TYPE_APPS_LOCALE = 14;
|
public static final int LIST_TYPE_APPS_LOCALE = 14;
|
||||||
public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
|
public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
|
||||||
public static final int LIST_TYPE_LONG_BACKGROUND_TASKS = 16;
|
public static final int LIST_TYPE_LONG_BACKGROUND_TASKS = 16;
|
||||||
|
public static final int LIST_TYPE_CLONED_APPS = 17;
|
||||||
|
|
||||||
// List types that should show instant apps.
|
// List types that should show instant apps.
|
||||||
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
|
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
|
||||||
@@ -544,6 +547,8 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
|
return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
|
||||||
case LIST_TYPE_LONG_BACKGROUND_TASKS:
|
case LIST_TYPE_LONG_BACKGROUND_TASKS:
|
||||||
return SettingsEnums.LONG_BACKGROUND_TASKS;
|
return SettingsEnums.LONG_BACKGROUND_TASKS;
|
||||||
|
case LIST_TYPE_CLONED_APPS:
|
||||||
|
return SettingsEnums.CLONED_APPS;
|
||||||
default:
|
default:
|
||||||
return SettingsEnums.PAGE_UNKNOWN;
|
return SettingsEnums.PAGE_UNKNOWN;
|
||||||
}
|
}
|
||||||
@@ -798,9 +803,11 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
&& mSortOrder != R.id.sort_order_size);
|
&& mSortOrder != R.id.sort_order_size);
|
||||||
|
|
||||||
mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem
|
mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem
|
||||||
&& mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
|
&& mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE
|
||||||
|
&& mListType != LIST_TYPE_CLONED_APPS);
|
||||||
mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem
|
mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem
|
||||||
&& mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
|
&& mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE
|
||||||
|
&& mListType != LIST_TYPE_CLONED_APPS);
|
||||||
|
|
||||||
mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN);
|
mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN);
|
||||||
|
|
||||||
@@ -983,6 +990,8 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
screenTitle = R.string.app_battery_usage_title;
|
screenTitle = R.string.app_battery_usage_title;
|
||||||
} else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
|
} else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
|
||||||
screenTitle = R.string.long_background_tasks_title;
|
screenTitle = R.string.long_background_tasks_title;
|
||||||
|
} else if (className.equals(ClonedAppsListActivity.class.getName())) {
|
||||||
|
screenTitle = R.string.cloned_apps_dashboard_title;
|
||||||
} else {
|
} else {
|
||||||
if (screenTitle == -1) {
|
if (screenTitle == -1) {
|
||||||
screenTitle = R.string.all_apps;
|
screenTitle = R.string.all_apps;
|
||||||
@@ -1111,6 +1120,7 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
private static final int VIEW_TYPE_APP = 0;
|
private static final int VIEW_TYPE_APP = 0;
|
||||||
private static final int VIEW_TYPE_EXTRA_VIEW = 1;
|
private static final int VIEW_TYPE_EXTRA_VIEW = 1;
|
||||||
private static final int VIEW_TYPE_APP_HEADER = 2;
|
private static final int VIEW_TYPE_APP_HEADER = 2;
|
||||||
|
private static final int VIEW_TYPE_TWO_TARGET = 3;
|
||||||
|
|
||||||
private final ApplicationsState mState;
|
private final ApplicationsState mState;
|
||||||
private final ApplicationsState.Session mSession;
|
private final ApplicationsState.Session mSession;
|
||||||
@@ -1188,6 +1198,8 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
mExtraInfoBridge = new AppStateAppBatteryUsageBridge(mContext, mState, this);
|
mExtraInfoBridge = new AppStateAppBatteryUsageBridge(mContext, mState, this);
|
||||||
} else if (mManageApplications.mListType == LIST_TYPE_LONG_BACKGROUND_TASKS) {
|
} else if (mManageApplications.mListType == LIST_TYPE_LONG_BACKGROUND_TASKS) {
|
||||||
mExtraInfoBridge = new AppStateLongBackgroundTasksBridge(mContext, mState, this);
|
mExtraInfoBridge = new AppStateLongBackgroundTasksBridge(mContext, mState, this);
|
||||||
|
} else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS) {
|
||||||
|
mExtraInfoBridge = new AppStateClonedAppsBridge(mContext, mState, this);
|
||||||
} else {
|
} else {
|
||||||
mExtraInfoBridge = null;
|
mExtraInfoBridge = null;
|
||||||
}
|
}
|
||||||
@@ -1301,6 +1313,14 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
R.string.desc_app_locale_selection_supported);
|
R.string.desc_app_locale_selection_supported);
|
||||||
} else if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
|
} else if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
|
||||||
view = ApplicationViewHolder.newView(parent, true /* twoTarget */);
|
view = ApplicationViewHolder.newView(parent, true /* twoTarget */);
|
||||||
|
} else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS
|
||||||
|
&& viewType == VIEW_TYPE_APP_HEADER) {
|
||||||
|
view = ApplicationViewHolder.newHeader(parent,
|
||||||
|
R.string.desc_cloned_apps_intro_text);
|
||||||
|
} else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS
|
||||||
|
&& viewType == VIEW_TYPE_TWO_TARGET) {
|
||||||
|
view = ApplicationViewHolder.newView(
|
||||||
|
parent, true, LIST_TYPE_CLONED_APPS, mContext);
|
||||||
} else {
|
} else {
|
||||||
view = ApplicationViewHolder.newView(parent, false /* twoTarget */);
|
view = ApplicationViewHolder.newView(parent, false /* twoTarget */);
|
||||||
}
|
}
|
||||||
@@ -1309,8 +1329,11 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
if (position == 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
|
if (position == 0 && (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE
|
||||||
|
|| mManageApplications.mListType == LIST_TYPE_CLONED_APPS)) {
|
||||||
return VIEW_TYPE_APP_HEADER;
|
return VIEW_TYPE_APP_HEADER;
|
||||||
|
} else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS) {
|
||||||
|
return VIEW_TYPE_TWO_TARGET;
|
||||||
}
|
}
|
||||||
return VIEW_TYPE_APP;
|
return VIEW_TYPE_APP;
|
||||||
}
|
}
|
||||||
@@ -1570,7 +1593,8 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
int count = getApplicationCount();
|
int count = getApplicationCount();
|
||||||
if (count != 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
|
if (count != 0 && (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE
|
||||||
|
|| mManageApplications.mListType == LIST_TYPE_CLONED_APPS)) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
@@ -1720,6 +1744,9 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
case LIST_TYPE_LONG_BACKGROUND_TASKS:
|
case LIST_TYPE_LONG_BACKGROUND_TASKS:
|
||||||
holder.setSummary(LongBackgroundTasksDetails.getSummary(mContext, entry));
|
holder.setSummary(LongBackgroundTasksDetails.getSummary(mContext, entry));
|
||||||
break;
|
break;
|
||||||
|
case LIST_TYPE_CLONED_APPS:
|
||||||
|
holder.setSummary(null);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
|
holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
|
||||||
break;
|
break;
|
||||||
@@ -1741,6 +1768,9 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
holder.setSummary(null);
|
holder.setSummary(null);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case LIST_TYPE_CLONED_APPS:
|
||||||
|
//todo(b/259022623): Attach onClick listener here.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1754,7 +1784,7 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
public static int getApplicationPosition(int listType, int position) {
|
public static int getApplicationPosition(int listType, int position) {
|
||||||
int applicationPosition = position;
|
int applicationPosition = position;
|
||||||
// Adjust position due to header added.
|
// Adjust position due to header added.
|
||||||
if (listType == LIST_TYPE_APPS_LOCALE) {
|
if (listType == LIST_TYPE_APPS_LOCALE || listType == LIST_TYPE_CLONED_APPS) {
|
||||||
applicationPosition = position > 0 ? position - 1 : RecyclerView.NO_POSITION;
|
applicationPosition = position > 0 ? position - 1 : RecyclerView.NO_POSITION;
|
||||||
}
|
}
|
||||||
return applicationPosition;
|
return applicationPosition;
|
||||||
|
@@ -21,6 +21,7 @@ import android.util.FeatureFlagUtils
|
|||||||
import com.android.settings.Settings.AlarmsAndRemindersActivity
|
import com.android.settings.Settings.AlarmsAndRemindersActivity
|
||||||
import com.android.settings.Settings.AppBatteryUsageActivity
|
import com.android.settings.Settings.AppBatteryUsageActivity
|
||||||
import com.android.settings.Settings.ChangeWifiStateActivity
|
import com.android.settings.Settings.ChangeWifiStateActivity
|
||||||
|
import com.android.settings.Settings.ClonedAppsListActivity
|
||||||
import com.android.settings.Settings.GamesStorageActivity
|
import com.android.settings.Settings.GamesStorageActivity
|
||||||
import com.android.settings.Settings.HighPowerApplicationsActivity
|
import com.android.settings.Settings.HighPowerApplicationsActivity
|
||||||
import com.android.settings.Settings.LongBackgroundTasksActivity
|
import com.android.settings.Settings.LongBackgroundTasksActivity
|
||||||
@@ -38,6 +39,7 @@ import com.android.settings.applications.manageapplications.ManageApplications.L
|
|||||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS
|
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_ALARMS_AND_REMINDERS
|
||||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_APPS_LOCALE
|
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_APPS_LOCALE
|
||||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION
|
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION
|
||||||
|
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_CLONED_APPS
|
||||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES
|
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_GAMES
|
||||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER
|
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_HIGH_POWER
|
||||||
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS
|
import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS
|
||||||
@@ -81,6 +83,7 @@ object ManageApplicationsUtil {
|
|||||||
AppLocaleDetails::class to LIST_TYPE_APPS_LOCALE,
|
AppLocaleDetails::class to LIST_TYPE_APPS_LOCALE,
|
||||||
AppBatteryUsageActivity::class to LIST_TYPE_BATTERY_OPTIMIZATION,
|
AppBatteryUsageActivity::class to LIST_TYPE_BATTERY_OPTIMIZATION,
|
||||||
LongBackgroundTasksActivity::class to LIST_TYPE_LONG_BACKGROUND_TASKS,
|
LongBackgroundTasksActivity::class to LIST_TYPE_LONG_BACKGROUND_TASKS,
|
||||||
|
ClonedAppsListActivity::class to LIST_TYPE_CLONED_APPS,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
|
@@ -42,9 +42,4 @@ public class SettingsUIDeviceConfig {
|
|||||||
* {@code true} whether or not event_log for generic actions is enabled. Default is true.
|
* {@code true} whether or not event_log for generic actions is enabled. Default is true.
|
||||||
*/
|
*/
|
||||||
public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
|
public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
|
||||||
|
|
||||||
/**
|
|
||||||
* {@code true} if Cloned Apps menu is available in Apps page. Default is false.
|
|
||||||
*/
|
|
||||||
public static final String CLONED_APPS_ENABLED = "cloned_apps_enabled";
|
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package com.android.settings.applications;
|
package com.android.settings.applications;
|
||||||
|
|
||||||
import static android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI;
|
import static android.provider.DeviceConfig.NAMESPACE_APP_CLONING;
|
||||||
|
|
||||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ import android.provider.DeviceConfig;
|
|||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import com.android.settings.core.SettingsUIDeviceConfig;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
|
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -54,7 +54,7 @@ public class ClonedAppsPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() {
|
public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() {
|
||||||
DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.CLONED_APPS_ENABLED,
|
DeviceConfig.setProperty(NAMESPACE_APP_CLONING, Utils.PROPERTY_CLONED_APPS_ENABLED,
|
||||||
"false", true /* makeDefault */);
|
"false", true /* makeDefault */);
|
||||||
|
|
||||||
assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
|
assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE);
|
||||||
@@ -62,10 +62,9 @@ public class ClonedAppsPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable() {
|
public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable() {
|
||||||
DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, SettingsUIDeviceConfig.CLONED_APPS_ENABLED,
|
DeviceConfig.setProperty(NAMESPACE_APP_CLONING, Utils.PROPERTY_CLONED_APPS_ENABLED,
|
||||||
"true", true /* makeDefault */);
|
"true", true /* makeDefault */);
|
||||||
|
|
||||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user