1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.applications; 18 19 import android.app.Application; 20 import android.app.usage.UsageStats; 21 import android.content.Context; 22 import android.icu.text.RelativeDateTimeFormatter; 23 import android.os.UserHandle; 24 import android.view.View; 25 26 import androidx.annotation.NonNull; 27 import androidx.annotation.VisibleForTesting; 28 import androidx.fragment.app.Fragment; 29 import androidx.preference.Preference; 30 import androidx.preference.PreferenceScreen; 31 32 import com.android.settings.R; 33 import com.android.settings.applications.appinfo.AppInfoDashboardFragment; 34 import com.android.settings.applications.manageapplications.ManageApplications; 35 import com.android.settings.core.BasePreferenceController; 36 import com.android.settings.core.SubSettingLauncher; 37 import com.android.settings.overlay.FeatureFactory; 38 import com.android.settingslib.Utils; 39 import com.android.settingslib.applications.ApplicationsState; 40 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 41 import com.android.settingslib.utils.StringUtil; 42 import com.android.settingslib.widget.AppEntitiesHeaderController; 43 import com.android.settingslib.widget.AppEntityInfo; 44 import com.android.settingslib.widget.LayoutPreference; 45 46 import java.util.List; 47 48 /** 49 * This controller displays up to three recently used apps. 50 * If there is no recently used app, we only show up an "App Info" preference. 51 */ 52 public class RecentAppsPreferenceController extends BasePreferenceController 53 implements RecentAppStatsMixin.RecentAppStatsListener { 54 55 @VisibleForTesting 56 static final String KEY_DIVIDER = "recent_apps_divider"; 57 58 @VisibleForTesting 59 AppEntitiesHeaderController mAppEntitiesController; 60 @VisibleForTesting 61 LayoutPreference mRecentAppsPreference; 62 @VisibleForTesting 63 Preference mDivider; 64 65 private final ApplicationsState mApplicationsState; 66 private final int mUserId; 67 private final MetricsFeatureProvider mMetricsFeatureProvider; 68 69 private Fragment mHost; 70 private List<UsageStats> mRecentApps; 71 RecentAppsPreferenceController(Context context, String key)72 public RecentAppsPreferenceController(Context context, String key) { 73 super(context, key); 74 mApplicationsState = ApplicationsState.getInstance( 75 (Application) mContext.getApplicationContext()); 76 mUserId = UserHandle.myUserId(); 77 mMetricsFeatureProvider = FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(); 78 } 79 setFragment(Fragment fragment)80 public void setFragment(Fragment fragment) { 81 mHost = fragment; 82 } 83 84 @Override getAvailabilityStatus()85 public int getAvailabilityStatus() { 86 return AVAILABLE_UNSEARCHABLE; 87 } 88 89 @Override displayPreference(PreferenceScreen screen)90 public void displayPreference(PreferenceScreen screen) { 91 super.displayPreference(screen); 92 93 mDivider = screen.findPreference(KEY_DIVIDER); 94 mRecentAppsPreference = screen.findPreference(getPreferenceKey()); 95 final View view = mRecentAppsPreference.findViewById(R.id.app_entities_header); 96 mAppEntitiesController = AppEntitiesHeaderController.newInstance(mContext, view) 97 .setHeaderTitleRes(R.string.recent_app_category_title) 98 .setHeaderDetailsClickListener((View v) -> { 99 mMetricsFeatureProvider.logClickedPreference(mRecentAppsPreference, 100 getMetricsCategory()); 101 new SubSettingLauncher(mContext) 102 .setDestination(ManageApplications.class.getName()) 103 .setArguments(null /* arguments */) 104 .setTitleRes(R.string.application_info_label) 105 .setSourceMetricsCategory(getMetricsCategory()) 106 .launch(); 107 }); 108 } 109 110 @Override onReloadDataCompleted(@onNull List<UsageStats> recentApps)111 public void onReloadDataCompleted(@NonNull List<UsageStats> recentApps) { 112 mRecentApps = recentApps; 113 refreshUi(); 114 // Show total number of installed apps as See all's summary. 115 new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON, 116 mContext.getPackageManager()) { 117 @Override 118 protected void onCountComplete(int num) { 119 mAppEntitiesController.setHeaderDetails( 120 mContext.getResources().getQuantityString(R.plurals.see_all_apps_title, 121 num, num)); 122 mAppEntitiesController.apply(); 123 } 124 }.execute(); 125 } 126 refreshUi()127 private void refreshUi() { 128 if (!mRecentApps.isEmpty()) { 129 displayRecentApps(); 130 mRecentAppsPreference.setVisible(true); 131 mDivider.setVisible(true); 132 } else { 133 mDivider.setVisible(false); 134 mRecentAppsPreference.setVisible(false); 135 } 136 } 137 displayRecentApps()138 private void displayRecentApps() { 139 int showAppsCount = 0; 140 141 for (UsageStats stat : mRecentApps) { 142 final AppEntityInfo appEntityInfoInfo = createAppEntity(stat); 143 if (appEntityInfoInfo != null) { 144 mAppEntitiesController.setAppEntity(showAppsCount++, appEntityInfoInfo); 145 } 146 147 if (showAppsCount == AppEntitiesHeaderController.MAXIMUM_APPS) { 148 break; 149 } 150 } 151 } 152 createAppEntity(UsageStats stat)153 private AppEntityInfo createAppEntity(UsageStats stat) { 154 final String pkgName = stat.getPackageName(); 155 final ApplicationsState.AppEntry appEntry = 156 mApplicationsState.getEntry(pkgName, mUserId); 157 if (appEntry == null) { 158 return null; 159 } 160 161 return new AppEntityInfo.Builder() 162 .setIcon(Utils.getBadgedIcon(mContext, appEntry.info)) 163 .setTitle(appEntry.label) 164 .setSummary(StringUtil.formatRelativeTime(mContext, 165 System.currentTimeMillis() - stat.getLastTimeUsed(), false, 166 RelativeDateTimeFormatter.Style.SHORT)) 167 .setOnClickListener(v -> { 168 mMetricsFeatureProvider.logClickedPreference(mRecentAppsPreference, 169 getMetricsCategory()); 170 AppInfoBase.startAppInfoFragment(AppInfoDashboardFragment.class, 171 R.string.application_info_label, pkgName, appEntry.info.uid, 172 mHost, 1001 /*RequestCode*/, getMetricsCategory()); 173 }) 174 .build(); 175 } 176 } 177