summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ActivityManager.java7
-rw-r--r--core/java/android/app/BackStackRecord.java92
-rw-r--r--core/java/android/app/Notification.java91
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java17
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl12
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl3
-rw-r--r--core/java/android/os/UserManager.java19
-rw-r--r--core/java/android/service/trust/TrustAgentService.java29
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java3
-rw-r--r--core/java/android/transition/ChangeTransform.java101
-rw-r--r--core/java/android/view/IWindowSession.aidl9
-rw-r--r--core/java/android/view/SurfaceView.java3
-rw-r--r--core/java/android/view/ThreadedRenderer.java8
-rw-r--r--core/java/android/view/ViewRootImpl.java2
-rw-r--r--core/java/android/view/WindowManagerPolicy.java11
-rw-r--r--core/java/android/widget/DatePickerCalendarDelegate.java41
-rw-r--r--core/java/android/widget/DatePickerController.java7
-rw-r--r--core/java/android/widget/DateTimeView.java126
-rw-r--r--core/java/android/widget/DayPickerView.java121
-rw-r--r--core/java/android/widget/PopupWindow.java84
-rw-r--r--core/java/android/widget/SimpleMonthAdapter.java77
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java17
-rw-r--r--core/java/com/android/internal/util/StateMachine.java16
-rw-r--r--core/java/com/android/internal/widget/ILockSettingsObserver.aidl9
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java16
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtilsCache.java29
26 files changed, 633 insertions, 317 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a285932..7a636db 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -213,6 +213,13 @@ public class ActivityManager {
public static final int BROADCAST_STICKY_CANT_HAVE_PERMISSION = -1;
/**
+ * Result for IActivityManager.broadcastIntent: trying to send a broadcast
+ * to a stopped user. Fail.
+ * @hide
+ */
+ public static final int BROADCAST_FAILED_USER_STOPPED = -2;
+
+ /**
* Type for IActivityManaqer.getIntentSender: this PendingIntent is
* for a sendBroadcast operation.
* @hide
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 0092ee7..2784d44 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -38,6 +38,7 @@ import android.view.ViewTreeObserver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
final class BackStackState implements Parcelable {
final int[] mOps;
@@ -1055,7 +1056,7 @@ final class BackStackRecord extends FragmentTransaction implements
}
private static ArrayList<View> captureExitingViews(Transition exitTransition,
- Fragment outFragment, ArrayMap<String, View> namedViews) {
+ Fragment outFragment, ArrayMap<String, View> namedViews, View nonExistentView) {
ArrayList<View> viewList = null;
if (exitTransition != null) {
viewList = new ArrayList<View>();
@@ -1064,7 +1065,10 @@ final class BackStackRecord extends FragmentTransaction implements
if (namedViews != null) {
viewList.removeAll(namedViews.values());
}
- addTargets(exitTransition, viewList);
+ if (!viewList.isEmpty()) {
+ viewList.add(nonExistentView);
+ addTargets(exitTransition, viewList);
+ }
}
return viewList;
}
@@ -1132,11 +1136,8 @@ final class BackStackRecord extends FragmentTransaction implements
namedViews = mapSharedElementsIn(state, isBack, inFragment);
removeTargets(sharedElementTransition, sharedElementTargets);
sharedElementTargets.clear();
- if (namedViews.isEmpty()) {
- sharedElementTargets.add(state.nonExistentView);
- } else {
- sharedElementTargets.addAll(namedViews.values());
- }
+ sharedElementTargets.add(state.nonExistentView);
+ sharedElementTargets.addAll(namedViews.values());
addTargets(sharedElementTransition, sharedElementTargets);
@@ -1153,6 +1154,9 @@ final class BackStackRecord extends FragmentTransaction implements
if (namedViews != null) {
enteringViews.removeAll(namedViews.values());
}
+ enteringViews.add(state.nonExistentView);
+ // We added this earlier to prevent any views being targeted.
+ enterTransition.removeTarget(state.nonExistentView);
addTargets(enterTransition, enteringViews);
}
setSharedElementEpicenter(enterTransition, state);
@@ -1293,11 +1297,8 @@ final class BackStackRecord extends FragmentTransaction implements
ArrayList<View> sharedElementTargets = new ArrayList<View>();
if (sharedElementTransition != null) {
namedViews = remapSharedElements(state, outFragment, isBack);
- if (namedViews.isEmpty()) {
- sharedElementTargets.add(state.nonExistentView);
- } else {
- sharedElementTargets.addAll(namedViews.values());
- }
+ sharedElementTargets.add(state.nonExistentView);
+ sharedElementTargets.addAll(namedViews.values());
addTargets(sharedElementTransition, sharedElementTargets);
// Notify the start of the transition.
@@ -1310,7 +1311,7 @@ final class BackStackRecord extends FragmentTransaction implements
}
ArrayList<View> exitingViews = captureExitingViews(exitTransition, outFragment,
- namedViews);
+ namedViews, state.nonExistentView);
if (exitingViews == null || exitingViews.isEmpty()) {
exitTransition = null;
}
@@ -1388,20 +1389,69 @@ final class BackStackRecord extends FragmentTransaction implements
}
}
- private static void removeTargets(Transition transition, ArrayList<View> views) {
- int numViews = views.size();
- for (int i = 0; i < numViews; i++) {
- transition.removeTarget(views.get(i));
+ /**
+ * This method removes the views from transitions that target ONLY those views.
+ * The views list should match those added in addTargets and should contain
+ * one view that is not in the view hierarchy (state.nonExistentView).
+ */
+ public static void removeTargets(Transition transition, ArrayList<View> views) {
+ if (transition instanceof TransitionSet) {
+ TransitionSet set = (TransitionSet) transition;
+ int numTransitions = set.getTransitionCount();
+ for (int i = 0; i < numTransitions; i++) {
+ Transition child = set.getTransitionAt(i);
+ removeTargets(child, views);
+ }
+ } else if (!hasSimpleTarget(transition)) {
+ List<View> targets = transition.getTargets();
+ if (targets != null && targets.size() == views.size() &&
+ targets.containsAll(views)) {
+ // We have an exact match. We must have added these earlier in addTargets
+ for (int i = views.size() - 1; i >= 0; i--) {
+ transition.removeTarget(views.get(i));
+ }
+ }
}
}
- private static void addTargets(Transition transition, ArrayList<View> views) {
- int numViews = views.size();
- for (int i = 0; i < numViews; i++) {
- transition.addTarget(views.get(i));
+ /**
+ * This method adds views as targets to the transition, but only if the transition
+ * doesn't already have a target. It is best for views to contain one View object
+ * that does not exist in the view hierarchy (state.nonExistentView) so that
+ * when they are removed later, a list match will suffice to remove the targets.
+ * Otherwise, if you happened to have targeted the exact views for the transition,
+ * the removeTargets call will remove them unexpectedly.
+ */
+ public static void addTargets(Transition transition, ArrayList<View> views) {
+ if (transition instanceof TransitionSet) {
+ TransitionSet set = (TransitionSet) transition;
+ int numTransitions = set.getTransitionCount();
+ for (int i = 0; i < numTransitions; i++) {
+ Transition child = set.getTransitionAt(i);
+ addTargets(child, views);
+ }
+ } else if (!hasSimpleTarget(transition)) {
+ List<View> targets = transition.getTargets();
+ if (isNullOrEmpty(targets)) {
+ // We can just add the target views
+ int numViews = views.size();
+ for (int i = 0; i < numViews; i++) {
+ transition.addTarget(views.get(i));
+ }
+ }
}
}
+ private static boolean hasSimpleTarget(Transition transition) {
+ return !isNullOrEmpty(transition.getTargetIds()) ||
+ !isNullOrEmpty(transition.getTargetNames()) ||
+ !isNullOrEmpty(transition.getTargetTypes());
+ }
+
+ private static boolean isNullOrEmpty(List list) {
+ return list == null || list.isEmpty();
+ }
+
/**
* Remaps a name-to-View map, substituting different names for keys.
*
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c65f017..dfe5cf5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1113,7 +1113,11 @@ public class Notification implements Parcelable
/** Notification action extra which contains wearable extensions */
private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
+ // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
private static final String KEY_FLAGS = "flags";
+ private static final String KEY_IN_PROGRESS_LABEL = "inProgressLabel";
+ private static final String KEY_CONFIRM_LABEL = "confirmLabel";
+ private static final String KEY_CANCEL_LABEL = "cancelLabel";
// Flags bitwise-ored to mFlags
private static final int FLAG_AVAILABLE_OFFLINE = 0x1;
@@ -1123,6 +1127,10 @@ public class Notification implements Parcelable
private int mFlags = DEFAULT_FLAGS;
+ private CharSequence mInProgressLabel;
+ private CharSequence mConfirmLabel;
+ private CharSequence mCancelLabel;
+
/**
* Create a {@link android.app.Notification.Action.WearableExtender} with default
* options.
@@ -1139,6 +1147,9 @@ public class Notification implements Parcelable
Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS);
if (wearableBundle != null) {
mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
+ mInProgressLabel = wearableBundle.getCharSequence(KEY_IN_PROGRESS_LABEL);
+ mConfirmLabel = wearableBundle.getCharSequence(KEY_CONFIRM_LABEL);
+ mCancelLabel = wearableBundle.getCharSequence(KEY_CANCEL_LABEL);
}
}
@@ -1154,6 +1165,15 @@ public class Notification implements Parcelable
if (mFlags != DEFAULT_FLAGS) {
wearableBundle.putInt(KEY_FLAGS, mFlags);
}
+ if (mInProgressLabel != null) {
+ wearableBundle.putCharSequence(KEY_IN_PROGRESS_LABEL, mInProgressLabel);
+ }
+ if (mConfirmLabel != null) {
+ wearableBundle.putCharSequence(KEY_CONFIRM_LABEL, mConfirmLabel);
+ }
+ if (mCancelLabel != null) {
+ wearableBundle.putCharSequence(KEY_CANCEL_LABEL, mCancelLabel);
+ }
builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
return builder;
@@ -1163,6 +1183,9 @@ public class Notification implements Parcelable
public WearableExtender clone() {
WearableExtender that = new WearableExtender();
that.mFlags = this.mFlags;
+ that.mInProgressLabel = this.mInProgressLabel;
+ that.mConfirmLabel = this.mConfirmLabel;
+ that.mCancelLabel = this.mCancelLabel;
return that;
}
@@ -1194,6 +1217,72 @@ public class Notification implements Parcelable
mFlags &= ~mask;
}
}
+
+ /**
+ * Set a label to display while the wearable is preparing to automatically execute the
+ * action. This is usually a 'ing' verb ending in ellipsis like "Sending..."
+ *
+ * @param label the label to display while the action is being prepared to execute
+ * @return this object for method chaining
+ */
+ public WearableExtender setInProgressLabel(CharSequence label) {
+ mInProgressLabel = label;
+ return this;
+ }
+
+ /**
+ * Get the label to display while the wearable is preparing to automatically execute
+ * the action. This is usually a 'ing' verb ending in ellipsis like "Sending..."
+ *
+ * @return the label to display while the action is being prepared to execute
+ */
+ public CharSequence getInProgressLabel() {
+ return mInProgressLabel;
+ }
+
+ /**
+ * Set a label to display to confirm that the action should be executed.
+ * This is usually an imperative verb like "Send".
+ *
+ * @param label the label to confirm the action should be executed
+ * @return this object for method chaining
+ */
+ public WearableExtender setConfirmLabel(CharSequence label) {
+ mConfirmLabel = label;
+ return this;
+ }
+
+ /**
+ * Get the label to display to confirm that the action should be executed.
+ * This is usually an imperative verb like "Send".
+ *
+ * @return the label to confirm the action should be executed
+ */
+ public CharSequence getConfirmLabel() {
+ return mConfirmLabel;
+ }
+
+ /**
+ * Set a label to display to cancel the action.
+ * This is usually an imperative verb, like "Cancel".
+ *
+ * @param label the label to display to cancel the action
+ * @return this object for method chaining
+ */
+ public WearableExtender setCancelLabel(CharSequence label) {
+ mCancelLabel = label;
+ return this;
+ }
+
+ /**
+ * Get the label to display to cancel the action.
+ * This is usually an imperative verb like "Cancel".
+ *
+ * @return the label to display to cancel the action
+ */
+ public CharSequence getCancelLabel() {
+ return mCancelLabel;
+ }
}
}
@@ -4356,7 +4445,7 @@ public class Notification implements Parcelable
/** Notification extra which contains wearable extensions */
private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
- // Keys within EXTRA_WEARABLE_OPTIONS for wearable options.
+ // Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
private static final String KEY_ACTIONS = "actions";
private static final String KEY_FLAGS = "flags";
private static final String KEY_DISPLAY_INTENT = "displayIntent";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d3ff79d..9157b1b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -62,13 +62,16 @@ import java.util.Collections;
import java.util.List;
/**
- * Public interface for managing policies enforced on a device. Most clients
- * of this class must have published a {@link DeviceAdminReceiver} that the user
- * has currently enabled.
+ * Public interface for managing policies enforced on a device. Most clients of this class must be
+ * registered with the system as a
+ * <a href={@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
+ * a device administrator may be registered as either a profile or device owner. A given method is
+ * accessible to all device administrators unless the documentation for that method specifies that
+ * it is restricted to either device or profile owners.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
- * <p>For more information about managing policies for device adminstration, read the
+ * <p>For more information about managing policies for device administration, read the
* <a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
* developer guide.</p>
* </div>
@@ -2586,6 +2589,10 @@ public class DevicePolicyManager {
* <p>The application restrictions are only made visible to the target application and the
* profile or device owner.
*
+ * <p>If the restrictions are not available yet, but may be applied in the near future,
+ * the admin can notify the target application of that by adding
+ * {@link UserManager#KEY_RESTRICTIONS_PENDING} to the settings parameter.
+ *
* <p>The calling device admin must be a profile or device owner; if it is not, a security
* exception will be thrown.
*
@@ -2593,6 +2600,8 @@ public class DevicePolicyManager {
* @param packageName The name of the package to update restricted settings for.
* @param settings A {@link Bundle} to be parsed by the receiving application, conveying a new
* set of active restrictions.
+ *
+ * @see UserManager#KEY_RESTRICTIONS_PENDING
*/
public void setApplicationRestrictions(ComponentName admin, String packageName,
Bundle settings) {
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 8a44c8e..0a2d4f5 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -291,4 +291,16 @@ interface IBackupManager {
* {@hide}
*/
void opComplete(int token);
+
+ /**
+ * Make the device's backup and restore machinery (in)active. When it is inactive,
+ * the device will not perform any backup operations, nor will it deliver data for
+ * restore, although clients can still safely call BackupManager methods.
+ *
+ * @param whichUser User handle of the defined user whose backup active state
+ * is to be adjusted.
+ * @param makeActive {@code true} when backup services are to be made active;
+ * {@code false} otherwise.
+ */
+ void setBackupServiceActive(int whichUser, boolean makeActive);
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 992f601..cd4535a 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -98,4 +98,7 @@ interface IBluetooth
boolean isActivityAndEnergyReportingSupported();
void getActivityEnergyInfoFromController();
BluetoothActivityEnergyInfo reportActivityInfo();
+
+ // for dumpsys support
+ String dump();
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 3234e77..bd6eeea 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -367,10 +367,27 @@ public class UserManager {
* <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
- * @hide
*/
public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
+ /**
+ * Application restriction key that is used to indicate the pending arrival
+ * of real restrictions for the app.
+ *
+ * <p>
+ * Applications that support restrictions should check for the presence of this key.
+ * A <code>true</code> value indicates that restrictions may be applied in the near
+ * future but are not available yet. It is the responsibility of any
+ * management application that sets this flag to update it when the final
+ * restrictions are enforced.
+ *
+ * <p/>Key for application restrictions.
+ * <p/>Type: Boolean
+ * @see android.app.admin.DevicePolicyManager#addApplicationRestriction()
+ * @see android.app.admin.DevicePolicyManager#getApplicationRestriction()
+ */
+ public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 00d60c0..d6c997f 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -94,31 +94,6 @@ public class TrustAgentService extends Service {
private static final int MSG_TRUST_TIMEOUT = 3;
/**
- * Container class for a list of configuration options and helper methods
- */
- public static final class Configuration {
- public final List<PersistableBundle> options;
- public Configuration(List<PersistableBundle> opts) {
- options = opts;
- }
-
- /**
- * Very basic method to determine if all bundles have the given feature, regardless
- * of type.
- * @param option String to search for.
- * @return true if found in all bundles.
- */
- public boolean hasOption(String option) {
- if (options == null || options.size() == 0) return false;
- final int N = options.size();
- for (int i = 0; i < N; i++) {
- if (!options.get(i).containsKey(option)) return false;
- }
- return true;
- }
- }
-
- /**
* Class containing raw data for a given configuration request.
*/
private static final class ConfigurationData {
@@ -147,7 +122,7 @@ public class TrustAgentService extends Service {
break;
case MSG_CONFIGURE:
ConfigurationData data = (ConfigurationData) msg.obj;
- boolean result = onConfigure(new Configuration(data.options));
+ boolean result = onConfigure(data.options);
try {
synchronized (mLock) {
mCallback.onConfigureCompleted(result, data.token);
@@ -212,7 +187,7 @@ public class TrustAgentService extends Service {
* @param options bundle containing all options or null if none.
* @return true if the {@link TrustAgentService} supports configuration options.
*/
- public boolean onConfigure(Configuration options) {
+ public boolean onConfigure(List<PersistableBundle> options) {
return false;
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 26e9a30..ceaf5f8 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -675,7 +675,8 @@ public abstract class WallpaperService extends Service {
com.android.internal.R.style.Animation_Wallpaper;
mInputChannel = new InputChannel();
if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
- Display.DEFAULT_DISPLAY, mContentInsets, mInputChannel) < 0) {
+ Display.DEFAULT_DISPLAY, mContentInsets, mStableInsets,
+ mInputChannel) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index 3fd28a6..a159b40 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -17,11 +17,14 @@ package android.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.FloatArrayEvaluator;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
+import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Property;
import android.view.GhostView;
@@ -56,16 +59,35 @@ public class ChangeTransform extends Transition {
PROPNAME_PARENT_MATRIX,
};
- private static final Property<View, Matrix> ANIMATION_MATRIX_PROPERTY =
- new Property<View, Matrix>(Matrix.class, "animationMatrix") {
+ /**
+ * This property sets the animation matrix properties that are not translations.
+ */
+ private static final Property<PathAnimatorMatrix, float[]> NON_TRANSLATIONS_PROPERTY =
+ new Property<PathAnimatorMatrix, float[]>(float[].class, "nonTranslations") {
@Override
- public Matrix get(View object) {
+ public float[] get(PathAnimatorMatrix object) {
return null;
}
@Override
- public void set(View object, Matrix value) {
- object.setAnimationMatrix(value);
+ public void set(PathAnimatorMatrix object, float[] value) {
+ object.setValues(value);
+ }
+ };
+
+ /**
+ * This property sets the translation animation matrix properties.
+ */
+ private static final Property<PathAnimatorMatrix, PointF> TRANSLATIONS_PROPERTY =
+ new Property<PathAnimatorMatrix, PointF>(PointF.class, "translations") {
+ @Override
+ public PointF get(PathAnimatorMatrix object) {
+ return null;
+ }
+
+ @Override
+ public void set(PathAnimatorMatrix object, PointF value) {
+ object.setTranslation(value);
}
};
@@ -261,8 +283,23 @@ public class ChangeTransform extends Transition {
final View view = endValues.view;
setIdentityTransforms(view);
- ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY,
- new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
+ final float[] startMatrixValues = new float[9];
+ startMatrix.getValues(startMatrixValues);
+ final float[] endMatrixValues = new float[9];
+ endMatrix.getValues(endMatrixValues);
+ final PathAnimatorMatrix pathAnimatorMatrix =
+ new PathAnimatorMatrix(view, startMatrixValues);
+
+ PropertyValuesHolder valuesProperty = PropertyValuesHolder.ofObject(
+ NON_TRANSLATIONS_PROPERTY, new FloatArrayEvaluator(new float[9]),
+ startMatrixValues, endMatrixValues);
+ Path path = getPathMotion().getPath(startMatrixValues[Matrix.MTRANS_X],
+ startMatrixValues[Matrix.MTRANS_Y], endMatrixValues[Matrix.MTRANS_X],
+ endMatrixValues[Matrix.MTRANS_Y]);
+ PropertyValuesHolder translationProperty = PropertyValuesHolder.ofObject(
+ TRANSLATIONS_PROPERTY, null, path);
+ ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(pathAnimatorMatrix,
+ valuesProperty, translationProperty);
final Matrix finalEndMatrix = endMatrix;
@@ -285,14 +322,13 @@ public class ChangeTransform extends Transition {
view.setTagInternal(R.id.parentMatrix, null);
}
}
- ANIMATION_MATRIX_PROPERTY.set(view, null);
+ view.setAnimationMatrix(null);
transforms.restore(view);
}
@Override
public void onAnimationPause(Animator animation) {
- ValueAnimator animator = (ValueAnimator) animation;
- Matrix currentMatrix = (Matrix) animator.getAnimatedValue();
+ Matrix currentMatrix = pathAnimatorMatrix.getMatrix();
setCurrentMatrix(currentMatrix);
}
@@ -457,4 +493,47 @@ public class ChangeTransform extends Transition {
mGhostView.setVisibility(View.VISIBLE);
}
}
+
+ /**
+ * PathAnimatorMatrix allows the translations and the rest of the matrix to be set
+ * separately. This allows the PathMotion to affect the translations while scale
+ * and rotation are evaluated separately.
+ */
+ private static class PathAnimatorMatrix {
+ private final Matrix mMatrix = new Matrix();
+ private final View mView;
+ private final float[] mValues;
+ private float mTranslationX;
+ private float mTranslationY;
+
+ public PathAnimatorMatrix(View view, float[] values) {
+ mView = view;
+ mValues = values.clone();
+ mTranslationX = mValues[Matrix.MTRANS_X];
+ mTranslationY = mValues[Matrix.MTRANS_Y];
+ setAnimationMatrix();
+ }
+
+ public void setValues(float[] values) {
+ System.arraycopy(values, 0, mValues, 0, values.length);
+ setAnimationMatrix();
+ }
+
+ public void setTranslation(PointF translation) {
+ mTranslationX = translation.x;
+ mTranslationY = translation.y;
+ setAnimationMatrix();
+ }
+
+ private void setAnimationMatrix() {
+ mValues[Matrix.MTRANS_X] = mTranslationX;
+ mValues[Matrix.MTRANS_Y] = mTranslationY;
+ mMatrix.setValues(mValues);
+ mView.setAnimationMatrix(mMatrix);
+ }
+
+ public Matrix getMatrix() {
+ return mMatrix;
+ }
+ }
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 037ed28..7b13e84 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -36,15 +36,16 @@ import android.view.Surface;
*/
interface IWindowSession {
int add(IWindow window, int seq, in WindowManager.LayoutParams attrs,
- in int viewVisibility, out Rect outContentInsets,
+ in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets,
out InputChannel outInputChannel);
int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
- out InputChannel outInputChannel);
+ out Rect outStableInsets, out InputChannel outInputChannel);
int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
- in int viewVisibility, out Rect outContentInsets);
+ in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets);
int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
- in int viewVisibility, in int layerStackId, out Rect outContentInsets);
+ in int viewVisibility, in int layerStackId, out Rect outContentInsets,
+ out Rect outStableInsets);
void remove(IWindow window);
/**
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index afc804c..49be57d 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -496,7 +496,8 @@ public class SurfaceView extends View {
mLayout.type = mWindowType;
mLayout.gravity = Gravity.START|Gravity.TOP;
mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
- mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets);
+ mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
+ mStableInsets);
}
boolean realSizeChanged;
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 00a8884..5579c13 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -66,6 +66,8 @@ public class ThreadedRenderer extends HardwareRenderer {
private static final int SYNC_OK = 0;
// Needs a ViewRoot invalidate
private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0;
+ // Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
+ private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1;
private static final String[] VISUALIZERS = {
PROFILE_PROPERTY_VISUALIZE_BARS,
@@ -336,6 +338,12 @@ public class ThreadedRenderer extends HardwareRenderer {
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
recordDuration, view.getResources().getDisplayMetrics().density);
+ if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
+ setEnabled(false);
+ // Invalidate since we failed to draw. This should fetch a Surface
+ // if it is still needed or do nothing if we are no longer drawing
+ attachInfo.mViewRootImpl.invalidate();
+ }
if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
attachInfo.mViewRootImpl.invalidate();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ea0a077..5d2a24b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -526,7 +526,7 @@ public final class ViewRootImpl implements ViewParent,
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
- mAttachInfo.mContentInsets, mInputChannel);
+ mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 673f075..b8e94ee 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -865,12 +865,15 @@ public interface WindowManagerPolicy {
* Return the insets for the areas covered by system windows. These values
* are computed on the most recent layout, so they are not guaranteed to
* be correct.
- *
+ *
* @param attrs The LayoutParams of the window.
- * @param contentInset The areas covered by system windows, expressed as positive insets
- *
+ * @param outContentInsets The areas covered by system windows, expressed as positive insets.
+ * @param outStableInsets The areas covered by stable system windows irrespective of their
+ * current visibility. Expressed as positive insets.
+ *
*/
- public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset);
+ public void getInsetHintLw(WindowManager.LayoutParams attrs, Rect outContentInsets,
+ Rect outStableInsets);
/**
* Called when layout of the windows is finished. After this function has
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 64c81e0..cf3dbab 100644
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -183,8 +183,11 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
mHeaderYearTextView.getTextColors(), R.attr.state_selected,
headerSelectedTextColor));
- mDayPickerView = new DayPickerView(mContext, this);
+ mDayPickerView = new DayPickerView(mContext);
+ mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
mDayPickerView.setRange(mMinDate, mMaxDate);
+ mDayPickerView.setDay(mCurrentDate);
+ mDayPickerView.setOnDaySelectedListener(mOnDaySelectedListener);
mYearPickerView = new YearPickerView(mContext);
mYearPickerView.init(this);
@@ -333,7 +336,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
switch (viewIndex) {
case MONTH_AND_DAY_VIEW:
- mDayPickerView.onDateChanged();
+ mDayPickerView.setDay(getSelectedDay());
if (mCurrentView != viewIndex) {
mMonthAndDayLayout.setSelected(true);
mHeaderYearTextView.setSelected(false);
@@ -445,6 +448,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
@Override
public void setFirstDayOfWeek(int firstDayOfWeek) {
mFirstDayOfWeek = firstDayOfWeek;
+
+ mDayPickerView.setFirstDayOfWeek(firstDayOfWeek);
}
@Override
@@ -606,19 +611,12 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
}
}
- @Override
- public void onDayOfMonthSelected(int year, int month, int day) {
- mCurrentDate.set(Calendar.YEAR, year);
- mCurrentDate.set(Calendar.MONTH, month);
- mCurrentDate.set(Calendar.DAY_OF_MONTH, day);
- updatePickers();
- updateDisplay(true);
- }
-
private void updatePickers() {
for (OnDateChangedListener listener : mListeners) {
listener.onDateChanged();
}
+
+ mDayPickerView.setDay(getSelectedDay());
}
@Override
@@ -627,11 +625,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
}
@Override
- public void unregisterOnDateChangedListener(OnDateChangedListener listener) {
- mListeners.remove(listener);
- }
-
- @Override
public Calendar getSelectedDay() {
return mCurrentDate;
}
@@ -652,6 +645,22 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i
}
/**
+ * Listener called when the user selects a day in the day picker view.
+ */
+ private final DayPickerView.OnDaySelectedListener
+ mOnDaySelectedListener = new DayPickerView.OnDaySelectedListener() {
+ @Override
+ public void onDaySelected(DayPickerView view, Calendar day) {
+ mCurrentDate.setTimeInMillis(day.getTimeInMillis());
+
+ updatePickers();
+ updateDisplay(true);
+
+ tryVibrate();
+ }
+ };
+
+ /**
* Class for managing state storing/restoring.
*/
private static class SavedState extends View.BaseSavedState {
diff --git a/core/java/android/widget/DatePickerController.java b/core/java/android/widget/DatePickerController.java
index ea6ec61..8f809ba 100644
--- a/core/java/android/widget/DatePickerController.java
+++ b/core/java/android/widget/DatePickerController.java
@@ -27,16 +27,9 @@ interface DatePickerController {
void onYearSelected(int year);
- void onDayOfMonthSelected(int year, int month, int day);
-
void registerOnDateChangedListener(OnDateChangedListener listener);
- void unregisterOnDateChangedListener(OnDateChangedListener listener);
-
Calendar getSelectedDay();
- void setFirstDayOfWeek(int firstDayOfWeek);
- int getFirstDayOfWeek();
-
void tryVibrate();
}
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 45d1403..443884a 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -32,6 +32,7 @@ import android.widget.RemoteViews.RemoteView;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
//
@@ -62,8 +63,8 @@ public class DateTimeView extends TextView {
int mLastDisplay = -1;
DateFormat mLastFormat;
- private boolean mAttachedToWindow;
private long mUpdateTimeMillis;
+ private static final ThreadLocal<ReceiverInfo> sReceiverInfo = new ThreadLocal<ReceiverInfo>();
public DateTimeView(Context context) {
super(context);
@@ -76,15 +77,21 @@ public class DateTimeView extends TextView {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- registerReceivers();
- mAttachedToWindow = true;
+ ReceiverInfo ri = sReceiverInfo.get();
+ if (ri == null) {
+ ri = new ReceiverInfo();
+ sReceiverInfo.set(ri);
+ }
+ ri.addView(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- unregisterReceivers();
- mAttachedToWindow = false;
+ final ReceiverInfo ri = sReceiverInfo.get();
+ if (ri != null) {
+ ri.removeView(this);
+ }
}
@android.view.RemotableViewMethod
@@ -204,49 +211,86 @@ public class DateTimeView extends TextView {
}
}
- private void registerReceivers() {
- Context context = getContext();
+ void clearFormatAndUpdate() {
+ mLastFormat = null;
+ update();
+ }
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_TIME_TICK);
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- context.registerReceiver(mBroadcastReceiver, filter);
+ private static class ReceiverInfo {
+ private final ArrayList<DateTimeView> mAttachedViews = new ArrayList<DateTimeView>();
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_TIME_TICK.equals(action)) {
+ if (System.currentTimeMillis() < getSoonestUpdateTime()) {
+ // The update() function takes a few milliseconds to run because of
+ // all of the time conversions it needs to do, so we can't do that
+ // every minute.
+ return;
+ }
+ }
+ // ACTION_TIME_CHANGED can also signal a change of 12/24 hr. format.
+ updateAll();
+ }
+ };
- Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT);
- context.getContentResolver().registerContentObserver(uri, true, mContentObserver);
- }
+ private final ContentObserver mObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateAll();
+ }
+ };
- private void unregisterReceivers() {
- Context context = getContext();
- context.unregisterReceiver(mBroadcastReceiver);
- context.getContentResolver().unregisterContentObserver(mContentObserver);
- }
+ public void addView(DateTimeView v) {
+ final boolean register = mAttachedViews.isEmpty();
+ mAttachedViews.add(v);
+ if (register) {
+ register(v.getContext().getApplicationContext());
+ }
+ }
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_TIME_TICK.equals(action)) {
- if (System.currentTimeMillis() < mUpdateTimeMillis) {
- // The update() function takes a few milliseconds to run because of
- // all of the time conversions it needs to do, so we can't do that
- // every minute.
- return;
+ public void removeView(DateTimeView v) {
+ mAttachedViews.remove(v);
+ if (mAttachedViews.isEmpty()) {
+ unregister(v.getContext().getApplicationContext());
+ }
+ }
+
+ void updateAll() {
+ final int count = mAttachedViews.size();
+ for (int i = 0; i < count; i++) {
+ mAttachedViews.get(i).clearFormatAndUpdate();
+ }
+ }
+
+ long getSoonestUpdateTime() {
+ long result = Long.MAX_VALUE;
+ final int count = mAttachedViews.size();
+ for (int i = 0; i < count; i++) {
+ final long time = mAttachedViews.get(i).mUpdateTimeMillis;
+ if (time < result) {
+ result = time;
}
}
- // ACTION_TIME_CHANGED can also signal a change of 12/24 hr. format.
- mLastFormat = null;
- update();
+ return result;
}
- };
- private ContentObserver mContentObserver = new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- mLastFormat = null;
- update();
+ void register(Context context) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ context.registerReceiver(mReceiver, filter);
+
+ final Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT);
+ context.getContentResolver().registerContentObserver(uri, true, mObserver);
}
- };
+
+ void unregister(Context context) {
+ context.unregisterReceiver(mReceiver);
+ context.getContentResolver().unregisterContentObserver(mObserver);
+ }
+ }
}
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index f9544d0..6cb1c9d 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -16,14 +16,10 @@
package android.widget;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
-import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
-import android.util.AttributeSet;
import android.util.Log;
import android.util.MathUtils;
import android.view.View;
@@ -38,9 +34,7 @@ import java.util.Locale;
/**
* This displays a list of months in a calendar format with selectable days.
*/
-class DayPickerView extends ListView implements AbsListView.OnScrollListener,
- OnDateChangedListener {
-
+class DayPickerView extends ListView implements AbsListView.OnScrollListener {
private static final String TAG = "DayPickerView";
// How long the GoTo fling animation should last
@@ -49,12 +43,14 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
// How long to wait after receiving an onScrollStateChanged notification before acting on it
private static final int SCROLL_CHANGE_DELAY = 40;
- private static int LIST_TOP_OFFSET = -1; // so that the top line will be under the separator
+ // so that the top line will be under the separator
+ private static final int LIST_TOP_OFFSET = -1;
- private SimpleDateFormat mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
+ private final SimpleMonthAdapter mAdapter = new SimpleMonthAdapter(getContext());
+
+ private final ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(this);
- // These affect the scroll speed and feel
- private float mFriction = 1.0f;
+ private SimpleDateFormat mYearFormat = new SimpleDateFormat("yyyy", Locale.getDefault());
// highlighted time
private Calendar mSelectedDay = Calendar.getInstance();
@@ -62,7 +58,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
private Calendar mMinDate = Calendar.getInstance();
private Calendar mMaxDate = Calendar.getInstance();
- private SimpleMonthAdapter mAdapter;
+ private OnDaySelectedListener mOnDaySelectedListener;
// which month should be displayed/highlighted [0-11]
private int mCurrentMonthDisplayed;
@@ -71,34 +67,27 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
// used for tracking what state listview is in
private int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE;
- private DatePickerController mController;
private boolean mPerformingScroll;
- private ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(this);
-
- public DayPickerView(Context context, DatePickerController controller) {
+ public DayPickerView(Context context) {
super(context);
- init();
- setController(controller);
- }
-
- public void setController(DatePickerController controller) {
- if (mController != null) {
- mController.unregisterOnDateChangedListener(this);
- }
- mController = controller;
- mController.registerOnDateChangedListener(this);
- setUpAdapter();
setAdapter(mAdapter);
- onDateChanged();
- }
-
- public void init() {
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
setDrawSelectorOnTop(false);
-
setUpListView();
+
+ goTo(mSelectedDay, false, true, true);
+
+ mAdapter.setOnDaySelectedListener(mProxyOnDaySelectedListener);
+ }
+
+ public void setDay(Calendar day) {
+ goTo(day, false, true, true);
+ }
+
+ public void setFirstDayOfWeek(int firstDayOfWeek) {
+ mAdapter.setFirstDayOfWeek(firstDayOfWeek);
}
public void setRange(Calendar minDate, Calendar maxDate) {
@@ -113,54 +102,19 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
}
/**
- * Constrains the supplied calendar to stay within the min and max
- * calendars, returning <code>true</code> if the supplied calendar
- * was modified.
+ * Sets the listener to call when the user selects a day.
*
- * @param value The calendar to constrain
- * @param min The minimum calendar
- * @param max The maximum calendar
- * @return True if <code>value</code> was modified
- */
- private boolean constrainCalendar(Calendar value, Calendar min, Calendar max) {
- if (value.compareTo(min) < 0) {
- value.setTimeInMillis(min.getTimeInMillis());
- return true;
- }
-
- if (value.compareTo(max) > 0) {
- value.setTimeInMillis(max.getTimeInMillis());
- return true;
- }
-
- return false;
- }
-
- public void onChange() {
- setUpAdapter();
- setAdapter(mAdapter);
- }
-
- /**
- * Creates a new adapter if necessary and sets up its parameters. Override
- * this method to provide a custom adapter.
+ * @param listener The listener to call.
*/
- protected void setUpAdapter() {
- if (mAdapter == null) {
- mAdapter = new SimpleMonthAdapter(getContext(), mController);
- } else {
- mAdapter.setSelectedDay(mSelectedDay);
- mAdapter.notifyDataSetChanged();
- }
- // refresh the view with the new parameters
- mAdapter.notifyDataSetChanged();
+ public void setOnDaySelectedListener(OnDaySelectedListener listener) {
+ mOnDaySelectedListener = listener;
}
/*
* Sets all the required fields for the list view. Override this method to
* set a different list view behavior.
*/
- protected void setUpListView() {
+ private void setUpListView() {
// Transparent background on scroll
setCacheColorHint(0);
// No dividers
@@ -173,7 +127,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
setOnScrollListener(this);
setFadingEdgeLength(0);
// Make the scrolling behavior nicer
- setFriction(ViewConfiguration.getScrollFriction() * mFriction);
+ setFriction(ViewConfiguration.getScrollFriction());
}
private int getDiffMonths(Calendar start, Calendar end) {
@@ -203,7 +157,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
* visible
* @return Whether or not the view animated to the new location
*/
- public boolean goTo(Calendar day, boolean animate, boolean setSelected, boolean forceScroll) {
+ private boolean goTo(Calendar day, boolean animate, boolean setSelected, boolean forceScroll) {
// Set the selected day
if (setSelected) {
@@ -392,11 +346,6 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
return firstPosition + mostVisibleIndex;
}
- @Override
- public void onDateChanged() {
- goTo(mController.getSelectedDay(), false, true, true);
- }
-
/**
* Attempts to return the date that has accessibility focus.
*
@@ -529,4 +478,18 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
mPerformingScroll = true;
return true;
}
+
+ public interface OnDaySelectedListener {
+ public void onDaySelected(DayPickerView view, Calendar day);
+ }
+
+ private final SimpleMonthAdapter.OnDaySelectedListener
+ mProxyOnDaySelectedListener = new SimpleMonthAdapter.OnDaySelectedListener() {
+ @Override
+ public void onDaySelected(SimpleMonthAdapter adapter, Calendar day) {
+ if (mOnDaySelectedListener != null) {
+ mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
+ }
+ }
+ };
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 54a7940..396c0b9 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -198,54 +198,17 @@ public class PopupWindow {
mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
final TypedArray a = context.obtainStyledAttributes(
- attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes);
-
- mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground);
+ attrs, R.styleable.PopupWindow, defStyleAttr, defStyleRes);
+ final Drawable bg = a.getDrawable(R.styleable.PopupWindow_popupBackground);
mElevation = a.getDimension(R.styleable.PopupWindow_popupElevation, 0);
mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);
final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, -1);
- mAnimationStyle = animStyle == com.android.internal.R.style.Animation_PopupWindow ? -1 :
- animStyle;
+ mAnimationStyle = animStyle == R.style.Animation_PopupWindow ? -1 : animStyle;
- // If this is a StateListDrawable, try to find and store the drawable to be
- // used when the drop-down is placed above its anchor view, and the one to be
- // used when the drop-down is placed below its anchor view. We extract
- // the drawables ourselves to work around a problem with using refreshDrawableState
- // that it will take into account the padding of all drawables specified in a
- // StateListDrawable, thus adding superfluous padding to drop-down views.
- //
- // We assume a StateListDrawable will have a drawable for ABOVE_ANCHOR_STATE_SET and
- // at least one other drawable, intended for the 'below-anchor state'.
- if (mBackground instanceof StateListDrawable) {
- StateListDrawable background = (StateListDrawable) mBackground;
-
- // Find the above-anchor view - this one's easy, it should be labeled as such.
- int aboveAnchorStateIndex = background.getStateDrawableIndex(ABOVE_ANCHOR_STATE_SET);
-
- // Now, for the below-anchor view, look for any other drawable specified in the
- // StateListDrawable which is not for the above-anchor state and use that.
- int count = background.getStateCount();
- int belowAnchorStateIndex = -1;
- for (int i = 0; i < count; i++) {
- if (i != aboveAnchorStateIndex) {
- belowAnchorStateIndex = i;
- break;
- }
- }
-
- // Store the drawables we found, if we found them. Otherwise, set them both
- // to null so that we'll just use refreshDrawableState.
- if (aboveAnchorStateIndex != -1 && belowAnchorStateIndex != -1) {
- mAboveAnchorBackgroundDrawable = background.getStateDrawable(aboveAnchorStateIndex);
- mBelowAnchorBackgroundDrawable = background.getStateDrawable(belowAnchorStateIndex);
- } else {
- mBelowAnchorBackgroundDrawable = null;
- mAboveAnchorBackgroundDrawable = null;
- }
- }
-
a.recycle();
+
+ setBackgroundDrawable(bg);
}
/**
@@ -346,6 +309,43 @@ public class PopupWindow {
*/
public void setBackgroundDrawable(Drawable background) {
mBackground = background;
+
+ // If this is a StateListDrawable, try to find and store the drawable to be
+ // used when the drop-down is placed above its anchor view, and the one to be
+ // used when the drop-down is placed below its anchor view. We extract
+ // the drawables ourselves to work around a problem with using refreshDrawableState
+ // that it will take into account the padding of all drawables specified in a
+ // StateListDrawable, thus adding superfluous padding to drop-down views.
+ //
+ // We assume a StateListDrawable will have a drawable for ABOVE_ANCHOR_STATE_SET and
+ // at least one other drawable, intended for the 'below-anchor state'.
+ if (mBackground instanceof StateListDrawable) {
+ StateListDrawable stateList = (StateListDrawable) mBackground;
+
+ // Find the above-anchor view - this one's easy, it should be labeled as such.
+ int aboveAnchorStateIndex = stateList.getStateDrawableIndex(ABOVE_ANCHOR_STATE_SET);
+
+ // Now, for the below-anchor view, look for any other drawable specified in the
+ // StateListDrawable which is not for the above-anchor state and use that.
+ int count = stateList.getStateCount();
+ int belowAnchorStateIndex = -1;
+ for (int i = 0; i < count; i++) {
+ if (i != aboveAnchorStateIndex) {
+ belowAnchorStateIndex = i;
+ break;
+ }
+ }
+
+ // Store the drawables we found, if we found them. Otherwise, set them both
+ // to null so that we'll just use refreshDrawableState.
+ if (aboveAnchorStateIndex != -1 && belowAnchorStateIndex != -1) {
+ mAboveAnchorBackgroundDrawable = stateList.getStateDrawable(aboveAnchorStateIndex);
+ mBelowAnchorBackgroundDrawable = stateList.getStateDrawable(belowAnchorStateIndex);
+ } else {
+ mBelowAnchorBackgroundDrawable = null;
+ mAboveAnchorBackgroundDrawable = null;
+ }
+ }
}
/**
diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java
index 5aa78c8..ecd2912 100644
--- a/core/java/android/widget/SimpleMonthAdapter.java
+++ b/core/java/android/widget/SimpleMonthAdapter.java
@@ -20,29 +20,28 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.SimpleMonthView.OnDayClickListener;
import java.util.Calendar;
-import java.util.HashMap;
/**
* An adapter for a list of {@link android.widget.SimpleMonthView} items.
*/
-class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayClickListener {
+class SimpleMonthAdapter extends BaseAdapter {
private final Calendar mMinDate = Calendar.getInstance();
private final Calendar mMaxDate = Calendar.getInstance();
private final Context mContext;
- private final DatePickerController mController;
private Calendar mSelectedDay;
private ColorStateList mCalendarTextColors;
+ private OnDaySelectedListener mOnDaySelectedListener;
- public SimpleMonthAdapter(Context context, DatePickerController controller) {
- mContext = context;
- mController = controller;
+ private int mFirstDayOfWeek;
- init();
- setSelectedDay(mController.getSelectedDay());
+ public SimpleMonthAdapter(Context context) {
+ mContext = context;
+ mSelectedDay = Calendar.getInstance();
}
public void setRange(Calendar min, Calendar max) {
@@ -52,27 +51,34 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli
notifyDataSetInvalidated();
}
+ public void setFirstDayOfWeek(int firstDayOfWeek) {
+ mFirstDayOfWeek = firstDayOfWeek;
+
+ notifyDataSetInvalidated();
+ }
+
/**
* Updates the selected day and related parameters.
*
* @param day The day to highlight
*/
public void setSelectedDay(Calendar day) {
- if (mSelectedDay != day) {
- mSelectedDay = day;
- notifyDataSetChanged();
- }
- }
+ mSelectedDay = day;
- void setCalendarTextColor(ColorStateList colors) {
- mCalendarTextColors = colors;
+ notifyDataSetChanged();
}
/**
- * Set up the gesture detector and selected time
+ * Sets the listener to call when the user selects a day.
+ *
+ * @param listener The listener to call.
*/
- protected void init() {
- mSelectedDay = Calendar.getInstance();
+ public void setOnDaySelectedListener(OnDaySelectedListener listener) {
+ mOnDaySelectedListener = listener;
+ }
+
+ void setCalendarTextColor(ColorStateList colors) {
+ mCalendarTextColors = colors;
}
@Override
@@ -111,7 +117,7 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli
AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT);
v.setLayoutParams(params);
v.setClickable(true);
- v.setOnDayClickListener(this);
+ v.setOnDayClickListener(mOnDayClickListener);
if (mCalendarTextColors != null) {
v.setTextColor(mCalendarTextColors);
@@ -148,7 +154,7 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli
enabledDayRangeEnd = 31;
}
- v.setMonthParams(selectedDay, month, year, mController.getFirstDayOfWeek(),
+ v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
enabledDayRangeStart, enabledDayRangeEnd);
v.invalidate();
@@ -159,27 +165,24 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli
return mSelectedDay.get(Calendar.YEAR) == year && mSelectedDay.get(Calendar.MONTH) == month;
}
- @Override
- public void onDayClick(SimpleMonthView view, Calendar day) {
- if (day != null && isCalendarInRange(day)) {
- onDaySelected(day);
- }
- }
-
private boolean isCalendarInRange(Calendar value) {
return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0;
}
- /**
- * Maintains the same hour/min/sec but moves the day to the tapped day.
- *
- * @param day The day that was tapped
- */
- private void onDaySelected(Calendar day) {
- mController.tryVibrate();
- mController.onDayOfMonthSelected(day.get(Calendar.YEAR), day.get(Calendar.MONTH),
- day.get(Calendar.DAY_OF_MONTH));
+ private final OnDayClickListener mOnDayClickListener = new OnDayClickListener() {
+ @Override
+ public void onDayClick(SimpleMonthView view, Calendar day) {
+ if (day != null && isCalendarInRange(day)) {
+ setSelectedDay(day);
+
+ if (mOnDaySelectedListener != null) {
+ mOnDaySelectedListener.onDaySelected(SimpleMonthAdapter.this, day);
+ }
+ }
+ }
+ };
- setSelectedDay(day);
+ public interface OnDaySelectedListener {
+ public void onDaySelected(SimpleMonthAdapter view, Calendar day);
}
}
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 86f580d..b5338df 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -23,8 +23,11 @@ import android.os.Process;
import android.os.StrictMode;
import android.os.SystemClock;
import android.util.Slog;
+
import com.android.internal.util.FastPrintWriter;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
@@ -325,7 +328,12 @@ public class ProcessCpuTracker {
mBaseIdleTime = idletime;
}
- mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
+ final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
+ } finally {
+ StrictMode.setThreadPolicy(savedPolicy);
+ }
final float[] loadAverages = mLoadAverageData;
if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
@@ -847,12 +855,7 @@ public class ProcessCpuTracker {
} catch (java.io.FileNotFoundException e) {
} catch (java.io.IOException e) {
} finally {
- if (is != null) {
- try {
- is.close();
- } catch (java.io.IOException e) {
- }
- }
+ IoUtils.closeQuietly(is);
StrictMode.setThreadPolicy(savedPolicy);
}
return null;
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index d26f79e..7ad3470 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1940,13 +1940,19 @@ public class StateMachine {
* @param args
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(getName() + ":");
- pw.println(" total records=" + getLogRecCount());
+ pw.println(this.toString());
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getName() + ":\n");
+ sb.append(" total records=" + getLogRecCount() + "\n");
for (int i = 0; i < getLogRecSize(); i++) {
- pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString());
- pw.flush();
+ sb.append(" rec[" + i + "]: " + getLogRec(i).toString() + "\n");
}
- pw.println("curState=" + getCurrentState().getName());
+ sb.append("curState=" + getCurrentState().getName());
+ return sb.toString();
}
/**
diff --git a/core/java/com/android/internal/widget/ILockSettingsObserver.aidl b/core/java/com/android/internal/widget/ILockSettingsObserver.aidl
index 6c354d8..edf8f0e 100644
--- a/core/java/com/android/internal/widget/ILockSettingsObserver.aidl
+++ b/core/java/com/android/internal/widget/ILockSettingsObserver.aidl
@@ -18,5 +18,14 @@ package com.android.internal.widget;
/** {@hide} */
oneway interface ILockSettingsObserver {
+ /**
+ * Called when a lock setting has changed.
+ *
+ * Note: Impementations of this should do as little work as possible, because this may be
+ * called synchronously while writing a setting.
+ *
+ * @param key the key of the setting that has changed or {@code null} if any may have changed.
+ * @param userId the user whose setting has changed.
+ */
void onLockSettingChanged(in String key, in int userId);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d6885da..a4b8380 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -65,6 +65,13 @@ public class LockPatternUtils {
private static final boolean DEBUG = false;
/**
+ * If true, LockPatternUtils will cache its values in-process. While this leads to faster reads,
+ * it can cause problems because writes to to the settings are no longer synchronous
+ * across all processes.
+ */
+ private static final boolean ENABLE_CLIENT_CACHE = false;
+
+ /**
* The maximum number of incorrect attempts before the user is prevented
* from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
*/
@@ -207,8 +214,13 @@ public class LockPatternUtils {
private ILockSettings getLockSettings() {
if (mLockSettingsService == null) {
- mLockSettingsService = LockPatternUtilsCache.getInstance(
- ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings")));
+ ILockSettings service = ILockSettings.Stub.asInterface(
+ ServiceManager.getService("lock_settings"));
+ if (ENABLE_CLIENT_CACHE) {
+ mLockSettingsService = LockPatternUtilsCache.getInstance(service);
+ } else {
+ mLockSettingsService = service;
+ }
}
return mLockSettingsService;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtilsCache.java b/core/java/com/android/internal/widget/LockPatternUtilsCache.java
index 624f67c..a9524ff 100644
--- a/core/java/com/android/internal/widget/LockPatternUtilsCache.java
+++ b/core/java/com/android/internal/widget/LockPatternUtilsCache.java
@@ -18,7 +18,9 @@ package com.android.internal.widget;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.Log;
/**
* A decorator for {@link ILockSettings} that caches the key-value responses in memory.
@@ -28,9 +30,11 @@ import android.util.ArrayMap;
*/
public class LockPatternUtilsCache implements ILockSettings {
- private static final String HAS_LOCK_PATTERN_CACHE_KEY
+ private static final String TAG = "LockPatternUtilsCache";
+
+ public static final String HAS_LOCK_PATTERN_CACHE_KEY
= "LockPatternUtils.Cache.HasLockPatternCacheKey";
- private static final String HAS_LOCK_PASSWORD_CACHE_KEY
+ public static final String HAS_LOCK_PASSWORD_CACHE_KEY
= "LockPatternUtils.Cache.HasLockPasswordCacheKey";
private static LockPatternUtilsCache sInstance;
@@ -53,7 +57,7 @@ public class LockPatternUtilsCache implements ILockSettings {
// ILockSettings
- private LockPatternUtilsCache(ILockSettings service) {
+ public LockPatternUtilsCache(ILockSettings service) {
mService = service;
try {
service.registerObserver(mObserver);
@@ -186,6 +190,7 @@ public class LockPatternUtilsCache implements ILockSettings {
// Caching
private Object peekCache(String key, int userId) {
+ if (!validateUserId(userId)) return null;
synchronized (mCache) {
// Safe to reuse mCacheKey, because it is not stored in the map.
return mCache.get(mCacheKey.set(key, userId));
@@ -193,6 +198,7 @@ public class LockPatternUtilsCache implements ILockSettings {
}
private void putCache(String key, int userId, Object value) {
+ if (!validateUserId(userId)) return;
synchronized (mCache) {
// Create a new key, because this will be stored in the map.
mCache.put(new CacheKey().set(key, userId), value);
@@ -200,9 +206,14 @@ public class LockPatternUtilsCache implements ILockSettings {
}
private void invalidateCache(String key, int userId) {
+ if (!validateUserId(userId)) return;
synchronized (mCache) {
- // Safe to reuse mCacheKey, because it is not stored in the map.
- mCache.remove(mCacheKey.set(key, userId));
+ if (key != null) {
+ // Safe to reuse mCacheKey, because it is not stored in the map.
+ mCache.remove(mCacheKey.set(key, userId));
+ } else {
+ mCache.clear();
+ }
}
}
@@ -213,6 +224,14 @@ public class LockPatternUtilsCache implements ILockSettings {
}
};
+ private final boolean validateUserId(int userId) {
+ if (userId < UserHandle.USER_OWNER) {
+ Log.e(TAG, "User " + userId + " not supported: Must be a concrete user.");
+ return false;
+ }
+ return true;
+ }
+
private static final class CacheKey {
String key;
int userId;