diff options
Diffstat (limited to 'core/java')
17 files changed, 380 insertions, 111 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/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/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index e3749b4..07117fe 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -230,6 +230,21 @@ public class ResolveInfo implements Parcelable { public ResolveInfo() { } + public ResolveInfo(ResolveInfo orig) { + activityInfo = orig.activityInfo; + serviceInfo = orig.serviceInfo; + filter = orig.filter; + priority = orig.priority; + preferredOrder = orig.preferredOrder; + match = orig.match; + specificIndex = orig.specificIndex; + labelRes = orig.labelRes; + nonLocalizedLabel = orig.nonLocalizedLabel; + icon = orig.icon; + resolvePackageName = orig.resolvePackageName; + system = orig.system; + } + public String toString() { ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo; return "ResolveInfo{" diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 27cabef..846443d 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -21,6 +21,7 @@ import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; +import java.net.SocketException; import java.security.KeyManagementException; import java.security.cert.X509Certificate; import javax.net.SocketFactory; @@ -341,6 +342,22 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { castToOpenSSLSocket(socket).setHostname(hostName); } + /** + * Sets this socket's SO_SNDTIMEO write timeout in milliseconds. + * Use 0 for no timeout. + * To take effect, this option must be set before the blocking method was called. + * + * @param socket a socket created by this factory. + * @param timeout the desired write timeout in milliseconds. + * @throws IllegalArgumentException if the socket was not created by this factory. + * + * @hide + */ + public void setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds) + throws SocketException { + castToOpenSSLSocket(socket).setSoWriteTimeout(writeTimeoutMilliseconds); + } + private static OpenSSLSocketImpl castToOpenSSLSocket(Socket socket) { if (!(socket instanceof OpenSSLSocketImpl)) { throw new IllegalArgumentException("Socket not created by this factory: " diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 3c90f1c..0e7ab52 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -255,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/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index e0e8de3..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. * @@ -649,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; @@ -698,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 @@ -1414,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 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/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 6ddfc3b..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); } @@ -1658,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; } @@ -1692,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); } @@ -1707,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); + } } } @@ -1745,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); } /** @@ -1779,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 5d65324..90f55bf 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -228,6 +228,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); } |