SystemServicesProxy.java revision 559b8c5f4ef20678d40a2d4161dfa14b378d2d91
1/* 2 * Copyright (C) 2014 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 17package com.android.systemui.recents.misc; 18 19import android.app.ActivityManager; 20import android.app.ActivityManagerNative; 21import android.app.ActivityOptions; 22import android.app.AppGlobals; 23import android.app.IActivityManager; 24import android.app.ITaskStackListener; 25import android.appwidget.AppWidgetHost; 26import android.appwidget.AppWidgetManager; 27import android.appwidget.AppWidgetProviderInfo; 28import android.content.ComponentName; 29import android.content.ContentResolver; 30import android.content.Context; 31import android.content.Intent; 32import android.content.pm.ActivityInfo; 33import android.content.pm.IPackageManager; 34import android.content.pm.PackageManager; 35import android.content.pm.ResolveInfo; 36import android.content.res.Resources; 37import android.graphics.Bitmap; 38import android.graphics.BitmapFactory; 39import android.graphics.Canvas; 40import android.graphics.Color; 41import android.graphics.Paint; 42import android.graphics.Point; 43import android.graphics.PorterDuff; 44import android.graphics.PorterDuffXfermode; 45import android.graphics.Rect; 46import android.graphics.drawable.ColorDrawable; 47import android.graphics.drawable.Drawable; 48import android.os.Bundle; 49import android.os.Handler; 50import android.os.HandlerThread; 51import android.os.ParcelFileDescriptor; 52import android.os.RemoteException; 53import android.os.SystemProperties; 54import android.os.UserHandle; 55import android.provider.Settings; 56import android.util.Log; 57import android.util.MutableBoolean; 58import android.util.Pair; 59import android.util.SparseArray; 60import android.view.Display; 61import android.view.WindowManager; 62import android.view.accessibility.AccessibilityManager; 63 64import com.android.internal.app.AssistUtils; 65import com.android.systemui.Prefs; 66import com.android.systemui.R; 67import com.android.systemui.recents.Constants; 68import com.android.systemui.recents.Recents; 69import com.android.systemui.recents.RecentsConfiguration; 70 71import java.io.IOException; 72import java.util.ArrayList; 73import java.util.Iterator; 74import java.util.List; 75import java.util.Random; 76 77/** 78 * Acts as a shim around the real system services that we need to access data from, and provides 79 * a point of injection when testing UI. 80 */ 81public class SystemServicesProxy { 82 final static String TAG = "SystemServicesProxy"; 83 84 final static BitmapFactory.Options sBitmapOptions; 85 final static HandlerThread sBgThread; 86 87 static { 88 sBgThread = new HandlerThread("Recents-SystemServicesProxy", 89 android.os.Process.THREAD_PRIORITY_BACKGROUND); 90 sBgThread.start(); 91 sBitmapOptions = new BitmapFactory.Options(); 92 sBitmapOptions.inMutable = true; 93 } 94 95 AccessibilityManager mAccm; 96 ActivityManager mAm; 97 IActivityManager mIam; 98 AppWidgetManager mAwm; 99 PackageManager mPm; 100 IPackageManager mIpm; 101 AssistUtils mAssistUtils; 102 WindowManager mWm; 103 Display mDisplay; 104 String mRecentsPackage; 105 ComponentName mAssistComponent; 106 107 Handler mBgThreadHandler; 108 109 Bitmap mDummyIcon; 110 int mDummyThumbnailWidth; 111 int mDummyThumbnailHeight; 112 Paint mBgProtectionPaint; 113 Canvas mBgProtectionCanvas; 114 115 /** Private constructor */ 116 public SystemServicesProxy(Context context) { 117 mAccm = AccessibilityManager.getInstance(context); 118 mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 119 mIam = ActivityManagerNative.getDefault(); 120 mAwm = AppWidgetManager.getInstance(context); 121 mPm = context.getPackageManager(); 122 mIpm = AppGlobals.getPackageManager(); 123 mAssistUtils = new AssistUtils(context); 124 mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 125 mDisplay = mWm.getDefaultDisplay(); 126 mRecentsPackage = context.getPackageName(); 127 mBgThreadHandler = new Handler(sBgThread.getLooper()); 128 129 // Get the dummy thumbnail width/heights 130 Resources res = context.getResources(); 131 int wId = com.android.internal.R.dimen.thumbnail_width; 132 int hId = com.android.internal.R.dimen.thumbnail_height; 133 mDummyThumbnailWidth = res.getDimensionPixelSize(wId); 134 mDummyThumbnailHeight = res.getDimensionPixelSize(hId); 135 136 // Create the protection paints 137 mBgProtectionPaint = new Paint(); 138 mBgProtectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); 139 mBgProtectionPaint.setColor(0xFFffffff); 140 mBgProtectionCanvas = new Canvas(); 141 142 // Resolve the assist intent 143 mAssistComponent = mAssistUtils.getAssistComponentForUser(UserHandle.myUserId()); 144 145 if (Constants.DebugFlags.App.EnableSystemServicesProxy) { 146 // Create a dummy icon 147 mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); 148 mDummyIcon.eraseColor(0xFF999999); 149 } 150 } 151 152 /** Returns a list of the recents tasks */ 153 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId, 154 boolean isTopTaskHome) { 155 if (mAm == null) return null; 156 157 // If we are mocking, then create some recent tasks 158 if (Constants.DebugFlags.App.EnableSystemServicesProxy) { 159 ArrayList<ActivityManager.RecentTaskInfo> tasks = 160 new ArrayList<ActivityManager.RecentTaskInfo>(); 161 int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount); 162 for (int i = 0; i < count; i++) { 163 // Create a dummy component name 164 int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount; 165 ComponentName cn = new ComponentName("com.android.test" + packageIndex, 166 "com.android.test" + i + ".Activity"); 167 String description = "" + i + " - " + 168 Long.toString(Math.abs(new Random().nextLong()), 36); 169 // Create the recent task info 170 ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo(); 171 rti.id = rti.persistentId = i; 172 rti.baseIntent = new Intent(); 173 rti.baseIntent.setComponent(cn); 174 rti.description = description; 175 rti.firstActiveTime = rti.lastActiveTime = i; 176 if (i % 2 == 0) { 177 rti.taskDescription = new ActivityManager.TaskDescription(description, 178 Bitmap.createBitmap(mDummyIcon), 179 0xFF000000 | (0xFFFFFF & new Random().nextInt())); 180 } else { 181 rti.taskDescription = new ActivityManager.TaskDescription(); 182 } 183 tasks.add(rti); 184 } 185 return tasks; 186 } 187 188 // Remove home/recents/excluded tasks 189 int minNumTasksToQuery = 10; 190 int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks); 191 List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery, 192 ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS | 193 ActivityManager.RECENT_IGNORE_UNAVAILABLE | 194 ActivityManager.RECENT_INCLUDE_PROFILES | 195 ActivityManager.RECENT_WITH_EXCLUDED, userId); 196 197 // Break early if we can't get a valid set of tasks 198 if (tasks == null) { 199 return new ArrayList<>(); 200 } 201 202 boolean isFirstValidTask = true; 203 Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator(); 204 while (iter.hasNext()) { 205 ActivityManager.RecentTaskInfo t = iter.next(); 206 207 // NOTE: The order of these checks happens in the expected order of the traversal of the 208 // tasks 209 210 // Check the first non-recents task, include this task even if it is marked as excluded 211 // from recents if we are currently in the app. In other words, only remove excluded 212 // tasks if it is not the first active task. 213 boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) 214 == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; 215 if (isExcluded && (isTopTaskHome || !isFirstValidTask)) { 216 iter.remove(); 217 continue; 218 } 219 isFirstValidTask = false; 220 } 221 222 return tasks.subList(0, Math.min(tasks.size(), numLatestTasks)); 223 } 224 225 /** Returns a list of the running tasks */ 226 private List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) { 227 if (mAm == null) return null; 228 return mAm.getRunningTasks(numTasks); 229 } 230 231 /** Returns the top task. */ 232 public ActivityManager.RunningTaskInfo getTopMostTask() { 233 List<ActivityManager.RunningTaskInfo> tasks = getRunningTasks(1); 234 if (tasks != null && !tasks.isEmpty()) { 235 return tasks.get(0); 236 } 237 return null; 238 } 239 240 /** Returns whether the recents is currently running */ 241 public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask, 242 MutableBoolean isHomeTopMost) { 243 if (topTask != null) { 244 ComponentName topActivity = topTask.topActivity; 245 246 // Check if the front most activity is recents 247 if (topActivity.getPackageName().equals(Recents.sRecentsPackage) && 248 topActivity.getClassName().equals(Recents.sRecentsActivity)) { 249 if (isHomeTopMost != null) { 250 isHomeTopMost.value = false; 251 } 252 return true; 253 } 254 255 if (isHomeTopMost != null) { 256 isHomeTopMost.value = isInHomeStack(topTask.id); 257 } 258 } 259 return false; 260 } 261 262 /** Get the bounds of a task. */ 263 public Rect getTaskBounds(int taskId) { 264 if (mIam == null) return null; 265 266 try { 267 return mIam.getTaskBounds(taskId); 268 } catch (RemoteException e) { 269 e.printStackTrace(); 270 } 271 return null; 272 } 273 274 /** Resize a given task. */ 275 public void resizeTask(int taskId, Rect bounds) { 276 if (mIam == null) return; 277 278 try { 279 if (RecentsConfiguration.getInstance().multiStackEnabled) { 280 // In debug mode, we force all task to be resizeable regardless of the 281 // current app configuration. 282 mIam.setTaskResizeable(taskId, true); 283 } 284 mIam.resizeTask(taskId, bounds); 285 } catch (RemoteException e) { 286 e.printStackTrace(); 287 } 288 } 289 290 /** Returns the focused stack id. */ 291 public int getFocusedStack() { 292 if (mIam == null) return -1; 293 294 try { 295 return mIam.getFocusedStackId(); 296 } catch (RemoteException e) { 297 e.printStackTrace(); 298 return -1; 299 } 300 } 301 302 /** Returns whether the specified task is in the home stack */ 303 public boolean isInHomeStack(int taskId) { 304 if (mAm == null) return false; 305 306 // If we are mocking, then just return false 307 if (Constants.DebugFlags.App.EnableSystemServicesProxy) { 308 return false; 309 } 310 311 return mAm.isInHomeStack(taskId); 312 } 313 314 /** Returns the top task thumbnail for the given task id */ 315 public Bitmap getTaskThumbnail(int taskId) { 316 if (mAm == null) return null; 317 318 // If we are mocking, then just return a dummy thumbnail 319 if (Constants.DebugFlags.App.EnableSystemServicesProxy) { 320 Bitmap thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, mDummyThumbnailHeight, 321 Bitmap.Config.ARGB_8888); 322 thumbnail.eraseColor(0xff333333); 323 return thumbnail; 324 } 325 326 Bitmap thumbnail = SystemServicesProxy.getThumbnail(mAm, taskId); 327 if (thumbnail != null) { 328 thumbnail.setHasAlpha(false); 329 // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top 330 // left pixel, then assume the whole thumbnail is transparent. Generally, proper 331 // screenshots are always composed onto a bitmap that has no alpha. 332 if (Color.alpha(thumbnail.getPixel(0, 0)) == 0) { 333 mBgProtectionCanvas.setBitmap(thumbnail); 334 mBgProtectionCanvas.drawRect(0, 0, thumbnail.getWidth(), thumbnail.getHeight(), 335 mBgProtectionPaint); 336 mBgProtectionCanvas.setBitmap(null); 337 Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()"); 338 } 339 } 340 return thumbnail; 341 } 342 343 /** 344 * Returns a task thumbnail from the activity manager 345 */ 346 public static Bitmap getThumbnail(ActivityManager activityManager, int taskId) { 347 ActivityManager.TaskThumbnail taskThumbnail = activityManager.getTaskThumbnail(taskId); 348 if (taskThumbnail == null) return null; 349 350 Bitmap thumbnail = taskThumbnail.mainThumbnail; 351 ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor; 352 if (thumbnail == null && descriptor != null) { 353 thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(), 354 null, sBitmapOptions); 355 } 356 if (descriptor != null) { 357 try { 358 descriptor.close(); 359 } catch (IOException e) { 360 } 361 } 362 return thumbnail; 363 } 364 365 /** Moves a task to the front with the specified activity options. */ 366 public void moveTaskToFront(int taskId, ActivityOptions opts) { 367 if (mAm == null) return; 368 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; 369 370 if (opts != null) { 371 mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME, 372 opts.toBundle()); 373 } else { 374 mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME); 375 } 376 } 377 378 /** Removes the task */ 379 public void removeTask(final int taskId) { 380 if (mAm == null) return; 381 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; 382 383 // Remove the task. 384 mBgThreadHandler.post(new Runnable() { 385 @Override 386 public void run() { 387 mAm.removeTask(taskId); 388 } 389 }); 390 } 391 392 /** 393 * Returns the activity info for a given component name. 394 * 395 * @param cn The component name of the activity. 396 * @param userId The userId of the user that this is for. 397 */ 398 public ActivityInfo getActivityInfo(ComponentName cn, int userId) { 399 if (mIpm == null) return null; 400 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo(); 401 402 try { 403 return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId); 404 } catch (RemoteException e) { 405 e.printStackTrace(); 406 return null; 407 } 408 } 409 410 /** 411 * Returns the activity info for a given component name. 412 * 413 * @param cn The component name of the activity. 414 */ 415 public ActivityInfo getActivityInfo(ComponentName cn) { 416 if (mPm == null) return null; 417 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo(); 418 419 try { 420 return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA); 421 } catch (PackageManager.NameNotFoundException e) { 422 e.printStackTrace(); 423 return null; 424 } 425 } 426 427 /** Returns the activity label */ 428 public String getActivityLabel(ActivityInfo info) { 429 if (mPm == null) return null; 430 431 // If we are mocking, then return a mock label 432 if (Constants.DebugFlags.App.EnableSystemServicesProxy) { 433 return "Recent Task"; 434 } 435 436 return info.loadLabel(mPm).toString(); 437 } 438 439 /** Returns the application label */ 440 public String getApplicationLabel(Intent baseIntent, int userId) { 441 if (mPm == null) return null; 442 443 // If we are mocking, then return a mock label 444 if (Constants.DebugFlags.App.EnableSystemServicesProxy) { 445 return "Recent Task"; 446 } 447 448 ResolveInfo ri = mPm.resolveActivityAsUser(baseIntent, 0, userId); 449 CharSequence label = (ri != null) ? ri.loadLabel(mPm) : null; 450 return (label != null) ? label.toString() : null; 451 } 452 453 /** Returns the content description for a given task */ 454 public String getContentDescription(Intent baseIntent, int userId, String activityLabel, 455 Resources res) { 456 String applicationLabel = getApplicationLabel(baseIntent, userId); 457 if (applicationLabel == null) { 458 return getBadgedLabel(activityLabel, userId); 459 } 460 String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId); 461 return applicationLabel.equals(activityLabel) ? badgedApplicationLabel 462 : res.getString(R.string.accessibility_recents_task_header, 463 badgedApplicationLabel, activityLabel); 464 } 465 466 /** 467 * Returns the activity icon for the ActivityInfo for a user, badging if 468 * necessary. 469 */ 470 public Drawable getActivityIcon(ActivityInfo info, int userId) { 471 if (mPm == null) return null; 472 473 // If we are mocking, then return a mock label 474 if (Constants.DebugFlags.App.EnableSystemServicesProxy) { 475 return new ColorDrawable(0xFF666666); 476 } 477 478 Drawable icon = info.loadIcon(mPm); 479 return getBadgedIcon(icon, userId); 480 } 481 482 /** 483 * Returns the given icon for a user, badging if necessary. 484 */ 485 public Drawable getBadgedIcon(Drawable icon, int userId) { 486 if (userId != UserHandle.myUserId()) { 487 icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId)); 488 } 489 return icon; 490 } 491 492 /** 493 * Returns the given label for a user, badging if necessary. 494 */ 495 public String getBadgedLabel(String label, int userId) { 496 if (userId != UserHandle.myUserId()) { 497 label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString(); 498 } 499 return label; 500 } 501 502 /** Returns the package name of the home activity. */ 503 public String getHomeActivityPackageName() { 504 if (mPm == null) return null; 505 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null; 506 507 ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>(); 508 ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities); 509 if (defaultHomeActivity != null) { 510 return defaultHomeActivity.getPackageName(); 511 } else if (homeActivities.size() == 1) { 512 ResolveInfo info = homeActivities.get(0); 513 if (info.activityInfo != null) { 514 return info.activityInfo.packageName; 515 } 516 } 517 return null; 518 } 519 520 /** 521 * Returns whether the foreground user is the owner. 522 */ 523 public boolean isForegroundUserSystem() { 524 if (mAm == null) return false; 525 526 return mAm.getCurrentUser() == UserHandle.USER_SYSTEM; 527 } 528 529 /** 530 * Returns the current search widget id. 531 */ 532 public int getSearchAppWidgetId(Context context) { 533 return Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, -1); 534 } 535 536 /** 537 * Returns the current search widget info, binding a new one if necessary. 538 */ 539 public AppWidgetProviderInfo getOrBindSearchAppWidget(Context context, AppWidgetHost host) { 540 int searchWidgetId = Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, -1); 541 AppWidgetProviderInfo searchWidgetInfo = mAwm.getAppWidgetInfo(searchWidgetId); 542 AppWidgetProviderInfo resolvedSearchWidgetInfo = resolveSearchAppWidget(); 543 544 // Return the search widget info if it hasn't changed 545 if (searchWidgetInfo != null && resolvedSearchWidgetInfo != null && 546 searchWidgetInfo.provider.equals(resolvedSearchWidgetInfo.provider)) { 547 if (Prefs.getString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null) == null) { 548 Prefs.putString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, 549 searchWidgetInfo.provider.getPackageName()); 550 } 551 return searchWidgetInfo; 552 } 553 554 // Delete the old widget 555 if (searchWidgetId != -1) { 556 host.deleteAppWidgetId(searchWidgetId); 557 } 558 559 // And rebind a new search widget 560 if (resolvedSearchWidgetInfo != null) { 561 Pair<Integer, AppWidgetProviderInfo> widgetInfo = bindSearchAppWidget(host, 562 resolvedSearchWidgetInfo); 563 if (widgetInfo != null) { 564 Prefs.putInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, widgetInfo.first); 565 Prefs.putString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, 566 widgetInfo.second.provider.getPackageName()); 567 return widgetInfo.second; 568 } 569 } 570 571 // If we fall through here, then there is no resolved search widget, so clear the state 572 Prefs.remove(context, Prefs.Key.SEARCH_APP_WIDGET_ID); 573 Prefs.remove(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE); 574 return null; 575 } 576 577 /** 578 * Returns the first Recents widget from the same package as the global assist activity. 579 */ 580 private AppWidgetProviderInfo resolveSearchAppWidget() { 581 if (mAssistComponent == null) return null; 582 List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders( 583 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX); 584 for (AppWidgetProviderInfo info : widgets) { 585 if (info.provider.getPackageName().equals(mAssistComponent.getPackageName())) { 586 return info; 587 } 588 } 589 return null; 590 } 591 592 /** 593 * Resolves and binds the search app widget that is to appear in the recents. 594 */ 595 private Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host, 596 AppWidgetProviderInfo resolvedSearchWidgetInfo) { 597 if (mAwm == null) return null; 598 if (mAssistComponent == null) return null; 599 600 // Allocate a new widget id and try and bind the app widget (if that fails, then just skip) 601 int searchWidgetId = host.allocateAppWidgetId(); 602 Bundle opts = new Bundle(); 603 opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 604 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX); 605 if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, resolvedSearchWidgetInfo.provider, opts)) { 606 host.deleteAppWidgetId(searchWidgetId); 607 return null; 608 } 609 return new Pair<>(searchWidgetId, resolvedSearchWidgetInfo); 610 } 611 612 /** 613 * Returns whether touch exploration is currently enabled. 614 */ 615 public boolean isTouchExplorationEnabled() { 616 if (mAccm == null) return false; 617 618 return mAccm.isEnabled() && mAccm.isTouchExplorationEnabled(); 619 } 620 621 /** 622 * Returns a global setting. 623 */ 624 public int getGlobalSetting(Context context, String setting) { 625 ContentResolver cr = context.getContentResolver(); 626 return Settings.Global.getInt(cr, setting, 0); 627 } 628 629 /** 630 * Returns a system setting. 631 */ 632 public int getSystemSetting(Context context, String setting) { 633 ContentResolver cr = context.getContentResolver(); 634 return Settings.System.getInt(cr, setting, 0); 635 } 636 637 /** 638 * Returns a system property. 639 */ 640 public String getSystemProperty(String key) { 641 return SystemProperties.get(key); 642 } 643 644 /** 645 * Returns the window rect. 646 */ 647 public Rect getWindowRect() { 648 Rect windowRect = new Rect(); 649 if (mWm == null) return windowRect; 650 651 Point p = new Point(); 652 mWm.getDefaultDisplay().getRealSize(p); 653 windowRect.set(0, 0, p.x, p.y); 654 return windowRect; 655 } 656 657 /** Starts an activity from recents. */ 658 public boolean startActivityFromRecents(Context context, int taskId, String taskName, 659 ActivityOptions options) { 660 if (mIam != null) { 661 try { 662 mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle()); 663 return true; 664 } catch (Exception e) { 665 Console.logError(context, 666 context.getString(R.string.recents_launch_error_message, taskName)); 667 } 668 } 669 return false; 670 } 671 672 /** Starts an in-place animation on the front most application windows. */ 673 public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts) { 674 if (mIam == null) return; 675 676 try { 677 mIam.startInPlaceAnimationOnFrontMostApplication(opts); 678 } catch (Exception e) { 679 e.printStackTrace(); 680 } 681 } 682 683 /** Registers a task stack listener with the system. */ 684 public void registerTaskStackListener(ITaskStackListener listener) { 685 if (mIam == null) return; 686 687 try { 688 mIam.registerTaskStackListener(listener); 689 } catch (Exception e) { 690 e.printStackTrace(); 691 } 692 } 693} 694