1 /* 2 * Copyright (C) 2015 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.tv.settings.device.apps; 18 19 import android.app.Activity; 20 import android.app.ActivityManager; 21 import android.content.ActivityNotFoundException; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.pm.IPackageDataObserver; 25 import android.content.pm.PackageManager; 26 import android.graphics.drawable.Drawable; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.UserHandle; 30 import android.support.annotation.NonNull; 31 import android.support.v17.preference.LeanbackPreferenceFragment; 32 import android.support.v7.preference.Preference; 33 import android.support.v7.preference.PreferenceScreen; 34 import android.util.Log; 35 import android.widget.Toast; 36 37 import com.android.settingslib.applications.ApplicationsState; 38 import com.android.tv.settings.R; 39 40 import java.util.ArrayList; 41 42 public class AppManagementFragment extends LeanbackPreferenceFragment { 43 private static final String TAG = "AppManagementFragment"; 44 45 private static final String ARG_PACKAGE_NAME = "packageName"; 46 47 // Result code identifiers 48 private static final int REQUEST_UNINSTALL = 1; 49 private static final int REQUEST_MANAGE_SPACE = 2; 50 private static final int REQUEST_UNINSTALL_UPDATES = 3; 51 52 private PackageManager mPackageManager; 53 private String mPackageName; 54 private ApplicationsState mApplicationsState; 55 private ApplicationsState.Session mSession; 56 private ApplicationsState.AppEntry mEntry; 57 private final ApplicationsState.Callbacks mCallbacks = new ApplicationsStateCallbacks(); 58 59 private ForceStopPreference mForceStopPreference; 60 private UninstallPreference mUninstallPreference; 61 private EnableDisablePreference mEnableDisablePreference; 62 private AppStoragePreference mAppStoragePreference; 63 private ClearDataPreference mClearDataPreference; 64 private ClearCachePreference mClearCachePreference; 65 private ClearDefaultsPreference mClearDefaultsPreference; 66 private NotificationsPreference mNotificationsPreference; 67 68 private final Handler mHandler = new Handler(); 69 private Runnable mBailoutRunnable = new Runnable() { 70 @Override 71 public void run() { 72 if (isResumed() && !getFragmentManager().popBackStackImmediate()) { 73 getActivity().onBackPressed(); 74 } 75 } 76 }; 77 prepareArgs(@onNull Bundle args, String packageName)78 public static void prepareArgs(@NonNull Bundle args, String packageName) { 79 args.putString(ARG_PACKAGE_NAME, packageName); 80 } 81 82 @Override onCreate(Bundle savedInstanceState)83 public void onCreate(Bundle savedInstanceState) { 84 mPackageName = getArguments().getString(ARG_PACKAGE_NAME); 85 86 final Activity activity = getActivity(); 87 mPackageManager = activity.getPackageManager(); 88 mApplicationsState = ApplicationsState.getInstance(activity.getApplication()); 89 mSession = mApplicationsState.newSession(mCallbacks); 90 mEntry = mApplicationsState.getEntry(mPackageName, UserHandle.myUserId()); 91 92 super.onCreate(savedInstanceState); 93 } 94 95 @Override onResume()96 public void onResume() { 97 super.onResume(); 98 mSession.resume(); 99 100 if (mEntry == null) { 101 Log.w(TAG, "App not found, trying to bail out"); 102 navigateBack(); 103 } 104 105 if (mClearDefaultsPreference != null) { 106 mClearDefaultsPreference.refresh(); 107 } 108 if (mEnableDisablePreference != null) { 109 mEnableDisablePreference.refresh(); 110 } 111 } 112 113 @Override onPause()114 public void onPause() { 115 super.onPause(); 116 mSession.pause(); 117 mHandler.removeCallbacks(mBailoutRunnable); 118 } 119 120 @Override onActivityResult(int requestCode, int resultCode, Intent data)121 public void onActivityResult(int requestCode, int resultCode, Intent data) { 122 super.onActivityResult(requestCode, resultCode, data); 123 if (mEntry == null) { 124 return; 125 } 126 switch (requestCode) { 127 case REQUEST_UNINSTALL: 128 if (resultCode == Activity.RESULT_OK) { 129 final int userId = UserHandle.getUserId(mEntry.info.uid); 130 mApplicationsState.removePackage(mPackageName, userId); 131 navigateBack(); 132 } 133 break; 134 case REQUEST_MANAGE_SPACE: 135 mClearDataPreference.setClearingData(false); 136 if(resultCode == Activity.RESULT_OK) { 137 final int userId = UserHandle.getUserId(mEntry.info.uid); 138 mApplicationsState.requestSize(mPackageName, userId); 139 } else { 140 Log.w(TAG, "Failed to clear data!"); 141 } 142 break; 143 case REQUEST_UNINSTALL_UPDATES: 144 mUninstallPreference.refresh(); 145 break; 146 } 147 } 148 navigateBack()149 private void navigateBack() { 150 // need to post this to avoid recursing in the fragment manager. 151 mHandler.removeCallbacks(mBailoutRunnable); 152 mHandler.post(mBailoutRunnable); 153 } 154 155 @Override onPreferenceTreeClick(Preference preference)156 public boolean onPreferenceTreeClick(Preference preference) { 157 if (preference.getIntent() != null) { 158 try { 159 startActivity(preference.getIntent()); 160 } catch (ActivityNotFoundException e) { 161 Log.e(TAG, "Could not find activity to launch", e); 162 // TODO(b/30507703): don't reuse this string 163 Toast.makeText(getContext(), R.string.status_unavailable, 164 Toast.LENGTH_SHORT).show(); 165 } 166 return true; 167 } else { 168 return super.onPreferenceTreeClick(preference); 169 } 170 } 171 172 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)173 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 174 final Context themedContext = getPreferenceManager().getContext(); 175 final PreferenceScreen screen = 176 getPreferenceManager().createPreferenceScreen(themedContext); 177 screen.setTitle(getAppName()); 178 179 if (mEntry == null) { 180 setPreferenceScreen(screen); 181 return; 182 } 183 184 final Preference versionPreference = new Preference(themedContext); 185 versionPreference.setSelectable(false); 186 versionPreference.setTitle(getString(R.string.device_apps_app_management_version, 187 mEntry.getVersion(getActivity()))); 188 versionPreference.setSummary(mPackageName); 189 screen.addPreference(versionPreference); 190 191 // Open 192 Intent appLaunchIntent = 193 mPackageManager.getLeanbackLaunchIntentForPackage(mEntry.info.packageName); 194 if (appLaunchIntent == null) { 195 appLaunchIntent = mPackageManager.getLaunchIntentForPackage(mEntry.info.packageName); 196 } 197 if (appLaunchIntent != null) { 198 final Preference openPreference = new Preference(themedContext); 199 openPreference.setIntent(appLaunchIntent); 200 openPreference.setTitle(R.string.device_apps_app_management_open); 201 screen.addPreference(openPreference); 202 } 203 204 // Force stop 205 mForceStopPreference = new ForceStopPreference(themedContext, mEntry); 206 screen.addPreference(mForceStopPreference); 207 208 // Uninstall 209 mUninstallPreference = new UninstallPreference(themedContext, mEntry); 210 screen.addPreference(mUninstallPreference); 211 212 // Disable/Enable 213 mEnableDisablePreference = new EnableDisablePreference(themedContext, mEntry); 214 screen.addPreference(mEnableDisablePreference); 215 216 // Storage used 217 mAppStoragePreference = new AppStoragePreference(themedContext, mEntry); 218 screen.addPreference(mAppStoragePreference); 219 220 // Clear data 221 mClearDataPreference = new ClearDataPreference(themedContext, mEntry); 222 screen.addPreference(mClearDataPreference); 223 224 // Clear cache 225 mClearCachePreference = new ClearCachePreference(themedContext, mEntry); 226 screen.addPreference(mClearCachePreference); 227 228 // Clear defaults 229 mClearDefaultsPreference = new ClearDefaultsPreference(themedContext, mEntry); 230 screen.addPreference(mClearDefaultsPreference); 231 232 // Notifications 233 mNotificationsPreference = new NotificationsPreference(themedContext, mEntry); 234 screen.addPreference(mNotificationsPreference); 235 236 // Permissions 237 final Preference permissionsPreference = new Preference(themedContext); 238 permissionsPreference.setTitle(R.string.device_apps_app_management_permissions); 239 permissionsPreference.setIntent(new Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS) 240 .putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName)); 241 screen.addPreference(permissionsPreference); 242 243 setPreferenceScreen(screen); 244 } 245 getAppName()246 public String getAppName() { 247 if (mEntry == null) { 248 return null; 249 } 250 mEntry.ensureLabel(getActivity()); 251 return mEntry.label; 252 } 253 getAppIcon()254 public Drawable getAppIcon() { 255 if (mEntry == null) { 256 return null; 257 } 258 mApplicationsState.ensureIcon(mEntry); 259 return mEntry.icon; 260 } 261 clearData()262 public void clearData() { 263 mClearDataPreference.setClearingData(true); 264 String spaceManagementActivityName = mEntry.info.manageSpaceActivityName; 265 if (spaceManagementActivityName != null) { 266 if (!ActivityManager.isUserAMonkey()) { 267 Intent intent = new Intent(Intent.ACTION_DEFAULT); 268 intent.setClassName(mEntry.info.packageName, spaceManagementActivityName); 269 startActivityForResult(intent, REQUEST_MANAGE_SPACE); 270 } 271 } else { 272 ActivityManager am = (ActivityManager) getActivity().getSystemService( 273 Context.ACTIVITY_SERVICE); 274 boolean success = am.clearApplicationUserData( 275 mEntry.info.packageName, new IPackageDataObserver.Stub() { 276 public void onRemoveCompleted( 277 final String packageName, final boolean succeeded) { 278 mHandler.post(new Runnable() { 279 @Override 280 public void run() { 281 mClearDataPreference.setClearingData(false); 282 if (succeeded) { 283 dataCleared(true); 284 } else { 285 dataCleared(false); 286 } 287 } 288 }); 289 } 290 }); 291 if (!success) { 292 mClearDataPreference.setClearingData(false); 293 dataCleared(false); 294 } 295 } 296 mClearDataPreference.refresh(); 297 } 298 dataCleared(boolean succeeded)299 private void dataCleared(boolean succeeded) { 300 if (succeeded) { 301 final int userId = UserHandle.getUserId(mEntry.info.uid); 302 mApplicationsState.requestSize(mPackageName, userId); 303 } else { 304 Log.w(TAG, "Failed to clear data!"); 305 mClearDataPreference.refresh(); 306 } 307 } 308 clearCache()309 public void clearCache() { 310 mClearCachePreference.setClearingCache(true); 311 mPackageManager.deleteApplicationCacheFiles(mEntry.info.packageName, 312 new IPackageDataObserver.Stub() { 313 public void onRemoveCompleted(final String packageName, 314 final boolean succeeded) { 315 mHandler.post(new Runnable() { 316 @Override 317 public void run() { 318 mClearCachePreference.setClearingCache(false); 319 cacheCleared(succeeded); 320 } 321 }); 322 } 323 }); 324 mClearCachePreference.refresh(); 325 } 326 cacheCleared(boolean succeeded)327 private void cacheCleared(boolean succeeded) { 328 if (succeeded) { 329 final int userId = UserHandle.getUserId(mEntry.info.uid); 330 mApplicationsState.requestSize(mPackageName, userId); 331 } else { 332 Log.w(TAG, "Failed to clear cache!"); 333 mClearCachePreference.refresh(); 334 } 335 } 336 launchUninstall()337 public void launchUninstall() { 338 if (mUninstallPreference.canUninstall() || mUninstallPreference.canUninstallUpdates()) { 339 Intent uninstallIntent = mUninstallPreference.getUninstallIntent(); 340 uninstallIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); 341 startActivityForResult(uninstallIntent, REQUEST_UNINSTALL); 342 } 343 mUninstallPreference.refresh(); 344 } 345 346 private class ApplicationsStateCallbacks implements ApplicationsState.Callbacks { 347 348 @Override onRunningStateChanged(boolean running)349 public void onRunningStateChanged(boolean running) { 350 if (mForceStopPreference != null) { 351 mForceStopPreference.refresh(); 352 } 353 } 354 355 @Override onPackageListChanged()356 public void onPackageListChanged() { 357 if (mEntry == null) { 358 return; 359 } 360 final int userId = UserHandle.getUserId(mEntry.info.uid); 361 mEntry = mApplicationsState.getEntry(mPackageName, userId); 362 if (mEntry == null) { 363 navigateBack(); 364 } 365 onCreatePreferences(null, null); 366 } 367 368 @Override onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps)369 public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {} 370 371 @Override onPackageIconChanged()372 public void onPackageIconChanged() {} 373 374 @Override onPackageSizeChanged(String packageName)375 public void onPackageSizeChanged(String packageName) { 376 if (mAppStoragePreference == null) { 377 // Nothing to do here. 378 return; 379 } 380 mAppStoragePreference.refresh(); 381 mClearDataPreference.refresh(); 382 mClearCachePreference.refresh(); 383 } 384 385 @Override onAllSizesComputed()386 public void onAllSizesComputed() { 387 if (mAppStoragePreference == null) { 388 // Nothing to do here. 389 return; 390 } 391 mAppStoragePreference.refresh(); 392 mClearDataPreference.refresh(); 393 mClearCachePreference.refresh(); 394 } 395 396 @Override onLauncherInfoChanged()397 public void onLauncherInfoChanged() {} 398 399 @Override onLoadEntriesCompleted()400 public void onLoadEntriesCompleted() { 401 if (mAppStoragePreference == null) { 402 // Nothing to do here. 403 return; 404 } 405 mAppStoragePreference.refresh(); 406 mClearDataPreference.refresh(); 407 mClearCachePreference.refresh(); 408 } 409 } 410 } 411