diff options
Diffstat (limited to 'core/java')
20 files changed, 391 insertions, 150 deletions
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 27c9c8b..197c1bd 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -231,6 +231,14 @@ public class AccountManagerService } }, intentFilter); + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent); + } + }, userFilter); } private UserAccounts initUser(int userId) { @@ -347,6 +355,28 @@ public class AccountManagerService } } + private void onUserRemoved(Intent intent) { + int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1); + if (userId < 1) return; + + UserAccounts accounts; + synchronized (mUsers) { + accounts = mUsers.get(userId); + mUsers.remove(userId); + } + if (accounts == null) { + File dbFile = new File(getDatabaseName(userId)); + dbFile.delete(); + return; + } + + synchronized (accounts.cacheLock) { + accounts.openHelper.close(); + File dbFile = new File(getDatabaseName(userId)); + dbFile.delete(); + } + } + private List<UserInfo> getAllUsers() { try { return AppGlobals.getPackageManager().getUsers(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index f38540c..0510de1 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1215,6 +1215,18 @@ final class ApplicationPackageManager extends PackageManager { * @hide */ @Override + public UserInfo getUser(int userId) { + try { + return mPM.getUser(userId); + } catch (RemoteException re) { + return null; + } + } + + /** + * @hide + */ + @Override public boolean removeUser(int id) { try { return mPM.removeUser(id); @@ -1228,7 +1240,10 @@ final class ApplicationPackageManager extends PackageManager { */ @Override public void updateUserName(int id, String name) { - // TODO: + try { + mPM.updateUserName(id, name); + } catch (RemoteException re) { + } } /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 1c9ef38..2a9f1af 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2141,6 +2141,30 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED"; + /** + * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USERID that has the + * userid of the new user. + * @hide + */ + public static final String ACTION_USER_ADDED = + "android.intent.action.USER_ADDED"; + + /** + * Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USERID that has + * the userid of the user. + * @hide + */ + public static final String ACTION_USER_REMOVED = + "android.intent.action.USER_REMOVED"; + + /** + * Broadcast sent to the system when the user switches. Carries an extra EXTRA_USERID that has + * the userid of the user to become the current one. + * @hide + */ + public static final String ACTION_USER_SWITCHED = + "android.intent.action.USER_SWITCHED"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). @@ -2682,6 +2706,13 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY"; + /** + * The userid carried with broadcast intents related to addition, removal and switching of users + * - {@link #ACTION_USER_ADDED}, {@link #ACTION_USER_REMOVED} and {@link #ACTION_USER_SWITCHED}. + * @hide + */ + public static final String EXTRA_USERID = + "android.intent.extra.user_id"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). @@ -6483,7 +6514,12 @@ public class Intent implements Parcelable, Cloneable { final String action = getAction(); if (ACTION_SEND.equals(action)) { - final Uri stream = getParcelableExtra(EXTRA_STREAM); + final Uri stream; + try { + stream = getParcelableExtra(EXTRA_STREAM); + } catch (ClassCastException e) { + return; + } if (stream != null) { final ClipData clipData = new ClipData( null, new String[] { getType() }, new ClipData.Item(stream)); @@ -6493,7 +6529,12 @@ public class Intent implements Parcelable, Cloneable { } } else if (ACTION_SEND_MULTIPLE.equals(action)) { - final ArrayList<Uri> streams = getParcelableArrayListExtra(EXTRA_STREAM); + final ArrayList<Uri> streams; + try { + streams = getParcelableArrayListExtra(EXTRA_STREAM); + } catch (ClassCastException e) { + return; + } if (streams != null && streams.size() > 0) { final Uri firstStream = streams.get(0); final ClipData clipData = new ClipData( diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index b7dfe92..06dfe90 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -326,6 +326,13 @@ public class SyncManager implements OnAccountsUpdateListener { } }; + private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent); + } + }; + private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM"; private final SyncHandler mSyncHandler; @@ -420,6 +427,10 @@ public class SyncManager implements OnAccountsUpdateListener { intentFilter.setPriority(100); context.registerReceiver(mShutdownIntentReceiver, intentFilter); + intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(mUserIntentReceiver, intentFilter); + if (!factoryTest) { mNotificationMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); @@ -905,6 +916,18 @@ public class SyncManager implements OnAccountsUpdateListener { } } + private void onUserRemoved(Intent intent) { + int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1); + if (userId == -1) return; + + // Clean up the storage engine database + mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId); + onAccountsUpdated(null); + synchronized (mSyncQueue) { + mSyncQueue.removeUser(userId); + } + } + /** * @hide */ diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java index 06da6fa..c18c86b 100644 --- a/core/java/android/content/SyncQueue.java +++ b/core/java/android/content/SyncQueue.java @@ -117,6 +117,19 @@ public class SyncQueue { return true; } + public void removeUser(int userId) { + ArrayList<SyncOperation> opsToRemove = new ArrayList<SyncOperation>(); + for (SyncOperation op : mOperationsMap.values()) { + if (op.userId == userId) { + opsToRemove.add(op); + } + } + + for (SyncOperation op : opsToRemove) { + remove(op); + } + } + /** * Remove the specified operation if it is in the queue. * @param operation the operation to remove diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index d89d2de..56fd5f8 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -358,6 +358,7 @@ interface IPackageManager { UserInfo createUser(in String name, int flags); boolean removeUser(int userId); + void updateUserName(int userId, String name); void installPackageWithVerification(in Uri packageURI, in IPackageInstallObserver observer, int flags, in String installerPackageName, in Uri verificationURI, @@ -370,6 +371,7 @@ interface IPackageManager { boolean isFirstBoot(); List<UserInfo> getUsers(); + UserInfo getUser(int userId); void setPermissionEnforcement(String permission, int enforcement); int getPermissionEnforcement(String permission); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 55426b8..b06b4a5 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2153,7 +2153,8 @@ public abstract class PackageManager { if ((flags & GET_SIGNATURES) != 0) { packageParser.collectCertificates(pkg, 0); } - return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null); + return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, false, + COMPONENT_ENABLED_STATE_DEFAULT); } /** @@ -2637,10 +2638,17 @@ public abstract class PackageManager { public abstract void updateUserFlags(int id, int flags); /** - * Returns the device identity that verifiers can use to associate their - * scheme to a particular device. This should not be used by anything other - * than a package verifier. - * + * Returns the details for the user specified by userId. + * @param userId the user id of the user + * @return UserInfo for the specified user, or null if no such user exists. + * @hide + */ + public abstract UserInfo getUser(int userId); + + /** + * Returns the device identity that verifiers can use to associate their scheme to a particular + * device. This should not be used by anything other than a package verifier. + * * @return identity that uniquely identifies current device * @hide */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 07d231a..eb8536f 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -230,6 +230,15 @@ public class PackageParser { return name.endsWith(".apk"); } + public static PackageInfo generatePackageInfo(PackageParser.Package p, + int gids[], int flags, long firstInstallTime, long lastUpdateTime, + HashSet<String> grantedPermissions) { + + return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, + grantedPermissions, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, + UserId.getCallingUserId()); + } + /** * Generate and return the {@link PackageInfo} for a parsed package. * @@ -238,15 +247,15 @@ public class PackageParser { */ public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions) { + HashSet<String> grantedPermissions, boolean stopped, int enabledState) { return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, - grantedPermissions, UserId.getCallingUserId()); + grantedPermissions, stopped, enabledState, UserId.getCallingUserId()); } - static PackageInfo generatePackageInfo(PackageParser.Package p, + public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions, int userId) { + HashSet<String> grantedPermissions, boolean stopped, int enabledState, int userId) { PackageInfo pi = new PackageInfo(); pi.packageName = p.packageName; @@ -254,7 +263,7 @@ public class PackageParser { pi.versionName = p.mVersionName; pi.sharedUserId = p.mSharedUserId; pi.sharedUserLabel = p.mSharedUserLabel; - pi.applicationInfo = generateApplicationInfo(p, flags); + pi.applicationInfo = generateApplicationInfo(p, flags, stopped, enabledState, userId); pi.installLocation = p.installLocation; pi.firstInstallTime = firstInstallTime; pi.lastUpdateTime = lastUpdateTime; @@ -290,7 +299,7 @@ public class PackageParser { if (activity.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { pi.activities[j++] = generateActivityInfo(p.activities.get(i), flags, - userId); + stopped, enabledState, userId); } } } @@ -311,7 +320,8 @@ public class PackageParser { final Activity activity = p.receivers.get(i); if (activity.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, userId); + pi.receivers[j++] = generateActivityInfo(p.receivers.get(i), flags, + stopped, enabledState, userId); } } } @@ -332,7 +342,8 @@ public class PackageParser { final Service service = p.services.get(i); if (service.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.services[j++] = generateServiceInfo(p.services.get(i), flags, userId); + pi.services[j++] = generateServiceInfo(p.services.get(i), flags, stopped, + enabledState, userId); } } } @@ -353,7 +364,8 @@ public class PackageParser { final Provider provider = p.providers.get(i); if (provider.info.enabled || (flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { - pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, userId); + pi.providers[j++] = generateProviderInfo(p.providers.get(i), flags, stopped, + enabledState, userId); } } } @@ -3068,11 +3080,11 @@ public class PackageParser { // For use by package manager to keep track of where it has done dexopt. public boolean mDidDexOpt; - // User set enabled state. - public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; - - // Whether the package has been stopped. - public boolean mSetStopped = false; + // // User set enabled state. + // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; + // + // // Whether the package has been stopped. + // public boolean mSetStopped = false; // Additional data supplied by callers. public Object mExtras; @@ -3337,9 +3349,9 @@ public class PackageParser { } } - private static boolean copyNeeded(int flags, Package p, Bundle metaData) { - if (p.mSetEnabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { - boolean enabled = p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + private static boolean copyNeeded(int flags, Package p, int enabledState, Bundle metaData) { + if (enabledState != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + boolean enabled = enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; if (p.applicationInfo.enabled != enabled) { return true; } @@ -3355,30 +3367,32 @@ public class PackageParser { return false; } - public static ApplicationInfo generateApplicationInfo(Package p, int flags) { - return generateApplicationInfo(p, flags, UserId.getCallingUserId()); + public static ApplicationInfo generateApplicationInfo(Package p, int flags, boolean stopped, + int enabledState) { + return generateApplicationInfo(p, flags, stopped, enabledState, UserId.getCallingUserId()); } - public static ApplicationInfo generateApplicationInfo(Package p, int flags, int userId) { + public static ApplicationInfo generateApplicationInfo(Package p, int flags, + boolean stopped, int enabledState, int userId) { if (p == null) return null; - if (!copyNeeded(flags, p, null) && userId == 0) { + if (!copyNeeded(flags, p, enabledState, null) && userId == 0) { // CompatibilityMode is global state. It's safe to modify the instance // of the package. if (!sCompatibilityModeEnabled) { p.applicationInfo.disableCompatibilityMode(); } - if (p.mSetStopped) { + if (stopped) { p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; } else { p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED; } - if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { p.applicationInfo.enabled = true; - } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED - || p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { p.applicationInfo.enabled = false; } - p.applicationInfo.enabledSetting = p.mSetEnabled; + p.applicationInfo.enabledSetting = enabledState; return p.applicationInfo; } @@ -3397,18 +3411,18 @@ public class PackageParser { if (!sCompatibilityModeEnabled) { ai.disableCompatibilityMode(); } - if (p.mSetStopped) { + if (stopped) { p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; } else { p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED; } - if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { ai.enabled = true; - } else if (p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED - || p.mSetEnabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + } else if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { ai.enabled = false; } - ai.enabledSetting = p.mSetEnabled; + ai.enabledSetting = enabledState; return ai; } @@ -3455,15 +3469,16 @@ public class PackageParser { } } - public static final ActivityInfo generateActivityInfo(Activity a, int flags, int userId) { + public static final ActivityInfo generateActivityInfo(Activity a, int flags, boolean stopped, + int enabledState, int userId) { if (a == null) return null; - if (!copyNeeded(flags, a.owner, a.metaData) && userId == 0) { + if (!copyNeeded(flags, a.owner, enabledState, a.metaData) && userId == 0) { return a.info; } // Make shallow copies so we can store the metadata safely ActivityInfo ai = new ActivityInfo(a.info); ai.metaData = a.metaData; - ai.applicationInfo = generateApplicationInfo(a.owner, flags, userId); + ai.applicationInfo = generateApplicationInfo(a.owner, flags, stopped, enabledState, userId); return ai; } @@ -3488,16 +3503,17 @@ public class PackageParser { } } - public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) { + public static final ServiceInfo generateServiceInfo(Service s, int flags, boolean stopped, + int enabledState, int userId) { if (s == null) return null; - if (!copyNeeded(flags, s.owner, s.metaData) + if (!copyNeeded(flags, s.owner, enabledState, s.metaData) && userId == UserId.getUserId(s.info.applicationInfo.uid)) { return s.info; } // Make shallow copies so we can store the metadata safely ServiceInfo si = new ServiceInfo(s.info); si.metaData = s.metaData; - si.applicationInfo = generateApplicationInfo(s.owner, flags, userId); + si.applicationInfo = generateApplicationInfo(s.owner, flags, stopped, enabledState, userId); return si; } @@ -3530,9 +3546,10 @@ public class PackageParser { } } - public static final ProviderInfo generateProviderInfo(Provider p, int flags, int userId) { + public static final ProviderInfo generateProviderInfo(Provider p, int flags, boolean stopped, + int enabledState, int userId) { if (p == null) return null; - if (!copyNeeded(flags, p.owner, p.metaData) + if (!copyNeeded(flags, p.owner, enabledState, p.metaData) && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 || p.info.uriPermissionPatterns == null) && userId == 0) { @@ -3544,7 +3561,7 @@ public class PackageParser { if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { pi.uriPermissionPatterns = null; } - pi.applicationInfo = generateApplicationInfo(p.owner, flags, userId); + pi.applicationInfo = generateApplicationInfo(p.owner, flags, stopped, enabledState, userId); return pi; } diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index a50f09f..e2aafa9 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -35,6 +35,30 @@ public abstract class DisplayList { */ public static final int FLAG_CLIP_CHILDREN = 0x1; + // NOTE: The STATUS_* values *must* match the enum in DrawGlInfo.h + + /** + * Indicates that the display list is done drawing. + * + * @see HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int) + */ + public static final int STATUS_DONE = 0x0; + + /** + * Indicates that the display list needs another drawing pass. + * + * @see HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int) + */ + public static final int STATUS_DRAW = 0x1; + + /** + * Indicates that the display list needs to re-execute its GL functors. + * + * @see HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int) + * @see HardwareCanvas#callDrawGLFunction(int) + */ + public static final int STATUS_INVOKE = 0x2; + /** * Starts recording the display list. All operations performed on the * returned canvas are recorded and stored in this display list. diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java index d9bf918..9639faf 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -79,25 +79,45 @@ public class FocusFinder { switch (direction) { case View.FOCUS_RIGHT: case View.FOCUS_DOWN: + setFocusBottomRight(root); + break; case View.FOCUS_FORWARD: - final int rootTop = root.getScrollY(); - final int rootLeft = root.getScrollX(); - mFocusedRect.set(rootLeft, rootTop, rootLeft, rootTop); + if (focused != null && focused.isLayoutRtl()) { + setFocusTopLeft(root); + } else { + setFocusBottomRight(root); + } break; case View.FOCUS_LEFT: case View.FOCUS_UP: + setFocusTopLeft(root); + break; case View.FOCUS_BACKWARD: - final int rootBottom = root.getScrollY() + root.getHeight(); - final int rootRight = root.getScrollX() + root.getWidth(); - mFocusedRect.set(rootRight, rootBottom, - rootRight, rootBottom); + if (focused != null && focused.isLayoutRtl()) { + setFocusBottomRight(root); + } else { + setFocusTopLeft(root); break; + } } } return findNextFocus(root, focused, mFocusedRect, direction); } + private void setFocusTopLeft(ViewGroup root) { + final int rootBottom = root.getScrollY() + root.getHeight(); + final int rootRight = root.getScrollX() + root.getWidth(); + mFocusedRect.set(rootRight, rootBottom, + rootRight, rootBottom); + } + + private void setFocusBottomRight(ViewGroup root) { + final int rootTop = root.getScrollY(); + final int rootLeft = root.getScrollX(); + mFocusedRect.set(rootLeft, rootTop, rootLeft, rootTop); + } + /** * Find the next view to take focus in root's descendants, searching from * a particular rectangle in root's coordinates. @@ -135,22 +155,10 @@ public class FocusFinder { final int count = focusables.size(); switch (direction) { case View.FOCUS_FORWARD: - if (focused != null) { - int position = focusables.lastIndexOf(focused); - if (position >= 0 && position + 1 < count) { - return focusables.get(position + 1); - } - } - return focusables.get(0); + return getForwardFocusable(focused, focusables, count); case View.FOCUS_BACKWARD: - if (focused != null) { - int position = focusables.indexOf(focused); - if (position > 0) { - return focusables.get(position - 1); - } - } - return focusables.get(count - 1); + return getBackwardFocusable(focused, focusables, count); } return null; } @@ -193,6 +201,38 @@ public class FocusFinder { return closest; } + private View getForwardFocusable(View focused, ArrayList<View> focusables, int count) { + return (focused != null && focused.isLayoutRtl()) ? + getPreviousFocusable(focused, focusables, count) : + getNextFocusable(focused, focusables, count); + } + + private View getNextFocusable(View focused, ArrayList<View> focusables, int count) { + if (focused != null) { + int position = focusables.lastIndexOf(focused); + if (position >= 0 && position + 1 < count) { + return focusables.get(position + 1); + } + } + return focusables.get(0); + } + + private View getBackwardFocusable(View focused, ArrayList<View> focusables, int count) { + return (focused != null && focused.isLayoutRtl()) ? + getNextFocusable(focused, focusables, count) : + getPreviousFocusable(focused, focusables, count); + } + + private View getPreviousFocusable(View focused, ArrayList<View> focusables, int count) { + if (focused != null) { + int position = focusables.indexOf(focused); + if (position > 0) { + return focusables.get(position - 1); + } + } + return focusables.get(count - 1); + } + /** * Is rect1 a better candidate than rect2 for a focus search in a particular * direction from a source rect? This is the core routine that determines diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 1f75e70..0e96742 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -296,11 +296,11 @@ class GLES20Canvas extends HardwareCanvas { /////////////////////////////////////////////////////////////////////////// @Override - public boolean callDrawGLFunction(int drawGLFunction) { + public int callDrawGLFunction(int drawGLFunction) { return nCallDrawGLFunction(mRenderer, drawGLFunction); } - private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction); + private static native int nCallDrawGLFunction(int renderer, int drawGLFunction); /////////////////////////////////////////////////////////////////////////// // Memory @@ -394,13 +394,13 @@ class GLES20Canvas extends HardwareCanvas { private static native void nSetDisplayListName(int displayList, String name); @Override - public boolean drawDisplayList(DisplayList displayList, int width, int height, + public int drawDisplayList(DisplayList displayList, int width, int height, Rect dirty, int flags) { return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty, flags); } - private static native boolean nDrawDisplayList(int renderer, int displayList, + private static native int nDrawDisplayList(int renderer, int displayList, int width, int height, Rect dirty, int flags); @Override diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 838c03c..2636ea2 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -59,11 +59,11 @@ public abstract class HardwareCanvas extends Canvas { * if this method returns true, can be null. * @param flags Optional flags about drawing, see {@link DisplayList} for * the possible flags. - * - * @return True if the content of the display list requires another - * drawing pass (invalidate()), false otherwise + * + * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or + * {@link DisplayList#STATUS_INVOKE} */ - public abstract boolean drawDisplayList(DisplayList displayList, int width, int height, + public abstract int drawDisplayList(DisplayList displayList, int width, int height, Rect dirty, int flags); /** @@ -90,10 +90,12 @@ public abstract class HardwareCanvas extends Canvas { * This function may return true if an invalidation is needed after the call. * * @param drawGLFunction A native function pointer - * @return true if an invalidate is needed after the call, false otherwise + * + * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or + * {@link DisplayList#STATUS_INVOKE} */ - public boolean callDrawGLFunction(int drawGLFunction) { + public int callDrawGLFunction(int drawGLFunction) { // Noop - this is done in the display list recorder subclass - return false; + return DisplayList.STATUS_DONE; } } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index f98cfc0..d40043f 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -966,7 +966,6 @@ public abstract class HardwareRenderer { Log.d("DLProperties", "getDisplayList():\t" + mProfileData[mProfileCurrentFrame]); } - } if (displayList != null) { @@ -975,7 +974,7 @@ public abstract class HardwareRenderer { drawDisplayListStartTime = System.nanoTime(); } - boolean invalidateNeeded = canvas.drawDisplayList(displayList, + int status = canvas.drawDisplayList(displayList, view.getWidth(), view.getHeight(), mRedrawClip, DisplayList.FLAG_CLIP_CHILDREN); @@ -986,19 +985,18 @@ public abstract class HardwareRenderer { if (ViewDebug.DEBUG_LATENCY) { Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took " + - total + "ms, invalidateNeeded=" + - invalidateNeeded + "."); + total + "ms, status=" + status); } } - if (invalidateNeeded) { + if (status != DisplayList.STATUS_DONE) { if (mRedrawClip.isEmpty()) { attachInfo.mViewRootImpl.invalidate(); } else { attachInfo.mViewRootImpl.invalidateChildInParent( null, mRedrawClip); + mRedrawClip.setEmpty(); } - mRedrawClip.setEmpty(); } } else { // Shouldn't reach here diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f769e96..2deeba6 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1459,7 +1459,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * apps. * @hide */ - public static final boolean USE_DISPLAY_LIST_PROPERTIES = false; + public static final boolean USE_DISPLAY_LIST_PROPERTIES = true; /** * Map used to store views' tags. @@ -7401,7 +7401,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal invalidateViewProperty(false, false); if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) { - mDisplayList.setCameraDistance(distance); + mDisplayList.setCameraDistance(-Math.abs(distance) / dpi); } } @@ -10747,16 +10747,25 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal int layerType = ( !(mParent instanceof ViewGroup) || ((ViewGroup)mParent).mDrawLayers) ? getLayerType() : LAYER_TYPE_NONE; - if (!isLayer && layerType == LAYER_TYPE_HARDWARE && USE_DISPLAY_LIST_PROPERTIES) { - final HardwareLayer layer = getHardwareLayer(); - if (layer != null && layer.isValid()) { - canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint); + if (!isLayer && layerType != LAYER_TYPE_NONE && USE_DISPLAY_LIST_PROPERTIES) { + if (layerType == LAYER_TYPE_HARDWARE) { + final HardwareLayer layer = getHardwareLayer(); + if (layer != null && layer.isValid()) { + canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint); + } else { + canvas.saveLayer(0, 0, mRight - mLeft, mBottom - mTop, mLayerPaint, + Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | + Canvas.CLIP_TO_LAYER_SAVE_FLAG); + } + caching = true; } else { - canvas.saveLayer(0, 0, - mRight - mLeft, mBottom - mTop, mLayerPaint, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + buildDrawingCache(true); + Bitmap cache = getDrawingCache(true); + if (cache != null) { + canvas.drawBitmap(cache, 0, 0, mLayerPaint); + caching = true; + } } - caching = true; } else { computeScroll(); @@ -11395,7 +11404,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal mTransformationInfo.mRotation, mTransformationInfo.mRotationX, mTransformationInfo.mRotationY, mTransformationInfo.mScaleX, mTransformationInfo.mScaleY); - displayList.setCameraDistance(getCameraDistance()); + if (mTransformationInfo.mCamera == null) { + mTransformationInfo.mCamera = new Camera(); + mTransformationInfo.matrix3D = new Matrix(); + } + displayList.setCameraDistance(mTransformationInfo.mCamera.getLocationZ()); if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == PIVOT_EXPLICITLY_SET) { displayList.setPivotX(getPivotX()); displayList.setPivotY(getPivotY()); @@ -11489,8 +11502,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } else { switch (layerType) { case LAYER_TYPE_SOFTWARE: - buildDrawingCache(true); - cache = getDrawingCache(true); + if (useDisplayListProperties) { + hasDisplayList = canHaveDisplayList(); + } else { + buildDrawingCache(true); + cache = getDrawingCache(true); + } break; case LAYER_TYPE_HARDWARE: if (useDisplayListProperties) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 6ccac78..30d6ec7 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3906,9 +3906,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager do { if (parent instanceof ViewGroup) { ViewGroup parentVG = (ViewGroup) parent; - parent = parentVG.invalidateChildInParentFast(left, top, dirty); - left = parentVG.mLeft; - top = parentVG.mTop; + if (parentVG.mLayerType != LAYER_TYPE_NONE) { + // Layered parents should be recreated, not just re-issued + parentVG.invalidate(); + parent = null; + } else { + parent = parentVG.invalidateChildInParentFast(left, top, dirty); + left = parentVG.mLeft; + top = parentVG.mTop; + } } else { // Reached the top; this calls into the usual invalidate method in // ViewRootImpl, which schedules a traversal @@ -4664,6 +4670,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public void clearDisappearingChildren() { if (mDisappearingChildren != null) { mDisappearingChildren.clear(); + invalidate(); } } @@ -4775,7 +4782,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager view.mParent = null; } } - mGroupFlags |= FLAG_INVALIDATE_REQUIRED; + invalidate(); } } } diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java index a21d3ee..349113e 100644 --- a/core/java/android/webkit/DebugFlags.java +++ b/core/java/android/webkit/DebugFlags.java @@ -42,12 +42,7 @@ class DebugFlags { public static final boolean WEB_BACK_FORWARD_LIST = false; public static final boolean WEB_SETTINGS = false; public static final boolean WEB_SYNC_MANAGER = false; - public static final boolean WEB_TEXT_VIEW = false; public static final boolean WEB_VIEW = false; public static final boolean WEB_VIEW_CORE = false; - /* - * Set to true to allow the WebTextView to draw on top of the web page in a - * different color with no background so you can see how the two line up. - */ - public static final boolean DRAW_WEBTEXTVIEW = false; + public static final boolean MEASURE_PAGE_SWAP_FPS = false; } diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index ab2db22..5ae2fe0 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -4717,10 +4717,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc queueFull = nativeSetBaseLayer(mNativeClass, layer, invalRegion, showVisualIndicator, isPictureAfterFirstLayout); - if (layer == 0 || isPictureAfterFirstLayout) { - mWebViewCore.resumeWebKitDraw(); - } else if (queueFull) { + if (queueFull) { mWebViewCore.pauseWebKitDraw(); + } else { + mWebViewCore.resumeWebKitDraw(); } if (mHTML5VideoViewProxy != null) { @@ -8615,9 +8615,19 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc void onPageSwapOccurred(boolean notifyAnimationStarted); } + long mLastSwapTime; + double mAverageSwapFps; + /** Called by JNI when pages are swapped (only occurs with hardware * acceleration) */ protected void pageSwapCallback(boolean notifyAnimationStarted) { + if (DebugFlags.MEASURE_PAGE_SWAP_FPS) { + long now = System.currentTimeMillis(); + long diff = now - mLastSwapTime; + mAverageSwapFps = ((1000.0 / diff) + mAverageSwapFps) / 2; + Log.d(LOGTAG, "page swap fps: " + mAverageSwapFps); + mLastSwapTime = now; + } mWebViewCore.resumeWebKitDraw(); if (notifyAnimationStarted) { mWebViewCore.sendMessage(EventHub.NOTIFY_ANIMATION_STARTED); @@ -8679,7 +8689,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" + b.left+","+b.top+","+b.right+","+b.bottom+"}"); } - invalidateContentRect(draw.mInvalRegion.getBounds()); + Rect invalBounds = draw.mInvalRegion.getBounds(); + if (!invalBounds.isEmpty()) { + invalidateContentRect(invalBounds); + } else { + mWebView.invalidate(); + } if (mPictureListener != null) { mPictureListener.onNewPicture(getWebView(), capturePicture()); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index b47f71d..afb2992 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -2271,6 +2271,7 @@ public final class WebViewCore { mFirstLayoutForNonStandardLoad = false; } if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID"); + pauseWebKitDraw(); Message.obtain(mWebViewClassic.mPrivateHandler, WebViewClassic.NEW_PICTURE_MSG_ID, draw).sendToTarget(); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 16d1b94..1f2410b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -7496,7 +7496,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Returns true, only while processing a touch gesture, if the initial * touch down event caused focus to move to the text view and as a result * its selection changed. Only valid while processing the touch gesture - * of interest. + * of interest, in an editable text view. */ public boolean didTouchFocusSelect() { return mEditor != null && getEditor().mTouchFocusSelected; @@ -11683,7 +11683,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener highlight = null; } - if (false /* TEMP patch for bugs 6198276 & 6193544 */ && canHaveDisplayList() && canvas.isHardwareAccelerated()) { + if (canHaveDisplayList() && canvas.isHardwareAccelerated()) { drawHardwareAccelerated(canvas, layout, highlight, cursorOffsetVertical); } else { layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical); @@ -11758,7 +11758,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener hardwareCanvas.onPostDraw(); blockDisplayList.end(); if (USE_DISPLAY_LIST_PROPERTIES) { - blockDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); + blockDisplayList.setLeftTopRightBottom(0, 0, width, height); } } } diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java index da189f1..07496a7 100644 --- a/core/java/com/android/internal/util/StateMachine.java +++ b/core/java/com/android/internal/util/StateMachine.java @@ -44,10 +44,14 @@ import java.util.Vector; * <p>When a state machine is created <code>addState</code> is used to build the * hierarchy and <code>setInitialState</code> is used to identify which of these * is the initial state. After construction the programmer calls <code>start</code> - * which initializes the state machine and calls <code>enter</code> for all of the initial - * state's hierarchy, starting at its eldest parent. For example given the simple - * state machine below after start is called mP1.enter will have been called and - * then mS1.enter.</p> + * which initializes and starts the state machine. The first action the StateMachine + * is to the invoke <code>enter</code> for all of the initial state's hierarchy, + * starting at its eldest parent. The calls to enter will be done in the context + * of the StateMachines Handler not in the context of the call to start and they + * will be invoked before any messages are processed. For example, given the simple + * state machine below mP1.enter will be invoked and then mS1.enter. Finally, + * messages sent to the state machine will be processed by the current state, + * in our simple state machine below that would initially be mS1.processMessage.</p> <code> mP1 / \ @@ -621,8 +625,8 @@ public class StateMachine { /** The debug flag */ private boolean mDbg = false; - /** The quit object */ - private static final Object mQuitObj = new Object(); + /** The SmHandler object, identifies that message is internal */ + private static final Object mSmHandlerObj = new Object(); /** The current message */ private Message mMsg; @@ -726,19 +730,18 @@ public class StateMachine { /** Save the current message */ mMsg = msg; - /** - * Check that construction was completed - */ - if (!mIsConstructionCompleted) { - Log.e(TAG, "The start method not called, ignore msg: " + msg); - return; + if (mIsConstructionCompleted) { + /** Normal path */ + processMsg(msg); + } else if (!mIsConstructionCompleted && + (mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) { + /** Initial one time path. */ + mIsConstructionCompleted = true; + invokeEnterMethods(0); + } else { + throw new RuntimeException("StateMachine.handleMessage: " + + "The start method not called, received msg: " + msg); } - - /** - * Process the message abiding by the hierarchical semantics - * and perform any requested transitions. - */ - processMsg(msg); performTransitions(); if (mDbg) Log.d(TAG, "handleMessage: X"); @@ -852,18 +855,8 @@ public class StateMachine { mTempStateStack = new StateInfo[maxDepth]; setupInitialStateStack(); - /** - * Construction is complete call all enter methods - * starting at the first entry. - */ - mIsConstructionCompleted = true; - mMsg = obtainMessage(SM_INIT_CMD); - invokeEnterMethods(0); - - /** - * Perform any transitions requested by the enter methods - */ - performTransitions(); + /** Sending SM_INIT_CMD message to invoke enter methods asynchronously */ + sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj)); if (mDbg) Log.d(TAG, "completeConstruction: X"); } @@ -1103,14 +1096,14 @@ public class StateMachine { /** @see StateMachine#setInitialState(State) */ private final void setInitialState(State initialState) { - if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName()); + if (mDbg) Log.d(TAG, "setInitialState: initialState=" + initialState.getName()); mInitialState = initialState; } /** @see StateMachine#transitionTo(IState) */ private final void transitionTo(IState destState) { mDestState = (State) destState; - if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName()); + if (mDbg) Log.d(TAG, "transitionTo: destState=" + mDestState.getName()); } /** @see StateMachine#deferMessage(Message) */ @@ -1127,12 +1120,12 @@ public class StateMachine { /** @see StateMachine#deferMessage(Message) */ private final void quit() { if (mDbg) Log.d(TAG, "quit:"); - sendMessage(obtainMessage(SM_QUIT_CMD, mQuitObj)); + sendMessage(obtainMessage(SM_QUIT_CMD, mSmHandlerObj)); } /** @see StateMachine#isQuit(Message) */ private final boolean isQuit(Message msg) { - return (msg.what == SM_QUIT_CMD) && (msg.obj == mQuitObj); + return (msg.what == SM_QUIT_CMD) && (msg.obj == mSmHandlerObj); } /** @see StateMachine#isDbg() */ |
