summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/Presentation.java89
-rw-r--r--core/java/android/hardware/display/DisplayManager.java72
-rw-r--r--core/java/android/os/UserManager.java17
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/view/Display.java103
-rw-r--r--core/java/android/view/DisplayInfo.java27
-rw-r--r--core/java/android/view/HardwareRenderer.java53
-rw-r--r--core/java/android/view/View.java17
-rw-r--r--core/java/android/view/ViewGroup.java1
-rw-r--r--core/java/android/widget/Editor.java29
-rw-r--r--core/java/android/widget/TextView.java9
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java139
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/GlowPadView.java5
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) $&#123;
+ * Display presentationDisplay = route.getPresentationDisplay();
+ * if (presentationDisplay != null) $&#123;
+ * Presentation presentation = new MyPresentation(context, presentationDisplay);
+ * presentation.show();
+ * $&#125;
+ * $&#125;
+ * }
+ * <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) $&#123;
+ * // 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();
+ * $&#125;
+ * }
+ * <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);