diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/Presentation.java | 89 | ||||
| -rw-r--r-- | core/java/android/hardware/display/DisplayManager.java | 72 | ||||
| -rw-r--r-- | core/java/android/os/UserManager.java | 17 | ||||
| -rw-r--r-- | core/java/android/provider/Settings.java | 11 | ||||
| -rw-r--r-- | core/java/android/view/Display.java | 103 | ||||
| -rw-r--r-- | core/java/android/view/DisplayInfo.java | 27 | ||||
| -rw-r--r-- | core/java/android/view/HardwareRenderer.java | 53 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 17 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 1 | ||||
| -rw-r--r-- | core/java/android/widget/Editor.java | 29 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 9 | ||||
| -rw-r--r-- | core/java/com/android/internal/widget/LockPatternUtils.java | 139 | ||||
| -rw-r--r-- | core/java/com/android/internal/widget/multiwaveview/GlowPadView.java | 5 |
13 files changed, 465 insertions, 107 deletions
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index 20b27c5..3e8af60 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -50,6 +50,93 @@ import android.util.TypedValue; * whenever the activity itself is paused or resumed. * </p> * + * <h3>Choosing a presentation display</h3> + * <p> + * Before showing a {@link Presentation} it's important to choose the {@link Display} + * on which it will appear. Choosing a presentation display is sometimes difficult + * because there may be multiple displays attached. Rather than trying to guess + * which display is best, an application should let the system choose a suitable + * presentation display. + * </p><p> + * There are two main ways to choose a {@link Display}. + * </p> + * + * <h4>Using the media router to choose a presentation display</h4> + * <p> + * The easiest way to choose a presentation display is to use the + * {@link android.media.MediaRouter MediaRouter} API. The media router service keeps + * track of which audio and video routes are available on the system. + * The media router sends notifications whenever routes are selected or unselected + * or when the preferred presentation display of a route changes. + * So an application can simply watch for these notifications and show or dismiss + * a presentation on the preferred presentation display automatically. + * </p><p> + * The preferred presentation display is the display that the media router recommends + * that the application should use if it wants to show content on the secondary display. + * Sometimes there may not be a preferred presentation display in which + * case the application should show its content locally without using a presentation. + * </p><p> + * Here's how to use the media router to create and show a presentation on the preferred + * presentation display using {@link android.media.MediaRouter.RouteInfo#getPresentationDisplay()}. + * </p> + * {@samplecode + * MediaRouter mediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); + * MediaRouter.RouteInfo route = mediaRouter.getSelectedRoute(); + * if (route != null) ${ + * Display presentationDisplay = route.getPresentationDisplay(); + * if (presentationDisplay != null) ${ + * Presentation presentation = new MyPresentation(context, presentationDisplay); + * presentation.show(); + * $} + * $} + * } + * <p> + * The following sample code from <code>ApiDemos</code> demonstrates how to use the media + * router to automatically switch between showing content in the main activity and showing + * the content in a presentation when a presentation display is available. + * </p> + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationWithMediaRouterActivity.java + * activity} + * + * <h4>Using the display manager to choose a presentation display</h4> + * <p> + * Another way to choose a presentation display is to use the {@link DisplayManager} API + * directly. The display manager service provides functions to enumerate and describe all + * displays that are attached to the system including displays that may be used + * for presentations. + * </p><p> + * The display manager keeps track of all displays in the system. However, not all + * displays are appropriate for showing presentations. For example, if an activity + * attempted to show a presentation on the main display it might obscure its own content + * (it's like opening a dialog on top of your activity). + * </p><p> + * Here's how to identify suitable displays for showing presentations using + * {@link DisplayManager#getDisplays(String)} and the + * {@link DisplayManager#DISPLAY_CATEGORY_PRESENTATION} category. + * </p> + * {@samplecode + * DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); + * Display[] presentationDisplays = displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); + * if (presentationDisplays.length > 0) ${ + * // If there is more than one suitable presentation display, then we could consider + * // giving the user a choice. For this example, we simply choose the first display + * // which is the one the system recommends as the preferred presentation display. + * Display display = presentationDisplays[0]; + * Presentation presentation = new MyPresentation(context, presentationDisplay); + * presentation.show(); + * $} + * } + * <p> + * The following sample code from <code>ApiDemos</code> demonstrates how to use the display + * manager to enumerate displays and show content on multiple presentation displays + * simultaneously. + * </p> + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/PresentationActivity.java + * activity} + * + * @see android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO for information on about live + * video routes and how to obtain the preferred presentation display for the + * current media route. * @see DisplayManager for information on how to enumerate displays and receive * notifications when displays are added or removed. */ @@ -121,7 +208,7 @@ public class Presentation extends Dialog { @Override protected void onStart() { super.onStart(); - mDisplayManager.registerDisplayListener(mDisplayListener, null); + mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); // Since we were not watching for display changes until just now, there is a // chance that the display metrics have changed. If so, we will need to diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 28e320b..0a7a2e7 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -21,6 +21,8 @@ import android.os.Handler; import android.util.SparseArray; import android.view.Display; +import java.util.ArrayList; + /** * Manages the properties of attached displays. * <p> @@ -40,6 +42,8 @@ public final class DisplayManager { private final Object mLock = new Object(); private final SparseArray<Display> mDisplays = new SparseArray<Display>(); + private final ArrayList<Display> mTempDisplays = new ArrayList<Display>(); + /** * Broadcast receiver that indicates when the Wifi display status changes. * <p> @@ -60,6 +64,20 @@ public final class DisplayManager { public static final String EXTRA_WIFI_DISPLAY_STATUS = "android.hardware.display.extra.WIFI_DISPLAY_STATUS"; + /** + * Display category: Presentation displays. + * <p> + * This category can be used to identify secondary displays that are suitable for + * use as presentation displays. + * </p> + * + * @see android.app.Presentation for information about presenting content + * on secondary displays. + * @see #getDisplays(String) + */ + public static final String DISPLAY_CATEGORY_PRESENTATION = + "android.hardware.display.category.PRESENTATION"; + /** @hide */ public DisplayManager(Context context) { mContext = context; @@ -87,24 +105,52 @@ public final class DisplayManager { * @return An array containing all displays. */ public Display[] getDisplays() { - int[] displayIds = mGlobal.getDisplayIds(); - int expectedCount = displayIds.length; - Display[] displays = new Display[expectedCount]; + return getDisplays(null); + } + + /** + * Gets all currently valid logical displays of the specified category. + * <p> + * When there are multiple displays in a category the returned displays are sorted + * of preference. For example, if the requested category is + * {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays + * then the displays are sorted so that the first display in the returned array + * is the most preferred presentation display. The application may simply + * use the first display or allow the user to choose. + * </p> + * + * @param category The requested display category or null to return all displays. + * @return An array containing all displays sorted by order of preference. + * + * @see #DISPLAY_CATEGORY_PRESENTATION + */ + public Display[] getDisplays(String category) { + final int[] displayIds = mGlobal.getDisplayIds(); synchronized (mLock) { - int actualCount = 0; - for (int i = 0; i < expectedCount; i++) { - Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); - if (display != null) { - displays[actualCount++] = display; + try { + if (category == null) { + addMatchingDisplaysLocked(mTempDisplays, displayIds, -1); + } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) { + addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI); + addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI); + addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY); } + return mTempDisplays.toArray(new Display[mTempDisplays.size()]); + } finally { + mTempDisplays.clear(); } - if (actualCount != expectedCount) { - Display[] oldDisplays = displays; - displays = new Display[actualCount]; - System.arraycopy(oldDisplays, 0, displays, 0, actualCount); + } + } + + private void addMatchingDisplaysLocked( + ArrayList<Display> displays, int[] displayIds, int matchType) { + for (int i = 0; i < displayIds.length; i++) { + Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/); + if (display != null + && (matchType < 0 || display.getType() == matchType)) { + displays.add(display); } } - return displays; } private Display getOrCreateDisplayLocked(int displayId, boolean assumeValid) { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 898c766..d73f99a 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -122,7 +122,7 @@ public class UserManager { * @param userHandle the user handle of the user whose information is being requested. * @return the UserInfo object for a specific user. * @hide - * */ + */ public UserInfo getUserInfo(int userHandle) { try { return mService.getUserInfo(userHandle); @@ -134,10 +134,11 @@ public class UserManager { /** * Return the serial number for a user. This is a device-unique - * number assigned to that user; if the user is deleted and new users - * created, the new users will not be given the same serial number. + * number assigned to that user; if the user is deleted and then a new + * user created, the new users will not be given the same serial number. * @param user The user whose serial number is to be retrieved. - * @return The serial number of the given user. + * @return The serial number of the given user; returns -1 if the + * given UserHandle does not exist. * @see #getUserForSerialNumber(long) */ public long getSerialNumberForUser(UserHandle user) { @@ -179,6 +180,14 @@ public class UserManager { } /** + * Return the number of users currently created on the device. + */ + public int getUserCount() { + List<UserInfo> users = getUsers(); + return users != null ? users.size() : 1; + } + + /** * Returns information for all users on this device. * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. * @return the list of users that were created. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 8897039..cda0f36 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3222,18 +3222,11 @@ public final class Settings { public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info"; /** - * Id of the time appwidget on the lockscreen, or -1 if none - * @hide - */ - public static final String LOCK_SCREEN_STATUS_APPWIDGET_ID = - "lock_screen_status_appwidget_id"; - - /** * Id of the user-selected appwidget on the lockscreen, or -1 if none * @hide */ - public static final String LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID = - "lock_screen_user_selected_appwidget_id"; + public static final String LOCK_SCREEN_APPWIDGET_IDS = + "lock_screen_appwidget_ids"; /** * This preference enables showing the owner info on LockScren. diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 1cd3e05..758abb5 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -54,7 +54,9 @@ public final class Display { private final DisplayManagerGlobal mGlobal; private final int mDisplayId; private final int mLayerStack; - private final String mName; + private final int mFlags; + private final int mType; + private final String mAddress; private final CompatibilityInfoHolder mCompatibilityInfo; private DisplayInfo mDisplayInfo; // never null @@ -141,6 +143,36 @@ public final class Display { public static final int FLAG_SECURE = 1 << 1; /** + * Display type: Unknown display type. + * @hide + */ + public static final int TYPE_UNKNOWN = 0; + + /** + * Display type: Built-in display. + * @hide + */ + public static final int TYPE_BUILT_IN = 1; + + /** + * Display type: HDMI display. + * @hide + */ + public static final int TYPE_HDMI = 2; + + /** + * Display type: WiFi display. + * @hide + */ + public static final int TYPE_WIFI = 3; + + /** + * Display type: Overlay display. + * @hide + */ + public static final int TYPE_OVERLAY = 4; + + /** * Internal method to create a display. * Applications should use {@link android.view.WindowManager#getDefaultDisplay()} * or {@link android.hardware.display.DisplayManager#getDisplay} @@ -154,10 +186,14 @@ public final class Display { mGlobal = global; mDisplayId = displayId; mDisplayInfo = displayInfo; - mLayerStack = displayInfo.layerStack; // can never change as long as the display is valid - mName = displayInfo.name; // cannot change as long as the display is valid mCompatibilityInfo = compatibilityInfo; mIsValid = true; + + // Cache properties that cannot change as long as the display is valid. + mLayerStack = displayInfo.layerStack; + mFlags = displayInfo.flags; + mType = displayInfo.type; + mAddress = displayInfo.address; } /** @@ -228,10 +264,34 @@ public final class Display { * @see #FLAG_SECURE */ public int getFlags() { - synchronized (this) { - updateDisplayInfoLocked(); - return mDisplayInfo.flags; - } + return mFlags; + } + + /** + * Gets the display type. + * + * @return The display type. + * + * @see #TYPE_UNKNOWN + * @see #TYPE_BUILT_IN + * @see #TYPE_HDMI + * @see #TYPE_WIFI + * @see #TYPE_OVERLAY + * @hide + */ + public int getType() { + return mType; + } + + /** + * Gets the display address, or null if none. + * Interpretation varies by display type. + * + * @return The display address. + * @hide + */ + public String getAddress() { + return mAddress; } /** @@ -246,10 +306,17 @@ public final class Display { /** * Gets the name of the display. + * <p> + * Note that some displays may be renamed by the user. + * </p> + * * @return The display's name. */ public String getName() { - return mName; + synchronized (this) { + updateDisplayInfoLocked(); + return mDisplayInfo.name; + } } /** @@ -527,5 +594,25 @@ public final class Display { + ", " + mTempMetrics + ", isValid=" + mIsValid; } } + + /** + * @hide + */ + public static String typeToString(int type) { + switch (type) { + case TYPE_UNKNOWN: + return "UNKNOWN"; + case TYPE_BUILT_IN: + return "BUILT_IN"; + case TYPE_HDMI: + return "HDMI"; + case TYPE_WIFI: + return "WIFI"; + case TYPE_OVERLAY: + return "OVERLAY"; + default: + return Integer.toString(type); + } + } } diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index ead5ff4..f3841d5 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -39,6 +39,17 @@ public final class DisplayInfo implements Parcelable { public int flags; /** + * Display type. + */ + public int type; + + /** + * Display address, or null if none. + * Interpretation varies by display type. + */ + public String address; + + /** * The human-readable name of the display. */ public String name; @@ -143,10 +154,12 @@ public final class DisplayInfo implements Parcelable { public float physicalYDpi; public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() { + @Override public DisplayInfo createFromParcel(Parcel source) { return new DisplayInfo(source); } + @Override public DisplayInfo[] newArray(int size) { return new DisplayInfo[size]; } @@ -171,6 +184,9 @@ public final class DisplayInfo implements Parcelable { public boolean equals(DisplayInfo other) { return other != null && layerStack == other.layerStack + && flags == other.flags + && type == other.type + && Objects.equal(address, other.address) && Objects.equal(name, other.name) && appWidth == other.appWidth && appHeight == other.appHeight @@ -195,6 +211,8 @@ public final class DisplayInfo implements Parcelable { public void copyFrom(DisplayInfo other) { layerStack = other.layerStack; flags = other.flags; + type = other.type; + address = other.address; name = other.name; appWidth = other.appWidth; appHeight = other.appHeight; @@ -214,6 +232,8 @@ public final class DisplayInfo implements Parcelable { public void readFromParcel(Parcel source) { layerStack = source.readInt(); flags = source.readInt(); + type = source.readInt(); + address = source.readString(); name = source.readString(); appWidth = source.readInt(); appHeight = source.readInt(); @@ -234,6 +254,8 @@ public final class DisplayInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(layerStack); dest.writeInt(this.flags); + dest.writeInt(type); + dest.writeString(address); dest.writeString(name); dest.writeInt(appWidth); dest.writeInt(appHeight); @@ -294,7 +316,10 @@ public final class DisplayInfo implements Parcelable { + ", rotation " + rotation + ", density " + logicalDensityDpi + ", " + physicalXDpi + " x " + physicalYDpi + " dpi" - + ", layerStack " + layerStack + flagsToString(flags) + "}"; + + ", layerStack " + layerStack + + ", type " + Display.typeToString(type) + + ", address " + address + + flagsToString(flags) + "}"; } private static String flagsToString(int flags) { diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 59f941d..1c613245 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -1526,30 +1526,6 @@ public abstract class HardwareRenderer { } @Override - void destroyLayers(View view) { - if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) { - if (mCanvas != null) { - mCanvas.clearLayerUpdates(); - } - destroyHardwareLayer(view); - GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); - } - } - - private static void destroyHardwareLayer(View view) { - view.destroyLayer(true); - - if (view instanceof ViewGroup) { - ViewGroup group = (ViewGroup) view; - - int count = group.getChildCount(); - for (int i = 0; i < count; i++) { - destroyHardwareLayer(group.getChildAt(i)); - } - } - } - - @Override boolean safelyRun(Runnable action) { boolean needsContext = true; if (isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) needsContext = false; @@ -1574,6 +1550,35 @@ public abstract class HardwareRenderer { } @Override + void destroyLayers(final View view) { + if (view != null) { + safelyRun(new Runnable() { + @Override + public void run() { + if (mCanvas != null) { + mCanvas.clearLayerUpdates(); + } + destroyHardwareLayer(view); + GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS); + } + }); + } + } + + private static void destroyHardwareLayer(View view) { + view.destroyLayer(true); + + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + + int count = group.getChildCount(); + for (int i = 0; i < count; i++) { + destroyHardwareLayer(group.getChildAt(i)); + } + } + } + + @Override void destroyHardwareResources(final View view) { if (view != null) { safelyRun(new Runnable() { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f5e259e..9d0d4f0 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1864,7 +1864,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Default horizontal layout direction. - * @hide */ private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; @@ -1914,7 +1913,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Default text direction is inherited */ - public static int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; + private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; /** * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) @@ -2024,7 +2023,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Default text alignment is inherited */ - public static int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; + private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; /** * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) @@ -3224,7 +3223,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mContext = context; mResources = context != null ? context.getResources() : null; mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; - // Set layout and text direction defaults + // Set some flags defaults mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | @@ -14198,11 +14197,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @hide */ protected void resolveDrawables() { - if (mBackground != null) { - mBackground.setLayoutDirection(getLayoutDirection()); + if (canResolveLayoutDirection()) { + if (mBackground != null) { + mBackground.setLayoutDirection(getLayoutDirection()); + } + mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; + onResolveDrawables(getLayoutDirection()); } - mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; - onResolveDrawables(getLayoutDirection()); } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7f785cd..00723f3 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3384,7 +3384,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (child.isLayoutDirectionInherited()) { child.resetRtlProperties(); - child.resolveRtlPropertiesIfNeeded(); } onViewAdded(child); diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 19b825c..495e46b 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -144,6 +144,8 @@ public class Editor { CharSequence mError; boolean mErrorWasChanged; ErrorPopup mErrorPopup; + private int mLastLayoutDirection = -1; + /** * This flag is set if the TextView tries to display an error before it * is attached to the window (so its position is still unknown). @@ -288,23 +290,30 @@ public class Editor { public void setError(CharSequence error, Drawable icon) { mError = TextUtils.stringOrSpannedString(error); mErrorWasChanged = true; - final Drawables dr = mTextView.mDrawables; - if (dr != null) { - switch (mTextView.getLayoutDirection()) { + final int layoutDirection = mTextView.getLayoutDirection(); + if (mLastLayoutDirection != layoutDirection) { + final Drawables dr = mTextView.mDrawables; + switch (layoutDirection) { default: case View.LAYOUT_DIRECTION_LTR: - mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, - dr.mDrawableBottom); + if (dr != null) { + mTextView.setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, + dr.mDrawableBottom); + } else { + mTextView.setCompoundDrawables(null, null, icon, null); + } break; case View.LAYOUT_DIRECTION_RTL: - mTextView.setCompoundDrawables(icon, dr.mDrawableTop, dr.mDrawableRight, - dr.mDrawableBottom); + if (dr != null) { + mTextView.setCompoundDrawables(icon, dr.mDrawableTop, dr.mDrawableRight, + dr.mDrawableBottom); + } else { + mTextView.setCompoundDrawables(icon, null, null, null); + } break; } - } else { - mTextView.setCompoundDrawables(null, null, icon, null); + mLastLayoutDirection = layoutDirection; } - if (mError == null) { if (mErrorPopup != null) { if (mErrorPopup.isShowing()) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 8e5ff40..a46481c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -306,7 +306,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private Layout.Alignment mLayoutAlignment; private int mResolvedTextAlignment; - private boolean mResolvedDrawables; + private int mLastLayoutDirection = -1; /** * On some devices the fading edges add a performance penalty if used @@ -8260,16 +8260,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void onResolveDrawables(int layoutDirection) { // No need to resolve twice - if (mResolvedDrawables) { + if (mLastLayoutDirection == layoutDirection) { return; } + mLastLayoutDirection = layoutDirection; // No drawable to resolve if (mDrawables == null) { return; } // No relative drawable to resolve if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) { - mResolvedDrawables = true; return; } @@ -8307,7 +8307,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; } updateDrawablesLayoutDirection(dr, layoutDirection); - mResolvedDrawables = true; } private void updateDrawablesLayoutDirection(Drawables dr, int layoutDirection) { @@ -8329,7 +8328,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @hide */ protected void resetResolvedDrawables() { - mResolvedDrawables = false; + mLastLayoutDirection = -1; } /** diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 3f40f20..f6ae83c 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -16,10 +16,6 @@ package com.android.internal.widget; -import com.android.internal.R; -import com.android.internal.telephony.ITelephony; -import com.google.android.collect.Lists; - import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; import android.content.ContentResolver; @@ -29,7 +25,6 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; -import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -43,6 +38,10 @@ import android.util.Log; import android.view.View; import android.widget.Button; +import com.android.internal.R; +import com.android.internal.telephony.ITelephony; +import com.google.android.collect.Lists; + import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -125,6 +124,11 @@ public class LockPatternUtils { */ public static final int FLAG_BIOMETRIC_WEAK_LIVELINESS = 0x1; + /** + * Pseudo-appwidget id we use to represent the default clock status widget + */ + public static final int ID_DEFAULT_STATUS_WIDGET = -2; + protected final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; protected final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; protected final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen"; @@ -146,6 +150,7 @@ public class LockPatternUtils { private final ContentResolver mContentResolver; private DevicePolicyManager mDevicePolicyManager; private ILockSettings mLockSettingsService; + private int mStickyWidgetIndex = -1; // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils. private static volatile int sCurrentUserId = UserHandle.USER_NULL; @@ -1045,28 +1050,116 @@ public class LockPatternUtils { } } - public int[] getUserDefinedWidgets() { - int appWidgetId = -1; + public int[] getAppWidgets() { String appWidgetIdString = Settings.Secure.getStringForUser( - mContentResolver, Settings.Secure.LOCK_SCREEN_USER_SELECTED_APPWIDGET_ID, + mContentResolver, Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, UserHandle.USER_CURRENT); - if (appWidgetIdString != null) { - appWidgetId = (int) Integer.decode(appWidgetIdString); + String delims = ","; + if (appWidgetIdString != null && appWidgetIdString.length() > 0) { + String[] appWidgetStringIds = appWidgetIdString.split(delims); + int[] appWidgetIds = new int[appWidgetStringIds.length]; + for (int i = 0; i < appWidgetStringIds.length; i++) { + String appWidget = appWidgetStringIds[i]; + try { + appWidgetIds[i] = Integer.decode(appWidget); + } catch (NumberFormatException e) { + Log.d(TAG, "Error when parsing widget id " + appWidget); + return null; + } + } + return appWidgetIds; + } + if (appWidgetIdString == null) { + return new int[] { LockPatternUtils.ID_DEFAULT_STATUS_WIDGET }; + } else { + return new int[0]; + } + } + + private static String combineStrings(int[] list, String separator) { + int listLength = list.length; + + switch (listLength) { + case 0: { + return ""; + } + case 1: { + return Integer.toString(list[0]); + } + } + + int strLength = 0; + int separatorLength = separator.length(); + + String[] stringList = new String[list.length]; + for (int i = 0; i < listLength; i++) { + stringList[i] = Integer.toString(list[i]); + strLength += stringList[i].length(); + if (i < listLength - 1) { + strLength += separatorLength; + } } - return new int[] { appWidgetId }; + StringBuilder sb = new StringBuilder(strLength); + + for (int i = 0; i < listLength; i++) { + sb.append(list[i]); + if (i < listLength - 1) { + sb.append(separator); + } + } + + return sb.toString(); } - public int getStatusWidget() { - int appWidgetId = -1; - String appWidgetIdString = Settings.Secure.getStringForUser( - mContentResolver, Settings.Secure.LOCK_SCREEN_STATUS_APPWIDGET_ID, - UserHandle.USER_CURRENT); - if (appWidgetIdString != null) { - appWidgetId = (int) Integer.decode(appWidgetIdString); + private void writeAppWidgets(int[] appWidgetIds) { + Settings.Secure.putStringForUser(mContentResolver, + Settings.Secure.LOCK_SCREEN_APPWIDGET_IDS, + combineStrings(appWidgetIds, ","), + UserHandle.USER_CURRENT); + } + + // TODO: log an error if this returns false + public boolean addAppWidget(int widgetId, int index) { + int[] widgets = getAppWidgets(); + if (widgets == null) { + return false; + } + if (index < 0 || index > widgets.length) { + return false; } + int[] newWidgets = new int[widgets.length + 1]; + for (int i = 0, j = 0; i < newWidgets.length; i++) { + if (index == i) { + newWidgets[i] = widgetId; + i++; + } + if (i < newWidgets.length) { + newWidgets[i] = widgets[j]; + j++; + } + } + writeAppWidgets(newWidgets); + return true; + } - return appWidgetId; + public boolean removeAppWidget(int widgetId) { + int[] widgets = getAppWidgets(); + + int[] newWidgets = new int[widgets.length - 1]; + for (int i = 0, j = 0; i < widgets.length; i++) { + if (widgets[i] == widgetId) { + // continue... + } else if (j >= newWidgets.length) { + // we couldn't find the widget + return false; + } else { + newWidgets[j] = widgets[i]; + j++; + } + } + writeAppWidgets(newWidgets); + return true; } private long getLong(String secureSettingKey, long defaultValue) { @@ -1218,4 +1311,12 @@ public class LockPatternUtils { return getBoolean(LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS, true); } + public int getStickyWidgetIndex() { + return mStickyWidgetIndex; + } + + public void setStickyWidgetIndex(int stickyWidgetIndex) { + mStickyWidgetIndex = stickyWidgetIndex; + } + } diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java index 0f49776..b7f64ec 100644 --- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java +++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java @@ -256,11 +256,8 @@ public class GlowPadView extends View { setDirectionDescriptionsResourceId(resourceId); } - a.recycle(); + mGravity = a.getInt(R.styleable.GlowPadView_gravity, Gravity.TOP); - // Use gravity attribute from LinearLayout - a = context.obtainStyledAttributes(attrs, android.R.styleable.LinearLayout); - mGravity = a.getInt(android.R.styleable.LinearLayout_gravity, Gravity.TOP); a.recycle(); setVibrateEnabled(mVibrationDuration > 0); |
