diff options
Diffstat (limited to 'core/java')
33 files changed, 792 insertions, 219 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 7870031..18503f6 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -42,10 +42,8 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.ManifestDigest; -import android.content.pm.UserInfo; import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; @@ -453,11 +451,17 @@ final class ApplicationPackageManager extends PackageManager { @Override public ResolveInfo resolveActivity(Intent intent, int flags) { + return resolveActivityAsUser(intent, flags, UserHandle.myUserId()); + } + + @Override + public ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId) { try { return mPM.resolveIntent( intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), - flags, UserHandle.myUserId()); + flags, + userId); } catch (RemoteException e) { throw new RuntimeException("Package manager has died", e); } @@ -466,12 +470,12 @@ final class ApplicationPackageManager extends PackageManager { @Override public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) { - return queryIntentActivitiesForUser(intent, flags, UserHandle.myUserId()); + return queryIntentActivitiesAsUser(intent, flags, UserHandle.myUserId()); } /** @hide Same as above but for a specific user */ @Override - public List<ResolveInfo> queryIntentActivitiesForUser(Intent intent, + public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) { try { return mPM.queryIntentActivities( @@ -551,19 +555,24 @@ final class ApplicationPackageManager extends PackageManager { } @Override - public List<ResolveInfo> queryIntentServices(Intent intent, int flags) { + public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) { try { return mPM.queryIntentServices( intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, - UserHandle.myUserId()); + userId); } catch (RemoteException e) { throw new RuntimeException("Package manager has died", e); } } @Override + public List<ResolveInfo> queryIntentServices(Intent intent, int flags) { + return queryIntentServicesAsUser(intent, flags, UserHandle.myUserId()); + } + + @Override public ProviderInfo resolveContentProvider(String name, int flags) { try { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 7896450..17c2c6b 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -951,6 +951,7 @@ public class Notification implements Parcelable private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS); private boolean mUseChronometer; private Style mStyle; + private boolean mShowWhen = true; /** * Constructs a new Builder with the defaults: @@ -982,8 +983,9 @@ public class Notification implements Parcelable /** * Add a timestamp pertaining to the notification (usually the time the event occurred). + * It will be shown in the notification content view by default; use + * {@link Builder#setShowWhen(boolean) setShowWhen} to control this. * - * @see Notification#when */ public Builder setWhen(long when) { @@ -992,6 +994,15 @@ public class Notification implements Parcelable } /** + * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown + * in the content view. + */ + public Builder setShowWhen(boolean show) { + mShowWhen = show; + return this; + } + + /** * Show the {@link Notification#when} field as a stopwatch. * * Instead of presenting <code>when</code> as a timestamp, the notification will show an @@ -1467,7 +1478,7 @@ public class Notification implements Parcelable contentView.setViewPadding(R.id.line1, 0, 0, 0, 0); } - if (mWhen != 0) { + if (mWhen != 0 && mShowWhen) { if (mUseChronometer) { contentView.setViewVisibility(R.id.chronometer, View.VISIBLE); contentView.setLong(R.id.chronometer, "setBase", @@ -1477,7 +1488,10 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.time, View.VISIBLE); contentView.setLong(R.id.time, "setTime", mWhen); } + } else { + contentView.setViewVisibility(R.id.time, View.GONE); } + contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE); contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE); return contentView; diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java index c8062ca..b351811 100644 --- a/core/java/android/app/admin/DeviceAdminInfo.java +++ b/core/java/android/app/admin/DeviceAdminInfo.java @@ -144,7 +144,7 @@ public final class DeviceAdminInfo implements Parcelable { * <p>To control this policy, the device admin must have a "disable-keyguard-widgets" * tag in the "uses-policies" section of its meta-data. */ - public static final int USES_POLICY_DISABLE_KEYGUARD_WIDGETS = 9; + public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9; /** @hide */ public static class PolicyInfo { @@ -194,9 +194,9 @@ public final class DeviceAdminInfo implements Parcelable { com.android.internal.R.string.policylab_disableCamera, com.android.internal.R.string.policydesc_disableCamera)); sPoliciesDisplayOrder.add(new PolicyInfo( - USES_POLICY_DISABLE_KEYGUARD_WIDGETS, "disable-keyguard-widgets", - com.android.internal.R.string.policylab_disableKeyguardWidgets, - com.android.internal.R.string.policydesc_disableKeyguardWidgets)); + USES_POLICY_DISABLE_KEYGUARD_FEATURES, "disable-keyguard-features", + com.android.internal.R.string.policylab_disableKeyguardFeatures, + com.android.internal.R.string.policydesc_disableKeyguardFeatures)); for (int i=0; i<sPoliciesDisplayOrder.size(); i++) { PolicyInfo pi = sPoliciesDisplayOrder.get(i); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 600d02a..6966793 100755 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1215,12 +1215,22 @@ public class DevicePolicyManager { /** * Widgets are enabled in keyguard */ - public static final int KEYGUARD_DISABLE_WIDGETS_NONE = 0; + public static final int KEYGUARD_DISABLE_FEATURES_NONE = 0; /** * Disable all keyguard widgets */ - public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 0x7fffffff; + public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1 << 0; + + /** + * Disable the camera on secure keyguard screens (e.g. PIN/Pattern/Password) + */ + public static final int KEYGUARD_DISABLE_SECURE_CAMERA = 1 << 1; + + /** + * Disable all current and future keyguard customizations + */ + public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff; /** * Called by an application that is administering the device to @@ -1362,22 +1372,22 @@ public class DevicePolicyManager { } /** - * Called by an application that is administering the device to disable adding widgets to - * keyguard. After setting this, keyguard widgets will be disabled according to the state - * provided. + * Called by an application that is administering the device to disable keyguard customizations, + * such as widgets. After setting this, keyguard features will be disabled according to the + * provided feature list. * * <p>The calling device admin must have requested - * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_WIDGETS} to be able to call + * {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES} to be able to call * this method; if it has not, a security exception will be thrown. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param which {@link DevicePolicyManager#KEYGUARD_DISABLE_WIDGETS_ALL} or - * {@link DevicePolicyManager#KEYGUARD_DISABLE_WIDGETS_NONE} (the default). + * {@link DevicePolicyManager#KEYGUARD_DISABLE_FEATURES_NONE} (the default). */ - public void setKeyguardWidgetsDisabled(ComponentName admin, int which) { + public void setKeyguardDisabledFeatures(ComponentName admin, int which) { if (mService != null) { try { - mService.setKeyguardWidgetsDisabled(admin, which, UserHandle.myUserId()); + mService.setKeyguardDisabledFeatures(admin, which, UserHandle.myUserId()); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } @@ -1385,25 +1395,25 @@ public class DevicePolicyManager { } /** - * Determine whether or not widgets have been disabled in keyguard either by the current + * Determine whether or not features have been disabled in keyguard either by the current * admin, if specified, or all admins. * @param admin The name of the admin component to check, or null to check if any admins - * have disabled widgets in keyguard. + * have disabled features in keyguard. */ - public int getKeyguardWidgetsDisabled(ComponentName admin) { - return getKeyguardWidgetsDisabled(admin, UserHandle.myUserId()); + public int getKeyguardDisabledFeatures(ComponentName admin) { + return getKeyguardDisabledFeatures(admin, UserHandle.myUserId()); } /** @hide per-user version */ - public int getKeyguardWidgetsDisabled(ComponentName admin, int userHandle) { + public int getKeyguardDisabledFeatures(ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getKeyguardWidgetsDisabled(admin, userHandle); + return mService.getKeyguardDisabledFeatures(admin, userHandle); } catch (RemoteException e) { Log.w(TAG, "Failed talking with device policy service", e); } } - return KEYGUARD_DISABLE_WIDGETS_NONE; + return KEYGUARD_DISABLE_FEATURES_NONE; } /** diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index bdfb177..e061ab3 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -82,8 +82,8 @@ interface IDevicePolicyManager { void setCameraDisabled(in ComponentName who, boolean disabled, int userHandle); boolean getCameraDisabled(in ComponentName who, int userHandle); - void setKeyguardWidgetsDisabled(in ComponentName who, int which, int userHandle); - int getKeyguardWidgetsDisabled(in ComponentName who, int userHandle); + void setKeyguardDisabledFeatures(in ComponentName who, int which, int userHandle); + int getKeyguardDisabledFeatures(in ComponentName who, int userHandle); void setActiveAdmin(in ComponentName policyReceiver, boolean refreshing, int userHandle); boolean isAdminActive(in ComponentName policyReceiver, int userHandle); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index c86826f..f258f17 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -226,7 +226,12 @@ public class AppWidgetHostView extends FrameLayout { if (jail == null) jail = new ParcelableSparseArray(); - super.dispatchRestoreInstanceState(jail); + try { + super.dispatchRestoreInstanceState(jail); + } catch (Exception e) { + Log.e(TAG, "failed to restoreInstanceState for widget id: " + mAppWidgetId + ", " + + (mInfo == null ? "null" : mInfo.provider), e); + } } /** diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index fd488ae..291726a 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -835,6 +835,14 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device has at least one camera pointing in + * some direction. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device's camera supports flash. */ @SdkConstant(SdkConstantType.FEATURE) @@ -1797,6 +1805,39 @@ public abstract class PackageManager { public abstract ResolveInfo resolveActivity(Intent intent, int flags); /** + * Determine the best action to perform for a given Intent for a given user. This + * is how {@link Intent#resolveActivity} finds an activity if a class has not + * been explicitly specified. + * + * <p><em>Note:</em> if using an implicit Intent (without an explicit ComponentName + * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY} + * only flag. You need to do so to resolve the activity in the same way + * that {@link android.content.Context#startActivity(Intent)} and + * {@link android.content.Intent#resolveActivity(PackageManager) + * Intent.resolveActivity(PackageManager)} do.</p> + * + * @param intent An intent containing all of the desired specification + * (action, data, type, category, and/or component). + * @param flags Additional option flags. The most important is + * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only + * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. + * @param userId The user id. + * + * @return Returns a ResolveInfo containing the final activity intent that + * was determined to be the best action. Returns null if no + * matching activity was found. If multiple matching activities are + * found and there is no default set, returns a ResolveInfo + * containing something else, such as the activity resolver. + * + * @see #MATCH_DEFAULT_ONLY + * @see #GET_INTENT_FILTERS + * @see #GET_RESOLVED_FILTER + * + * @hide + */ + public abstract ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId); + + /** * Retrieve all activities that can be performed for the given intent. * * @param intent The desired intent as per resolveActivity(). @@ -1836,7 +1877,7 @@ public abstract class PackageManager { * @see #GET_RESOLVED_FILTER * @hide */ - public abstract List<ResolveInfo> queryIntentActivitiesForUser(Intent intent, + public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId); @@ -1944,6 +1985,27 @@ public abstract class PackageManager { int flags); /** + * Retrieve all services that can match the given intent for a given user. + * + * @param intent The desired intent as per resolveService(). + * @param flags Additional option flags. + * @param userId The user id. + * + * @return A List<ResolveInfo> containing one entry for each matching + * ServiceInfo. These are ordered from best to worst match -- that + * is, the first item in the list is what is returned by + * resolveService(). If there are no matching services, an empty + * list is returned. + * + * @see #GET_INTENT_FILTERS + * @see #GET_RESOLVED_FILTER + * + * @hide + */ + public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent, + int flags, int userId); + + /** * Find a single content provider by its base path name. * * @param name The name of the provider to find. diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 7b3a8af..375d788 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -233,6 +233,21 @@ public class Camera { * @see Parameters#setJpegThumbnailSize(int, int) */ public int orientation; + + /** + * <p>Whether the shutter sound can be disabled.</p> + * + * <p>On some devices, the camera shutter sound cannot be turned off + * through {@link #enableShutterSound enableShutterSound}. This field + * can be used to determine whether a call to disable the shutter sound + * will succeed.</p> + * + * <p>If this field is set to true, then a call of + * {@code enableShutterSound(false)} will be successful. If set to + * false, then that call will fail, and the shutter sound will be played + * when {@link Camera#takePicture takePicture} is called.</p> + */ + public boolean canDisableShutterSound; }; /** diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 2a5c1aa..96c96d7 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -72,6 +72,15 @@ public class UserManager { } } + /** + * Used to determine whether the user making this call is subject to + * teleportations. + * @return whether the user making this call is a goat + */ + public boolean isUserAGoat() { + return false; + } + /** * Returns the UserInfo object describing a specific user. * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index cfa5479..0e7ab52 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -122,6 +122,38 @@ public final class MediaStore { "android.media.action.MEDIA_PLAY_FROM_SEARCH"; /** + * An intent to perform a search for readable media and automatically play content from the + * result when possible. This can be fired, for example, by the result of a voice recognition + * command to read a book or magazine. + * <p> + * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string that can + * contain any type of unstructured text search, like the name of a book or magazine, an author + * a genre, a publisher, or any combination of these. + * <p> + * Because this intent includes an open-ended unstructured search string, it makes the most + * sense for apps that can support large-scale search of text media, such as services connected + * to an online database of books and/or magazines which can be read on the device. + */ + public static final String INTENT_ACTION_TEXT_OPEN_FROM_SEARCH = + "android.media.action.TEXT_OPEN_FROM_SEARCH"; + + /** + * An intent to perform a search for video media and automatically play content from the + * result when possible. This can be fired, for example, by the result of a voice recognition + * command to play movies. + * <p> + * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string that can + * contain any type of unstructured video search, like the name of a movie, one or more actors, + * a genre, or any combination of these. + * <p> + * Because this intent includes an open-ended unstructured search string, it makes the most + * sense for apps that can support large-scale search of video, such as services connected to an + * online database of videos which can be streamed and played on the device. + */ + public static final String INTENT_ACTION_VIDEO_PLAY_FROM_SEARCH = + "android.media.action.VIDEO_PLAY_FROM_SEARCH"; + + /** * The name of the Intent-extra used to define the artist */ public static final String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist"; @@ -223,7 +255,6 @@ public final class MediaStore { * * @see #ACTION_IMAGE_CAPTURE * @see #EXTRA_OUTPUT - * @hide */ public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 66738a1..7864302 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5334,26 +5334,35 @@ public final class Settings { * review apps prior to installation. * 1 = request apps to be verified prior to installation, if a verifier exists. * 0 = do not verify apps before installation - * {@hide} + * @hide */ public static final String PACKAGE_VERIFIER_ENABLE = "package_verifier_enable"; /** Timeout for package verification. - * {@hide} */ + * @hide */ public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout"; /** Default response code for package verification. - * {@hide} */ + * @hide */ public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response"; - /** Show package verification setting in the Settings app. + /** + * Show package verification setting in the Settings app. * 1 = show (default) * 0 = hide - * {@hide} + * @hide */ public static final String PACKAGE_VERIFIER_SETTING_VISIBLE = "verifier_setting_visible"; /** + * Run package verificaiton on apps installed through ADB/ADT/USB + * 1 = perform package verification on ADB installs (default) + * 0 = bypass package verification on ADB installs + * @hide + */ + public static final String PACKAGE_VERIFIER_INCLUDE_ADB = "verifier_verify_adb_installs"; + + /** * The interval in milliseconds at which to check packet counts on the * mobile data interface when screen is on, to detect possible data * connection problems. diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java index 4a23d39..dedfb0c 100644 --- a/core/java/android/service/dreams/Dream.java +++ b/core/java/android/service/dreams/Dream.java @@ -44,22 +44,47 @@ import com.android.internal.policy.PolicyManager; * <p>Dreams are interactive screensavers launched when a charging device is idle, or docked in a * desk dock. Dreams provide another modality for apps to express themselves, tailored for * an exhibition/lean-back experience.</p> + * + * <p>Dreams should be declared in the manifest as follows:</p> + * <pre> + * {@code + * <service + * android:name=".MyDream" + * android:exported="true" + * android:icon="@drawable/my_icon" + * android:label="@string/my_dream_label" > + * + * <intent-filter> + * <action android:name="android.intent.action.MAIN" /> + * <category android:name="android.intent.category.DREAM" /> + * </intent-filter> + * + * <!-- Point to configuration activity for this dream (optional) --> + * <meta-data + * android:name="android.service.dreams.config_activity" + * android:value="com.example.mypackage/com.example.mypackage.MyDreamSettingsActivity" /> + * </service> + * } + * </pre> */ public class Dream extends Service implements Window.Callback { private final static boolean DEBUG = true; private final String TAG = Dream.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; /** - * The {@link Intent} that must be declared as handled by the service. - * To be supported, the service must also require the - * {@link android.Manifest.permission#BIND_WALLPAPER} permission so - * that other applications can not abuse it. + * Used with {@link Intent#ACTION_MAIN} to declare the necessary intent-filter for a dream. + * + * @see Dream */ - @SdkConstant(SdkConstantType.SERVICE_ACTION) - public static final String SERVICE_INTERFACE = - "android.service.dreams.Dream"; + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_DREAM = + "android.intent.category.DREAM"; - /** Service meta-data key for declaring an optional configuration activity. */ + /** + * Service meta-data key for declaring an optional configuration activity. + * + * @see Dream + * */ public static final String METADATA_NAME_CONFIG_ACTIVITY = "android.service.dreams.config_activity"; @@ -86,10 +111,14 @@ public class Dream extends Service implements Window.Callback { private Window mWindow; private WindowManager mWindowManager; private IDreamManager mSandman; - private boolean mInteractive; + private boolean mInteractive = false; + private boolean mLowProfile = true; + private boolean mFullscreen = false; + private boolean mScreenBright = false; private boolean mFinished; // begin Window.Callback methods + /** {@inheritDoc} */ @Override public boolean dispatchKeyEvent(KeyEvent event) { // TODO: create more flexible version of mInteractive that allows use of KEYCODE_BACK @@ -105,6 +134,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchKeyEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchKeyShortcutEvent(KeyEvent event) { if (!mInteractive) { @@ -115,6 +145,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchKeyShortcutEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchTouchEvent(MotionEvent event) { // TODO: create more flexible version of mInteractive that allows clicks @@ -127,6 +158,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchTouchEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchTrackballEvent(MotionEvent event) { if (!mInteractive) { @@ -137,6 +169,7 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchTrackballEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchGenericMotionEvent(MotionEvent event) { if (!mInteractive) { @@ -147,86 +180,112 @@ public class Dream extends Service implements Window.Callback { return mWindow.superDispatchGenericMotionEvent(event); } + /** {@inheritDoc} */ @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { return false; } + /** {@inheritDoc} */ @Override public View onCreatePanelView(int featureId) { return null; } + /** {@inheritDoc} */ @Override public boolean onCreatePanelMenu(int featureId, Menu menu) { return false; } + /** {@inheritDoc} */ @Override public boolean onPreparePanel(int featureId, View view, Menu menu) { return false; } + /** {@inheritDoc} */ @Override public boolean onMenuOpened(int featureId, Menu menu) { return false; } + /** {@inheritDoc} */ @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { return false; } + /** {@inheritDoc} */ @Override public void onWindowAttributesChanged(LayoutParams attrs) { - } + /** {@inheritDoc} */ @Override public void onContentChanged() { - } + /** {@inheritDoc} */ @Override public void onWindowFocusChanged(boolean hasFocus) { - } + /** {@inheritDoc} */ @Override public void onAttachedToWindow() { } + /** {@inheritDoc} */ @Override public void onDetachedFromWindow() { } + /** {@inheritDoc} */ @Override public void onPanelClosed(int featureId, Menu menu) { } + /** {@inheritDoc} */ @Override public boolean onSearchRequested() { return false; } + /** {@inheritDoc} */ @Override public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) { return null; } + /** {@inheritDoc} */ @Override public void onActionModeStarted(ActionMode mode) { } + /** {@inheritDoc} */ @Override public void onActionModeFinished(ActionMode mode) { } // end Window.Callback methods + // begin public api + /** + * Retrieves the current {@link android.view.WindowManager} for the dream. + * Behaves similarly to {@link android.app.Activity#getWindowManager()}. + * + * @return The current window manager, or null if the dream is not started. + */ public WindowManager getWindowManager() { return mWindowManager; } + /** + * Retrieves the current {@link android.view.Window} for the dream. + * Behaves similarly to {@link android.app.Activity#getWindow()}. + * + * @return The current window, or null if the dream is not started. + */ public Window getWindow() { return mWindow; } @@ -235,6 +294,8 @@ public class Dream extends Service implements Window.Callback { * Inflates a layout resource and set it to be the content view for this Dream. * Behaves similarly to {@link android.app.Activity#setContentView(int)}. * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * * @param layoutResID Resource ID to be inflated. * * @see #setContentView(android.view.View) @@ -248,7 +309,8 @@ public class Dream extends Service implements Window.Callback { * Sets a view to be the content view for this Dream. * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)}, * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view. - * + * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> * @param view The desired content to display. * * @see #setContentView(int) @@ -263,6 +325,8 @@ public class Dream extends Service implements Window.Callback { * Behaves similarly to * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}. * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * * @param view The desired content to display. * @param params Layout parameters for the view. * @@ -275,7 +339,9 @@ public class Dream extends Service implements Window.Callback { /** * Adds a view to the Dream's window, leaving other content views in place. - * + * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * * @param view The desired content to display. * @param params Layout parameters for the view. */ @@ -284,6 +350,25 @@ public class Dream extends Service implements Window.Callback { } /** + * Finds a view that was identified by the id attribute from the XML that + * was processed in {@link #onCreate}. + * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * + * @return The view if found or null otherwise. + */ + public View findViewById(int id) { + return getWindow().findViewById(id); + } + + /** FIXME remove once platform dreams are updated */ + @Deprecated + protected void lightsOut() { + setLowProfile(true); + setFullscreen(true); + } + + /** * Marks this dream as interactive to receive input events. * * <p>Non-interactive dreams (default) will dismiss on the first input event.</p> @@ -297,36 +382,79 @@ public class Dream extends Service implements Window.Callback { } /** - * Returns whether or not this dream is interactive. + * Returns whether or not this dream is interactive. Defaults to false. + * + * @see #setInteractive(boolean) */ public boolean isInteractive() { return mInteractive; } - /** Convenience method for setting View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. */ - protected void lightsOut() { - // turn the lights down low - final View v = mWindow.getDecorView(); - if (v != null) { - v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE - | View.SYSTEM_UI_FLAG_FULLSCREEN); - } + /** + * Sets View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. + * + * @param lowProfile True to set View.SYSTEM_UI_FLAG_LOW_PROFILE + */ + public void setLowProfile(boolean lowProfile) { + mLowProfile = lowProfile; + int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE; + applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag); } /** - * Finds a view that was identified by the id attribute from the XML that - * was processed in {@link #onCreate}. + * Returns whether or not this dream is in low profile mode. Defaults to true. * - * @return The view if found or null otherwise. + * @see #setLowProfile(boolean) */ - public View findViewById(int id) { - return getWindow().findViewById(id); + public boolean isLowProfile() { + return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_LOW_PROFILE, mLowProfile); + } + + /** + * Sets View.SYSTEM_UI_FLAG_FULLSCREEN on the content view. + * + * @param fullscreen True to set View.SYSTEM_UI_FLAG_FULLSCREEN + */ + public void setFullscreen(boolean fullscreen) { + mFullscreen = fullscreen; + int flag = View.SYSTEM_UI_FLAG_FULLSCREEN; + applySystemUiVisibilityFlags(mFullscreen ? flag : 0, flag); + } + + /** + * Returns whether or not this dream is in fullscreen mode. Defaults to false. + * + * @see #setFullscreen(boolean) + */ + public boolean isFullscreen() { + return getSystemUiVisibilityFlagValue(View.SYSTEM_UI_FLAG_FULLSCREEN, mFullscreen); + } + + /** + * Marks this dream as keeping the screen bright while dreaming. + * + * @param screenBright True to keep the screen bright while dreaming. + */ + public void setScreenBright(boolean screenBright) { + mScreenBright = screenBright; + int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; + applyWindowFlags(mScreenBright ? flag : 0, flag); + } + + /** + * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false, + * allowing the screen to dim if necessary. + * + * @see #setScreenBright(boolean) + */ + public boolean isScreenBright() { + return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright); } /** * Called when this Dream is constructed. Place your initialization here. * - * Subclasses must call through to the superclass implementation. + * <p>Subclasses must call through to the superclass implementation.</p> */ @Override public void onCreate() { @@ -336,23 +464,51 @@ public class Dream extends Service implements Window.Callback { } /** - * Called when this Dream is started. + * Called when this Dream is started. The window is created and visible at this point. */ public void onStart() { + if (DEBUG) Slog.v(TAG, "onStart()"); // hook for subclasses - Slog.v(TAG, "called Dream.onStart()"); } - private void loadSandman() { - mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams")); + /** {@inheritDoc} */ + @Override + public final IBinder onBind(Intent intent) { + if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); + return new DreamServiceWrapper(); } /** - * Creates a new dream window, attaches the current content view, and shows it. - * - * @param windowToken Binder to attach to the window to allow access to the correct window type. - * @hide + * Stops the dream, detaches from the window, and wakes up. + * + * <p>Subclasses must call through to the superclass implementation.</p> + * + * <p>After this method is called, the service will be stopped.</p> */ + public void finish() { + if (DEBUG) Slog.v(TAG, "finish()"); + finishInternal(); + } + + /** {@inheritDoc} */ + @Override + public void onDestroy() { + if (DEBUG) Slog.v(TAG, "onDestroy()"); + super.onDestroy(); + + if (DEBUG) Slog.v(TAG, "Removing window"); + try { + mWindowManager.removeView(mWindow.getDecorView()); + } catch (Throwable t) { + Slog.w(TAG, "Crashed removing window view", t); + } + } + // end public api + + private void loadSandman() { + mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams")); + } + private final void attach(IBinder windowToken) { if (DEBUG) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId()); @@ -375,7 +531,8 @@ public class Dream extends Service implements Window.Callback { lp.windowAnimations = com.android.internal.R.style.Animation_Dream; lp.flags |= ( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD - | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0) ); mWindow.setAttributes(lp); @@ -389,8 +546,11 @@ public class Dream extends Service implements Window.Callback { @Override public void run() { if (DEBUG) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId()); - try { + applySystemUiVisibilityFlags( + (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0) + | (mFullscreen ? View.SYSTEM_UI_FLAG_FULLSCREEN : 0), + View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN); getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes()); } catch (Throwable t) { Slog.w("Crashed adding window view", t); @@ -424,18 +584,6 @@ public class Dream extends Service implements Window.Callback { } } - /** - * Stops the dream, detaches from the window, and wakes up. - * - * Subclasses must call through to the superclass implementation. - * - * <p>After this method is called, the service will be stopped.</p> - */ - public void finish() { - if (DEBUG) Slog.v(TAG, "finish()"); - finishInternal(); - } - private void finishInternal() { if (DEBUG) Slog.v(TAG, "finishInternal() mFinished = " + mFinished); if (mFinished) return; @@ -454,23 +602,33 @@ public class Dream extends Service implements Window.Callback { } } - @Override - public void onDestroy() { - if (DEBUG) Slog.v(TAG, "onDestroy()"); - super.onDestroy(); + private boolean getWindowFlagValue(int flag, boolean defaultValue) { + return mWindow == null ? defaultValue : (mWindow.getAttributes().flags & flag) != 0; + } - if (DEBUG) Slog.v(TAG, "Removing window"); - try { - mWindowManager.removeView(mWindow.getDecorView()); - } catch (Throwable t) { - Slog.w(TAG, "Crashed removing window view", t); + private void applyWindowFlags(int flags, int mask) { + if (mWindow != null) { + WindowManager.LayoutParams lp = mWindow.getAttributes(); + lp.flags = applyFlags(lp.flags, flags, mask); + mWindow.setAttributes(lp); + mWindowManager.updateViewLayout(mWindow.getDecorView(), lp); } } - @Override - public final IBinder onBind(Intent intent) { - if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); - return new DreamServiceWrapper(); + private boolean getSystemUiVisibilityFlagValue(int flag, boolean defaultValue) { + View v = mWindow == null ? null : mWindow.getDecorView(); + return v == null ? defaultValue : (v.getSystemUiVisibility() & flag) != 0; + } + + private void applySystemUiVisibilityFlags(int flags, int mask) { + View v = mWindow == null ? null : mWindow.getDecorView(); + if (v != null) { + v.setSystemUiVisibility(applyFlags(v.getSystemUiVisibility(), flags, mask)); + } + } + + private int applyFlags(int oldFlags, int flags, int mask) { + return (oldFlags&~mask) | (flags&mask); } private class DreamServiceWrapper extends IDreamService.Stub { diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 6848606..b661748 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -16,7 +16,6 @@ package android.view; -import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerGlobal; import android.os.Handler; import android.os.Looper; @@ -685,7 +684,24 @@ public final class Choreographer { } @Override - public void onVsync(long timestampNanos, int frame) { + public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { + // Ignore vsync from secondary display. + // This can be problematic because the call to scheduleVsync() is a one-shot. + // We need to ensure that we will still receive the vsync from the primary + // display which is the one we really care about. Ideally we should schedule + // vsync for a particular display. + // At this time Surface Flinger won't send us vsyncs for secondary displays + // but that could change in the future so let's log a message to help us remember + // that we need to fix this. + if (builtInDisplayId != Surface.BUILT_IN_DISPLAY_ID_MAIN) { + Log.d(TAG, "Received vsync from secondary display, but we don't support " + + "this case yet. Choreographer needs a way to explicitly request " + + "vsync for a specific display to ensure it doesn't lose track " + + "of its scheduled vsync."); + scheduleVsync(); + return; + } + // Post the vsync event to the Handler. // The idea is to prevent incoming vsync events from completely starving // the message queue. If there are no messages in the queue with timestamps diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 0b138c2..a919ffc 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -101,9 +101,23 @@ public abstract class DisplayEventReceiver { * * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()} * timebase. + * @param builtInDisplayId The surface flinger built-in display id such as + * {@link Surface#BUILT_IN_DISPLAY_ID_MAIN}. * @param frame The frame number. Increases by one for each vertical sync interval. */ - public void onVsync(long timestampNanos, int frame) { + public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { + } + + /** + * Called when a display hotplug event is received. + * + * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()} + * timebase. + * @param builtInDisplayId The surface flinger built-in display id such as + * {@link Surface#BUILT_IN_DISPLAY_ID_HDMI}. + * @param connected True if the display is connected, false if it disconnected. + */ + public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { } /** @@ -121,7 +135,13 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") - private void dispatchVsync(long timestampNanos, int frame) { - onVsync(timestampNanos, frame); + private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) { + onVsync(timestampNanos, builtInDisplayId, frame); + } + + // Called from native code. + @SuppressWarnings("unused") + private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) { + onHotplug(timestampNanos, builtInDisplayId, connected); } } diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 032ff7b..c703aaf 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -147,7 +147,17 @@ class GLES20Canvas extends HardwareCanvas { /////////////////////////////////////////////////////////////////////////// // Hardware layers /////////////////////////////////////////////////////////////////////////// - + + @Override + void pushLayerUpdate(HardwareLayer layer) { + nPushLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer); + } + + @Override + void clearLayerUpdates() { + nClearLayerUpdates(mRenderer); + } + static native int nCreateTextureLayer(boolean opaque, int[] layerInfo); static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo); static native boolean nResizeLayer(int layerId, int width, int height, int[] layerInfo); @@ -163,6 +173,9 @@ class GLES20Canvas extends HardwareCanvas { int left, int top, int right, int bottom); static native boolean nCopyLayer(int layerId, int bitmap); + private static native void nClearLayerUpdates(int renderer); + private static native void nPushLayerUpdate(int renderer, int layer); + /////////////////////////////////////////////////////////////////////////// // Canvas management /////////////////////////////////////////////////////////////////////////// diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java index fcfc8e1..44d4719 100644 --- a/core/java/android/view/GLES20RenderLayer.java +++ b/core/java/android/view/GLES20RenderLayer.java @@ -110,7 +110,7 @@ class GLES20RenderLayer extends GLES20Layer { } @Override - void redraw(DisplayList displayList, Rect dirtyRect) { + void redrawLater(DisplayList displayList, Rect dirtyRect) { GLES20Canvas.nUpdateRenderLayer(mLayer, mCanvas.getRenderer(), ((GLES20DisplayList) displayList).getNativeDisplayList(), dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom); diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java index b0ee2aa..797c734 100644 --- a/core/java/android/view/GLES20TextureLayer.java +++ b/core/java/android/view/GLES20TextureLayer.java @@ -98,6 +98,6 @@ class GLES20TextureLayer extends GLES20Layer { } @Override - void redraw(DisplayList displayList, Rect dirtyRect) { + void redrawLater(DisplayList displayList, Rect dirtyRect) { } } diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index 777552a..eeae3ed 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -132,4 +132,20 @@ public abstract class HardwareCanvas extends Canvas { * @see #detachFunctor(int) */ abstract void attachFunctor(int functor); + + /** + * Indicates that the specified layer must be updated as soon as possible. + * + * @param layer The layer to update + * + * @see #clearLayerUpdates() + */ + abstract void pushLayerUpdate(HardwareLayer layer); + + /** + * Removes all enqueued layer updates. + * + * @see #pushLayerUpdate(HardwareLayer) + */ + abstract void clearLayerUpdates(); } diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index d798e73..d6868ca 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -203,5 +203,5 @@ abstract class HardwareLayer { * execute in this layer * @param dirtyRect The dirty region of the layer that needs to be redrawn */ - abstract void redraw(DisplayList displayList, Rect dirtyRect); + abstract void redrawLater(DisplayList displayList, Rect dirtyRect); } diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index ef5dc56..bafab21 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -149,6 +149,17 @@ public abstract class HardwareRenderer { "debug.hwui.show_layers_updates"; /** + * Turn on to show overdraw level. + * + * Possible values: + * "true", to enable overdraw debugging + * "false", to disable overdraw debugging + * + * @hide + */ + public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw"; + + /** * A process can set this flag to false to prevent the use of hardware * rendering. * @@ -370,6 +381,14 @@ public abstract class HardwareRenderer { private static native void nDisableVsync(); /** + * Indicates that the specified hardware layer needs to be updated + * as soon as possible. + * + * @param layer The hardware layer that needs an update + */ + abstract void pushLayerUpdate(HardwareLayer layer); + + /** * Interface used to receive callbacks whenever a view is drawn by * a hardware renderer instance. */ @@ -641,6 +660,7 @@ public abstract class HardwareRenderer { int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; final boolean mDebugDirtyRegions; + final boolean mShowOverdraw; final int mGlVersion; final boolean mTranslucent; @@ -690,6 +710,9 @@ public abstract class HardwareRenderer { if (mDebugDirtyRegions) { Log.d(LOG_TAG, "Debugging dirty regions"); } + + mShowOverdraw = SystemProperties.getBoolean( + HardwareRenderer.DEBUG_SHOW_OVERDRAW_PROPERTY, false); } @Override @@ -1154,8 +1177,9 @@ public abstract class HardwareRenderer { getDisplayListStartTime = System.nanoTime(); } - DisplayList displayList; + canvas.clearLayerUpdates(); + DisplayList displayList; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); try { displayList = view.getDisplayList(); @@ -1405,7 +1429,8 @@ public abstract class HardwareRenderer { EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, - EGL_STENCIL_SIZE, GLES20Canvas.getStencilSize(), + // TODO: Find a better way to choose the stencil size + EGL_STENCIL_SIZE, mShowOverdraw ? GLES20Canvas.getStencilSize() : 0, EGL_SURFACE_TYPE, EGL_WINDOW_BIT | (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0), EGL_NONE @@ -1452,6 +1477,11 @@ public abstract class HardwareRenderer { } @Override + void pushLayerUpdate(HardwareLayer layer) { + mGlCanvas.pushLayerUpdate(layer); + } + + @Override public DisplayList createDisplayList(String name) { return new GLES20DisplayList(name); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 13de538..31bbc6a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -12286,9 +12286,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (!mHardwareLayer.isValid()) { return null; } + mHardwareLayer.setLayerPaint(mLayerPaint); + mHardwareLayer.redrawLater(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect); + ViewRootImpl viewRoot = getViewRootImpl(); + if (viewRoot != null) viewRoot.pushHardwareLayerUpdate(mHardwareLayer); - mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect); mLocalDirtyRect.setEmpty(); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 27fd374..6bb8697 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -653,6 +653,12 @@ public final class ViewRootImpl implements ViewParent, } } + void pushHardwareLayerUpdate(HardwareLayer layer) { + if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { + mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer); + } + } + public boolean attachFunctor(int functor) { //noinspection SimplifiableIfStatement if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 77fd12a..732699b 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -27,6 +27,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.UserHandle; import android.util.Log; import android.view.IWindow; import android.view.View; @@ -79,6 +80,8 @@ public final class AccessibilityManager { final IAccessibilityManager mService; + final int mUserId; + final Handler mHandler; boolean mIsEnabled; @@ -129,35 +132,72 @@ public final class AccessibilityManager { } /** + * Creates the singleton AccessibilityManager to be shared across users. This + * has to be called before the local AccessibilityManager is created to ensure + * it registers itself in the system correctly. + * <p> + * Note: Calling this method requires INTERACT_ACROSS_USERS_FULL or + * INTERACT_ACROSS_USERS permission. + * </p> + * @param context Context in which this manager operates. + * @throws IllegalStateException if not called before the local + * AccessibilityManager is instantiated. + * + * @hide + */ + public static void createAsSharedAcrossUsers(Context context) { + synchronized (sInstanceSync) { + if (sInstance != null) { + throw new IllegalStateException("AccessibilityManager already created."); + } + createSingletonInstance(context, UserHandle.USER_CURRENT); + } + } + + /** * Get an AccessibilityManager instance (create one if necessary). * + * @param context Context in which this manager operates. + * * @hide */ public static AccessibilityManager getInstance(Context context) { synchronized (sInstanceSync) { if (sInstance == null) { - IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE); - IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder); - sInstance = new AccessibilityManager(context, service); + createSingletonInstance(context, UserHandle.myUserId()); } } return sInstance; } /** + * Creates the singleton instance. + * + * @param context Context in which this manager operates. + * @param userId The user id under which to operate. + */ + private static void createSingletonInstance(Context context, int userId) { + IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE); + IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder); + sInstance = new AccessibilityManager(context, service, userId); + } + + /** * Create an instance. * * @param context A {@link Context}. * @param service An interface to the backing service. + * @param userId User id under which to run. * * @hide */ - public AccessibilityManager(Context context, IAccessibilityManager service) { + public AccessibilityManager(Context context, IAccessibilityManager service, int userId) { mHandler = new MyHandler(context.getMainLooper()); mService = service; + mUserId = userId; try { - final int stateFlags = mService.addClient(mClient); + final int stateFlags = mService.addClient(mClient, userId); setState(stateFlags); } catch (RemoteException re) { Log.e(LOG_TAG, "AccessibilityManagerService is dead", re); @@ -222,7 +262,7 @@ public final class AccessibilityManager { // client using it is called through Binder from another process. Example: MMS // app adds a SMS notification and the NotificationManagerService calls this method long identityToken = Binder.clearCallingIdentity(); - doRecycle = mService.sendAccessibilityEvent(event); + doRecycle = mService.sendAccessibilityEvent(event, mUserId); Binder.restoreCallingIdentity(identityToken); if (DEBUG) { Log.i(LOG_TAG, event + " sent"); @@ -244,7 +284,7 @@ public final class AccessibilityManager { throw new IllegalStateException("Accessibility off. Did you forget to check that?"); } try { - mService.interrupt(); + mService.interrupt(mUserId); if (DEBUG) { Log.i(LOG_TAG, "Requested interrupt from all services"); } @@ -280,7 +320,7 @@ public final class AccessibilityManager { public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() { List<AccessibilityServiceInfo> services = null; try { - services = mService.getInstalledAccessibilityServiceList(); + services = mService.getInstalledAccessibilityServiceList(mUserId); if (DEBUG) { Log.i(LOG_TAG, "Installed AccessibilityServices " + services); } @@ -307,7 +347,7 @@ public final class AccessibilityManager { int feedbackTypeFlags) { List<AccessibilityServiceInfo> services = null; try { - services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags); + services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId); if (DEBUG) { Log.i(LOG_TAG, "Installed AccessibilityServices " + services); } @@ -385,7 +425,7 @@ public final class AccessibilityManager { public int addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection) { try { - return mService.addAccessibilityInteractionConnection(windowToken, connection); + return mService.addAccessibilityInteractionConnection(windowToken, connection, mUserId); } catch (RemoteException re) { Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re); } diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index 5b5134a..60238627 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -34,18 +34,18 @@ import android.view.IWindow; */ interface IAccessibilityManager { - int addClient(IAccessibilityManagerClient client); + int addClient(IAccessibilityManagerClient client, int userId); - boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent); + boolean sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId); - List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(); + List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId); - List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType); + List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId); - void interrupt(); + void interrupt(int userId); int addAccessibilityInteractionConnection(IWindow windowToken, - in IAccessibilityInteractionConnection connection); + in IAccessibilityInteractionConnection connection, int userId); void removeAccessibilityInteractionConnection(IWindow windowToken); diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index d23f52c..1c47615 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -4594,11 +4594,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc private void ensureSelectionHandles() { if (mSelectHandleCenter == null) { mSelectHandleCenter = mContext.getResources().getDrawable( - com.android.internal.R.drawable.text_select_handle_middle); + com.android.internal.R.drawable.text_select_handle_middle).mutate(); mSelectHandleLeft = mContext.getResources().getDrawable( - com.android.internal.R.drawable.text_select_handle_left); + com.android.internal.R.drawable.text_select_handle_left).mutate(); mSelectHandleRight = mContext.getResources().getDrawable( - com.android.internal.R.drawable.text_select_handle_right); + com.android.internal.R.drawable.text_select_handle_right).mutate(); // All handles have the same height, so we can save effort with // this assumption. mSelectOffset = new Point(0, diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java index fe6c4f5..736566e 100644 --- a/core/java/android/widget/ActivityChooserModel.java +++ b/core/java/android/widget/ActivityChooserModel.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.database.DataSetObservable; -import android.database.DataSetObserver; import android.os.AsyncTask; import android.text.TextUtils; import android.util.Log; @@ -458,13 +457,18 @@ public class ActivityChooserModel extends DataSetObservable { * </p> * * @return An {@link Intent} for launching the activity or null if the - * policy has consumed the intent. + * policy has consumed the intent or there is not current intent + * set via {@link #setIntent(Intent)}. * * @see HistoricalRecord * @see OnChooseActivityListener */ public Intent chooseActivity(int index) { synchronized (mInstanceLock) { + if (mIntent == null) { + return null; + } + ensureConsistentState(); ActivityResolveInfo chosenActivity = mActivities.get(index); diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index 27d15f6..06dadb0 100755 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -257,7 +257,7 @@ public class AppSecurityPermissions { try { pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); } catch (NameNotFoundException e) { - Log.w(TAG, "Could'nt retrieve permissions for package:"+packageName); + Log.w(TAG, "Couldn't retrieve permissions for package:"+packageName); return; } // Extract all user permissions diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index b06da06..361eca4 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -1573,7 +1573,8 @@ public class CalendarView extends FrameLayout { // If we're showing the week number calculate it based on Monday int i = 0; if (mShowWeekNumber) { - mDayNumbers[0] = Integer.toString(mTempDate.get(Calendar.WEEK_OF_YEAR)); + mDayNumbers[0] = String.format(Locale.getDefault(), "%d", + mTempDate.get(Calendar.WEEK_OF_YEAR)); i++; } @@ -1594,7 +1595,8 @@ public class CalendarView extends FrameLayout { if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { mDayNumbers[i] = ""; } else { - mDayNumbers[i] = Integer.toString(mTempDate.get(Calendar.DAY_OF_MONTH)); + mDayNumbers[i] = String.format(Locale.getDefault(), "%d", + mTempDate.get(Calendar.DAY_OF_MONTH)); } mTempDate.add(Calendar.DAY_OF_MONTH, 1); } @@ -1609,7 +1611,7 @@ public class CalendarView extends FrameLayout { } /** - * Initialize the paint isntances. + * Initialize the paint instances. */ private void initilaizePaints() { mDrawPaint.setFakeBoldText(false); @@ -1620,6 +1622,7 @@ public class CalendarView extends FrameLayout { mMonthNumDrawPaint.setAntiAlias(true); mMonthNumDrawPaint.setStyle(Style.FILL); mMonthNumDrawPaint.setTextAlign(Align.CENTER); + mMonthNumDrawPaint.setTextSize(mDateTextSize); } /** @@ -1657,16 +1660,34 @@ public class CalendarView extends FrameLayout { * @return True if a day was found for the given location. */ public boolean getDayFromLocation(float x, Calendar outCalendar) { - int dayStart = mShowWeekNumber ? mWidth / mNumCells : 0; - if (x < dayStart || x > mWidth) { + final boolean isLayoutRtl = isLayoutRtl(); + + int start; + int end; + + if (isLayoutRtl) { + start = 0; + end = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; + } else { + start = mShowWeekNumber ? mWidth / mNumCells : 0; + end = mWidth; + } + + if (x < start || x > end) { outCalendar.clear(); return false; } - // Selection is (x - start) / (pixels/day) == (x -s) * day / pixels - int dayPosition = (int) ((x - dayStart) * mDaysPerWeek - / (mWidth - dayStart)); + + // Selection is (x - start) / (pixels/day) which is (x - start) * day / pixels + int dayPosition = (int) ((x - start) * mDaysPerWeek / (end - start)); + + if (isLayoutRtl) { + dayPosition = mDaysPerWeek - 1 - dayPosition; + } + outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis()); outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition); + return true; } @@ -1691,12 +1712,25 @@ public class CalendarView extends FrameLayout { mTempRect.top = mWeekSeperatorLineWidth; mTempRect.bottom = mHeight; - mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0; - mTempRect.right = mSelectedLeft - 2; + + final boolean isLayoutRtl = isLayoutRtl(); + + if (isLayoutRtl) { + mTempRect.left = 0; + mTempRect.right = mSelectedLeft - 2; + } else { + mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0; + mTempRect.right = mSelectedLeft - 2; + } canvas.drawRect(mTempRect, mDrawPaint); - mTempRect.left = mSelectedRight + 3; - mTempRect.right = mWidth; + if (isLayoutRtl) { + mTempRect.left = mSelectedRight + 3; + mTempRect.right = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; + } else { + mTempRect.left = mSelectedRight + 3; + mTempRect.right = mWidth; + } canvas.drawRect(mTempRect, mDrawPaint); } @@ -1706,25 +1740,41 @@ public class CalendarView extends FrameLayout { * @param canvas The canvas to draw on */ private void drawWeekNumbersAndDates(Canvas canvas) { - float textHeight = mDrawPaint.getTextSize(); - int y = (int) ((mHeight + textHeight) / 2) - mWeekSeperatorLineWidth; - int nDays = mNumCells; + final float textHeight = mDrawPaint.getTextSize(); + final int y = (int) ((mHeight + textHeight) / 2) - mWeekSeperatorLineWidth; + final int nDays = mNumCells; + final int divisor = 2 * nDays; mDrawPaint.setTextAlign(Align.CENTER); mDrawPaint.setTextSize(mDateTextSize); + int i = 0; - int divisor = 2 * nDays; - if (mShowWeekNumber) { - mDrawPaint.setColor(mWeekNumberColor); - int x = mWidth / divisor; - canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); - i++; - } - for (; i < nDays; i++) { - mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor - : mUnfocusedMonthDateColor); - int x = (2 * i + 1) * mWidth / divisor; - canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint); + + if (isLayoutRtl()) { + for (; i < nDays - 1; i++) { + mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor + : mUnfocusedMonthDateColor); + int x = (2 * i + 1) * mWidth / divisor; + canvas.drawText(mDayNumbers[nDays - 1 - i], x, y, mMonthNumDrawPaint); + } + if (mShowWeekNumber) { + mDrawPaint.setColor(mWeekNumberColor); + int x = mWidth - mWidth / divisor; + canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); + } + } else { + if (mShowWeekNumber) { + mDrawPaint.setColor(mWeekNumberColor); + int x = mWidth / divisor; + canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); + i++; + } + for (; i < nDays; i++) { + mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor + : mUnfocusedMonthDateColor); + int x = (2 * i + 1) * mWidth / divisor; + canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint); + } } } @@ -1744,8 +1794,16 @@ public class CalendarView extends FrameLayout { } mDrawPaint.setColor(mWeekSeparatorLineColor); mDrawPaint.setStrokeWidth(mWeekSeperatorLineWidth); - float x = mShowWeekNumber ? mWidth / mNumCells : 0; - canvas.drawLine(x, 0, mWidth, 0, mDrawPaint); + float startX; + float stopX; + if (isLayoutRtl()) { + startX = 0; + stopX = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; + } else { + startX = mShowWeekNumber ? mWidth / mNumCells : 0; + stopX = mWidth; + } + canvas.drawLine(startX, 0, stopX, 0, mDrawPaint); } /** @@ -1778,15 +1836,21 @@ public class CalendarView extends FrameLayout { */ private void updateSelectionPositions() { if (mHasSelectedDay) { + final boolean isLayoutRtl = isLayoutRtl(); int selectedPosition = mSelectedDay - mFirstDayOfWeek; if (selectedPosition < 0) { selectedPosition += 7; } - if (mShowWeekNumber) { + if (mShowWeekNumber && !isLayoutRtl) { selectedPosition++; } - mSelectedLeft = selectedPosition * mWidth / mNumCells; - mSelectedRight = (selectedPosition + 1) * mWidth / mNumCells; + if (isLayoutRtl) { + mSelectedLeft = (mDaysPerWeek - 1 - selectedPosition) * mWidth / mNumCells; + + } else { + mSelectedLeft = selectedPosition * mWidth / mNumCells; + } + mSelectedRight = mSelectedLeft + mWidth / mNumCells; } } diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index ac3bedb..07d3a7a 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -220,7 +220,7 @@ public class DatePicker extends FrameLayout { // day mDaySpinner = (NumberPicker) findViewById(R.id.day); - mDaySpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); + mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); mDaySpinner.setOnLongPressUpdateInterval(100); mDaySpinner.setOnValueChangedListener(onChangeListener); mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input); diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index dbc777e..704f6b6 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -51,10 +51,12 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import com.android.internal.R; +import libcore.icu.LocaleData; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * A widget that enables the user to select a number form a predefined range. @@ -138,13 +140,6 @@ public class NumberPicker extends LinearLayout { private static final int DEFAULT_LAYOUT_RESOURCE_ID = R.layout.number_picker; /** - * The numbers accepted by the input text's {@link Filter} - */ - private static final char[] DIGIT_CHARACTERS = new char[] { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' - }; - - /** * Constant for unspecified size. */ private static final int SIZE_UNSPECIFIED = -1; @@ -154,23 +149,53 @@ public class NumberPicker extends LinearLayout { * strings like "01". Keeping a static formatter etc. is the most efficient * way to do this; it avoids creating temporary objects on every call to * format(). - * - * @hide */ - public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() { + private static class TwoDigitFormatter implements NumberPicker.Formatter { final StringBuilder mBuilder = new StringBuilder(); - final java.util.Formatter mFmt = new java.util.Formatter(mBuilder, java.util.Locale.US); + char mZeroDigit; + java.util.Formatter mFmt; final Object[] mArgs = new Object[1]; + TwoDigitFormatter() { + final Locale locale = Locale.getDefault(); + init(locale); + } + + private void init(Locale locale) { + mFmt = createFormatter(locale); + mZeroDigit = getZeroDigit(locale); + } + public String format(int value) { + final Locale currentLocale = Locale.getDefault(); + if (mZeroDigit != getZeroDigit(currentLocale)) { + init(currentLocale); + } mArgs[0] = value; mBuilder.delete(0, mBuilder.length()); mFmt.format("%02d", mArgs); return mFmt.toString(); } - }; + + private static char getZeroDigit(Locale locale) { + return LocaleData.get(locale).zeroDigit; + } + + private java.util.Formatter createFormatter(Locale locale) { + return new java.util.Formatter(mBuilder, locale); + } + } + + private static final TwoDigitFormatter sTwoDigitFormatter = new TwoDigitFormatter(); + + /** + * @hide + */ + public static final Formatter getTwoDigitFormatter() { + return sTwoDigitFormatter; + } /** * The increment button. @@ -1156,7 +1181,7 @@ public class NumberPicker extends LinearLayout { if (mDisplayedValues == null) { float maxDigitWidth = 0; for (int i = 0; i <= 9; i++) { - final float digitWidth = mSelectorWheelPaint.measureText(String.valueOf(i)); + final float digitWidth = mSelectorWheelPaint.measureText(formatNumberWithLocale(i)); if (digitWidth > maxDigitWidth) { maxDigitWidth = digitWidth; } @@ -1689,7 +1714,7 @@ public class NumberPicker extends LinearLayout { } private String formatNumber(int value) { - return (mFormatter != null) ? mFormatter.format(value) : String.valueOf(value); + return (mFormatter != null) ? mFormatter.format(value) : formatNumberWithLocale(value); } private void validateInputTextView(View v) { @@ -1849,6 +1874,20 @@ public class NumberPicker extends LinearLayout { } /** + * The numbers accepted by the input text's {@link Filter} + */ + private static final char[] DIGIT_CHARACTERS = new char[] { + // Latin digits are the common case + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + // Arabic-Indic + '\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668' + , '\u0669', + // Extended Arabic-Indic + '\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8' + , '\u06f9' + }; + + /** * Filter for accepting only valid indices or prefixes of the string * representation of valid indices. */ @@ -2493,4 +2532,8 @@ public class NumberPicker extends LinearLayout { return null; } } + + static private String formatNumberWithLocale(int value) { + return String.format(Locale.getDefault(), "%d", value); + } } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 87ef23f..1a47ce2 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -222,6 +222,14 @@ public class RemoteViews implements Parcelable, Filter { int viewId; } + /** + * Merges the passed RemoteViews actions with this RemoteViews actions according to + * action-specific merge rules. + * + * @param newRv + * + * @hide + */ public void mergeRemoteViews(RemoteViews newRv) { // We first copy the new RemoteViews, as the process of merging modifies the way the actions // reference the bitmap cache. We don't want to modify the object as it may need to diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index cb9ed61..e6796cb 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -172,7 +172,7 @@ public class TimePicker extends FrameLayout { mMinuteSpinner.setMinValue(0); mMinuteSpinner.setMaxValue(59); mMinuteSpinner.setOnLongPressUpdateInterval(100); - mMinuteSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); + mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { updateInputState(); @@ -500,7 +500,7 @@ public class TimePicker extends FrameLayout { if (is24HourView()) { mHourSpinner.setMinValue(0); mHourSpinner.setMaxValue(23); - mHourSpinner.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); + mHourSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); } else { mHourSpinner.setMinValue(1); mHourSpinner.setMaxValue(12); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index f3bef08..09457cc 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -215,36 +215,26 @@ public class LockPatternUtils { } public void setCurrentUser(int userId) { - if (Process.myUid() == Process.SYSTEM_UID) { - mCurrentUserId = userId; - } else { - throw new SecurityException("Only the system process can set the current user"); - } + mCurrentUserId = userId; } public int getCurrentUser() { - if (Process.myUid() == Process.SYSTEM_UID) { - if (mCurrentUserId != UserHandle.USER_NULL) { - // Someone is regularly updating using setCurrentUser() use that value. - return mCurrentUserId; - } - try { - return ActivityManagerNative.getDefault().getCurrentUser().id; - } catch (RemoteException re) { - return UserHandle.USER_OWNER; - } - } else { - throw new SecurityException("Only the system process can get the current user"); + if (mCurrentUserId != UserHandle.USER_NULL) { + // Someone is regularly updating using setCurrentUser() use that value. + return mCurrentUserId; + } + try { + return ActivityManagerNative.getDefault().getCurrentUser().id; + } catch (RemoteException re) { + return UserHandle.USER_OWNER; } } public void removeUser(int userId) { - if (Process.myUid() == Process.SYSTEM_UID) { - try { - getLockSettings().removeUser(userId); - } catch (RemoteException re) { - Log.e(TAG, "Couldn't remove lock settings for user " + userId); - } + try { + getLockSettings().removeUser(userId); + } catch (RemoteException re) { + Log.e(TAG, "Couldn't remove lock settings for user " + userId); } } @@ -591,10 +581,6 @@ public class LockPatternUtils { // Compute the hash final byte[] hash = passwordToHash(password); try { - if (Process.myUid() != Process.SYSTEM_UID && userHandle != UserHandle.myUserId()) { - throw new SecurityException( - "Only the system process can save lock password for another user"); - } getLockSettings().setLockPassword(hash, userHandle); DevicePolicyManager dpm = getDevicePolicyManager(); KeyStore keyStore = KeyStore.getInstance(); @@ -1007,8 +993,8 @@ public class LockPatternUtils { * or null if there is no next alarm. */ public String getNextAlarm() { - String nextAlarm = Settings.System.getString(mContentResolver, - Settings.System.NEXT_ALARM_FORMATTED); + String nextAlarm = Settings.System.getStringForUser(mContentResolver, + Settings.System.NEXT_ALARM_FORMATTED, UserHandle.USER_CURRENT); if (nextAlarm == null || TextUtils.isEmpty(nextAlarm)) { return null; } @@ -1035,8 +1021,9 @@ public class LockPatternUtils { public int[] getUserDefinedWidgets() { int appWidgetId = -1; - String appWidgetIdString = Settings.Secure.getString( - mContentResolver, Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID); + String appWidgetIdString = Settings.Secure.getStringForUser( + mContentResolver, Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID, + UserHandle.USER_CURRENT); if (appWidgetIdString != null) { appWidgetId = (int) Integer.decode(appWidgetIdString); } @@ -1046,8 +1033,9 @@ public class LockPatternUtils { public int getStatusWidget() { int appWidgetId = -1; - String appWidgetIdString = Settings.Secure.getString( - mContentResolver, Settings.Secure.LOCK_SCREEN_STATUS_APPWIDGET_ID); + String appWidgetIdString = Settings.Secure.getStringForUser( + mContentResolver, Settings.Secure.LOCK_SCREEN_STATUS_APPWIDGET_ID, + UserHandle.USER_CURRENT); if (appWidgetIdString != null) { appWidgetId = (int) Integer.decode(appWidgetIdString); } |