summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java68
-rw-r--r--core/java/android/animation/ObjectAnimator.java6
-rw-r--r--core/java/android/app/Activity.java37
-rw-r--r--core/java/android/app/ActivityManager.java21
-rw-r--r--core/java/android/app/ActivityManagerNative.java38
-rw-r--r--core/java/android/app/ActivityOptions.java48
-rw-r--r--core/java/android/app/ActivityThread.java35
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java3
-rw-r--r--core/java/android/app/ApplicationPackageManager.java12
-rw-r--r--core/java/android/app/ApplicationThreadNative.java22
-rw-r--r--core/java/android/app/BackStackRecord.java92
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java9
-rw-r--r--core/java/android/app/IActivityManager.java6
-rw-r--r--core/java/android/app/IApplicationThread.java9
-rw-r--r--core/java/android/app/Instrumentation.java15
-rw-r--r--core/java/android/app/LocalActivityManager.java5
-rw-r--r--core/java/android/app/Notification.java154
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java72
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl7
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl12
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java2
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl3
-rw-r--r--core/java/android/content/ContentProvider.java5
-rw-r--r--core/java/android/content/Intent.java273
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl1
-rw-r--r--core/java/android/content/pm/LabeledIntent.aidl19
-rw-r--r--core/java/android/content/pm/LauncherApps.java16
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/content/res/Configuration.java2
-rw-r--r--core/java/android/content/res/Resources.java14
-rw-r--r--core/java/android/content/res/TypedArray.java24
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java8
-rw-r--r--core/java/android/hardware/hdmi/HdmiRecordListener.java12
-rw-r--r--core/java/android/hardware/hdmi/HdmiTvClient.java12
-rw-r--r--core/java/android/hardware/hdmi/IHdmiRecordListener.aidl16
-rw-r--r--core/java/android/net/ConnectivityManager.java130
-rw-r--r--core/java/android/net/DhcpResults.java4
-rw-r--r--core/java/android/net/IConnectivityManager.aidl2
-rw-r--r--core/java/android/net/LinkAddress.java26
-rw-r--r--core/java/android/net/NetworkCapabilities.java6
-rw-r--r--core/java/android/net/NetworkScoreManager.java19
-rw-r--r--core/java/android/net/NetworkScorerAppManager.java6
-rw-r--r--core/java/android/net/PskKeyManager.java7
-rw-r--r--core/java/android/net/RssiCurve.java55
-rw-r--r--core/java/android/net/StaticIpConfiguration.java1
-rw-r--r--core/java/android/os/Debug.java37
-rw-r--r--core/java/android/os/INetworkManagementService.aidl15
-rw-r--r--core/java/android/os/IPowerManager.aidl2
-rw-r--r--core/java/android/os/PowerManager.java22
-rw-r--r--core/java/android/os/PowerManagerInternal.java7
-rw-r--r--core/java/android/os/UserManager.java19
-rw-r--r--core/java/android/print/IPrintDocumentAdapter.aidl1
-rw-r--r--core/java/android/print/PrintManager.java21
-rw-r--r--core/java/android/provider/CallLog.java63
-rw-r--r--core/java/android/provider/Settings.java35
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java12
-rw-r--r--core/java/android/service/trust/ITrustAgentService.aidl4
-rw-r--r--core/java/android/service/trust/ITrustAgentServiceCallback.aidl2
-rw-r--r--core/java/android/service/trust/TrustAgentService.java69
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java3
-rwxr-xr-xcore/java/android/text/format/DateFormat.java68
-rw-r--r--core/java/android/text/format/Formatter.java21
-rw-r--r--core/java/android/transition/ChangeTransform.java101
-rw-r--r--core/java/android/transition/Transition.java6
-rw-r--r--core/java/android/util/TypedValue.java23
-rw-r--r--core/java/android/view/AccessibilityInteractionController.java12
-rw-r--r--core/java/android/view/GLES20Canvas.java2
-rw-r--r--core/java/android/view/HardwareLayer.java5
-rw-r--r--core/java/android/view/IWindow.aidl5
-rw-r--r--core/java/android/view/IWindowManager.aidl1
-rw-r--r--core/java/android/view/IWindowSession.aidl9
-rw-r--r--core/java/android/view/RenderNodeAnimator.java2
-rw-r--r--core/java/android/view/Surface.java10
-rw-r--r--core/java/android/view/SurfaceView.java3
-rw-r--r--core/java/android/view/ThreadedRenderer.java11
-rw-r--r--core/java/android/view/View.java227
-rw-r--r--core/java/android/view/ViewGroup.java24
-rw-r--r--core/java/android/view/ViewRootImpl.java119
-rw-r--r--core/java/android/view/ViewTreeObserver.java86
-rw-r--r--core/java/android/view/Window.java29
-rw-r--r--core/java/android/view/WindowManager.java2
-rw-r--r--core/java/android/view/WindowManagerGlobal.java18
-rw-r--r--core/java/android/view/WindowManagerPolicy.java11
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java168
-rw-r--r--core/java/android/widget/AbsListView.java14
-rw-r--r--core/java/android/widget/AbsSeekBar.java6
-rw-r--r--core/java/android/widget/ActionMenuView.java2
-rw-r--r--core/java/android/widget/CheckedTextView.java6
-rw-r--r--core/java/android/widget/CompoundButton.java6
-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.java127
-rw-r--r--core/java/android/widget/FrameLayout.java6
-rw-r--r--core/java/android/widget/ImageView.java29
-rw-r--r--core/java/android/widget/ListPopupWindow.java9
-rw-r--r--core/java/android/widget/OverScroller.java4
-rw-r--r--core/java/android/widget/PopupWindow.java84
-rw-r--r--core/java/android/widget/ProgressBar.java24
-rw-r--r--core/java/android/widget/RemoteViews.java20
-rw-r--r--core/java/android/widget/SimpleMonthAdapter.java77
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java43
-rw-r--r--core/java/android/widget/Toolbar.java14
-rw-r--r--core/java/com/android/internal/app/AlertController.java87
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java16
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java79
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java35
-rw-r--r--core/java/com/android/internal/app/ToolbarActionBar.java48
-rw-r--r--core/java/com/android/internal/app/WindowDecorActionBar.java23
-rw-r--r--core/java/com/android/internal/content/ReferrerIntent.aidl19
-rw-r--r--core/java/com/android/internal/content/ReferrerIntent.java51
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java310
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java17
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl1
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl2
-rw-r--r--core/java/com/android/internal/util/MemInfoReader.java4
-rw-r--r--core/java/com/android/internal/util/StateMachine.java16
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/java/com/android/internal/view/RootViewSurfaceTaker.java16
-rw-r--r--core/java/com/android/internal/widget/ActionBarContextView.java2
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java16
-rw-r--r--core/java/com/android/internal/widget/DecorToolbar.java9
-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
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java80
-rw-r--r--core/java/com/android/internal/widget/ToolbarWidgetWrapper.java32
127 files changed, 3124 insertions, 1058 deletions
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 1e1b33f..a9eaf29 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -24,11 +24,9 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Display;
import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -620,18 +618,6 @@ public abstract class AccessibilityService extends Service {
}
}
- @Override
- public Object getSystemService(String name) {
- if (Context.WINDOW_SERVICE.equals(name)) {
- if (mWindowManager == null) {
- WindowManager wrapped = (WindowManager) super.getSystemService(name);
- mWindowManager = new LocalWindowManager(wrapped);
- }
- return mWindowManager;
- }
- return super.getSystemService(name);
- }
-
/**
* Implement to return the implementation of the internal accessibility
* service interface.
@@ -658,6 +644,9 @@ public abstract class AccessibilityService extends Service {
public void init(int connectionId, IBinder windowToken) {
mConnectionId = connectionId;
mWindowToken = windowToken;
+
+ // Let the window manager know about our shiny new token.
+ WindowManagerGlobal.getInstance().setDefaultToken(mWindowToken);
}
@Override
@@ -812,53 +801,4 @@ public abstract class AccessibilityService extends Service {
}
}
}
-
- private class LocalWindowManager implements WindowManager {
- private final WindowManager mImpl;
-
- private LocalWindowManager(WindowManager impl) {
- mImpl = impl;
- }
-
- @Override
- public Display getDefaultDisplay() {
- return mImpl.getDefaultDisplay();
- }
-
- @Override
- public void addView(View view, ViewGroup.LayoutParams params) {
- if (!(params instanceof WindowManager.LayoutParams)) {
- throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
- }
- WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
- if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
- && windowParams.token == null) {
- windowParams.token = mWindowToken;
- }
- mImpl.addView(view, params);
- }
-
- @Override
- public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
- if (!(params instanceof WindowManager.LayoutParams)) {
- throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
- }
- WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
- if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
- && windowParams.token == null) {
- windowParams.token = mWindowToken;
- }
- mImpl.updateViewLayout(view, params);
- }
-
- @Override
- public void removeViewImmediate(View view) {
- mImpl.removeViewImmediate(view);
- }
-
- @Override
- public void removeView(View view) {
- mImpl.removeView(view);
- }
- }
}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 500634c..59daaab 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -885,7 +885,8 @@ public final class ObjectAnimator extends ValueAnimator {
}
/**
- * Sets the target object whose property will be animated by this animation
+ * Sets the target object whose property will be animated by this animation. If the
+ * animator has been started, it will be canceled.
*
* @param target The object being animated
*/
@@ -893,6 +894,9 @@ public final class ObjectAnimator extends ValueAnimator {
public void setTarget(@Nullable Object target) {
final Object oldTarget = getTarget();
if (oldTarget != target) {
+ if (isStarted()) {
+ cancel();
+ }
mTarget = target == null ? null : new WeakReference<Object>(target);
// New target should cause re-initialization prior to starting
mInitialized = false;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4b705dd..148527f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -693,6 +693,7 @@ public class Activity extends ContextThemeWrapper
/*package*/ String mEmbeddedID;
private Application mApplication;
/*package*/ Intent mIntent;
+ /*package*/ String mReferrer;
private ComponentName mComponent;
/*package*/ ActivityInfo mActivityInfo;
/*package*/ ActivityThread mMainThread;
@@ -4448,6 +4449,39 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Return information about who launched this activity. If the launching Intent
+ * contains an {@link android.content.Intent#EXTRA_REFERRER Intent.EXTRA_REFERRER},
+ * that will be returned as-is; otherwise, if known, an
+ * {@link Intent#URI_ANDROID_APP_SCHEME android-app:} referrer URI containing the
+ * package name that started the Intent will be returned. This may return null if no
+ * referrer can be identified -- it is neither explicitly specified, nor is it known which
+ * application package was involved.
+ *
+ * <p>If called while inside the handling of {@link #onNewIntent}, this function will
+ * return the referrer that submitted that new intent to the activity. Otherwise, it
+ * always returns the referrer of the original Intent.</p>
+ *
+ * <p>Note that this is <em>not</em> a security feature -- you can not trust the
+ * referrer information, applications can spoof it.</p>
+ */
+ @Nullable
+ public Uri getReferrer() {
+ Intent intent = getIntent();
+ Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+ if (referrer != null) {
+ return referrer;
+ }
+ String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+ if (referrerName != null) {
+ return Uri.parse(referrerName);
+ }
+ if (mReferrer != null) {
+ return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
+ }
+ return null;
+ }
+
+ /**
* Return the name of the package that invoked this activity. This is who
* the data in {@link #setResult setResult()} will be sent to. You can
* use this information to validate that the recipient is allowed to
@@ -5868,7 +5902,7 @@ public class Activity extends ContextThemeWrapper
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
- Configuration config, IVoiceInteractor voiceInteractor) {
+ Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
@@ -5891,6 +5925,7 @@ public class Activity extends ContextThemeWrapper
mIdent = ident;
mApplication = application;
mIntent = intent;
+ mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 37e8aa4..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
@@ -1243,26 +1250,16 @@ public class ActivityManager {
}
/**
- * If set, the process of the root activity of the task will be killed
- * as part of removing the task.
- * @hide
- */
- public static final int REMOVE_TASK_KILL_PROCESS = 0x0001;
-
- /**
* Completely remove the given task.
*
* @param taskId Identifier of the task to be removed.
- * @param flags Additional operational flags. May be 0 or
- * {@link #REMOVE_TASK_KILL_PROCESS}.
* @return Returns true if the given task was found and removed.
*
* @hide
*/
- public boolean removeTask(int taskId, int flags)
- throws SecurityException {
+ public boolean removeTask(int taskId) throws SecurityException {
try {
- return ActivityManagerNative.getDefault().removeTask(taskId, flags);
+ return ActivityManagerNative.getDefault().removeTask(taskId);
} catch (RemoteException e) {
// System dead, we will be dead too soon!
return false;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4e2ff0b..c3028b7 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1884,8 +1884,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
{
data.enforceInterface(IActivityManager.descriptor);
int taskId = data.readInt();
- int fl = data.readInt();
- boolean result = removeTask(taskId, fl);
+ boolean result = removeTask(taskId);
reply.writeNoException();
reply.writeInt(result ? 1 : 0);
return true;
@@ -2280,6 +2279,20 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case START_IN_PLACE_ANIMATION_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final Bundle bundle;
+ if (data.readInt() == 0) {
+ bundle = null;
+ } else {
+ bundle = data.readBundle();
+ }
+ final ActivityOptions options = bundle == null ? null : new ActivityOptions(bundle);
+ startInPlaceAnimationOnFrontMostApplication(options);
+ reply.writeNoException();
+ return true;
+ }
+
case REQUEST_VISIBLE_BEHIND_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -4778,12 +4791,11 @@ class ActivityManagerProxy implements IActivityManager
return result;
}
- public boolean removeTask(int taskId, int flags) throws RemoteException {
+ public boolean removeTask(int taskId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
- data.writeInt(flags);
mRemote.transact(REMOVE_TASK_TRANSACTION, data, reply, 0);
reply.readException();
boolean result = reply.readInt() != 0;
@@ -5300,6 +5312,24 @@ class ActivityManagerProxy implements IActivityManager
}
@Override
+ public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions options)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ if (options == null) {
+ data.writeInt(0);
+ } else {
+ data.writeInt(1);
+ data.writeBundle(options.toBundle());
+ }
+ mRemote.transact(START_IN_PLACE_ANIMATION_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
+ @Override
public boolean requestVisibleBehind(IBinder token, boolean visible) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index cd6a4f5..3d390bf 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -63,6 +63,12 @@ public class ActivityOptions {
public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes";
/**
+ * Custom in-place animation resource ID.
+ * @hide
+ */
+ public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:animInPlaceRes";
+
+ /**
* Bitmap for thumbnail animation.
* @hide
*/
@@ -132,11 +138,14 @@ public class ActivityOptions {
public static final int ANIM_THUMBNAIL_ASPECT_SCALE_UP = 8;
/** @hide */
public static final int ANIM_THUMBNAIL_ASPECT_SCALE_DOWN = 9;
+ /** @hide */
+ public static final int ANIM_CUSTOM_IN_PLACE = 10;
private String mPackageName;
private int mAnimationType = ANIM_NONE;
private int mCustomEnterResId;
private int mCustomExitResId;
+ private int mCustomInPlaceResId;
private Bitmap mThumbnail;
private int mStartX;
private int mStartY;
@@ -198,6 +207,30 @@ public class ActivityOptions {
return opts;
}
+ /**
+ * Creates an ActivityOptions specifying a custom animation to run in place on an existing
+ * activity.
+ *
+ * @param context Who is defining this. This is the application that the
+ * animation resources will be loaded from.
+ * @param animId A resource ID of the animation resource to use for
+ * the incoming activity.
+ * @return Returns a new ActivityOptions object that you can use to
+ * supply these options as the options Bundle when running an in-place animation.
+ * @hide
+ */
+ public static ActivityOptions makeCustomInPlaceAnimation(Context context, int animId) {
+ if (animId == 0) {
+ throw new RuntimeException("You must specify a valid animation.");
+ }
+
+ ActivityOptions opts = new ActivityOptions();
+ opts.mPackageName = context.getPackageName();
+ opts.mAnimationType = ANIM_CUSTOM_IN_PLACE;
+ opts.mCustomInPlaceResId = animId;
+ return opts;
+ }
+
private void setOnAnimationStartedListener(Handler handler,
OnAnimationStartedListener listener) {
if (listener != null) {
@@ -540,6 +573,10 @@ public class ActivityOptions {
opts.getBinder(KEY_ANIM_START_LISTENER));
break;
+ case ANIM_CUSTOM_IN_PLACE:
+ mCustomInPlaceResId = opts.getInt(KEY_ANIM_IN_PLACE_RES_ID, 0);
+ break;
+
case ANIM_SCALE_UP:
mStartX = opts.getInt(KEY_ANIM_START_X, 0);
mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
@@ -592,6 +629,11 @@ public class ActivityOptions {
}
/** @hide */
+ public int getCustomInPlaceResId() {
+ return mCustomInPlaceResId;
+ }
+
+ /** @hide */
public Bitmap getThumbnail() {
return mThumbnail;
}
@@ -689,6 +731,9 @@ public class ActivityOptions {
}
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
break;
+ case ANIM_CUSTOM_IN_PLACE:
+ mCustomInPlaceResId = otherOptions.mCustomInPlaceResId;
+ break;
case ANIM_SCALE_UP:
mStartX = otherOptions.mStartX;
mStartY = otherOptions.mStartY;
@@ -756,6 +801,9 @@ public class ActivityOptions {
b.putBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
!= null ? mAnimationStartedListener.asBinder() : null);
break;
+ case ANIM_CUSTOM_IN_PLACE:
+ b.putInt(KEY_ANIM_IN_PLACE_RES_ID, mCustomInPlaceResId);
+ break;
case ANIM_SCALE_UP:
b.putInt(KEY_ANIM_START_X, mStartX);
b.putInt(KEY_ANIM_START_Y, mStartY);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index fa15ad7..5f21d75 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -94,6 +94,7 @@ import android.renderscript.RenderScript;
import android.security.AndroidKeyStoreProvider;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
@@ -268,6 +269,7 @@ public final class ActivityThread {
IBinder token;
int ident;
Intent intent;
+ String referrer;
IVoiceInteractor voiceInteractor;
Bundle state;
PersistableBundle persistentState;
@@ -290,7 +292,7 @@ public final class ActivityThread {
LoadedApk packageInfo;
List<ResultInfo> pendingResults;
- List<Intent> pendingIntents;
+ List<ReferrerIntent> pendingIntents;
boolean startsNotResumed;
boolean isForward;
@@ -348,7 +350,7 @@ public final class ActivityThread {
}
static final class NewIntentData {
- List<Intent> intents;
+ List<ReferrerIntent> intents;
IBinder token;
public String toString() {
return "NewIntentData{intents=" + intents + " token=" + token + "}";
@@ -605,9 +607,9 @@ public final class ActivityThread {
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
- List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+ List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
@@ -617,6 +619,7 @@ public final class ActivityThread {
r.token = token;
r.ident = ident;
r.intent = intent;
+ r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
@@ -637,13 +640,13 @@ public final class ActivityThread {
}
public final void scheduleRelaunchActivity(IBinder token,
- List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+ List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config) {
requestRelaunchActivity(token, pendingResults, pendingNewIntents,
configChanges, notResumed, config, true);
}
- public final void scheduleNewIntent(List<Intent> intents, IBinder token) {
+ public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) {
NewIntentData data = new NewIntentData();
data.intents = intents;
data.token = token;
@@ -1742,6 +1745,12 @@ public final class ActivityThread {
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
+
+ if (mSystemThread && "android".equals(aInfo.packageName)) {
+ packageInfo.installSystemApplicationInfo(aInfo,
+ getSystemContext().mPackageInfo.getClassLoader());
+ }
+
if (includeCode) {
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
@@ -1802,10 +1811,6 @@ public final class ActivityThread {
synchronized (this) {
getSystemContext().installSystemApplicationInfo(info, classLoader);
- // The code package for "android" in the system server needs
- // to be the system context's package.
- mPackages.put("android", new WeakReference<LoadedApk>(getSystemContext().mPackageInfo));
-
// give ourselves a default profiler
mProfiler = new Profiler();
}
@@ -2232,7 +2237,7 @@ public final class ActivityThread {
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
- r.voiceInteractor);
+ r.referrer, r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent;
@@ -2419,8 +2424,7 @@ public final class ActivityThread {
}
}
- private void deliverNewIntents(ActivityClientRecord r,
- List<Intent> intents) {
+ private void deliverNewIntents(ActivityClientRecord r, List<ReferrerIntent> intents) {
final int N = intents.size();
for (int i=0; i<N; i++) {
Intent intent = intents.get(i);
@@ -2431,8 +2435,7 @@ public final class ActivityThread {
}
}
- public final void performNewIntents(IBinder token,
- List<Intent> intents) {
+ public final void performNewIntents(IBinder token, List<ReferrerIntent> intents) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
final boolean resumed = !r.paused;
@@ -3750,7 +3753,7 @@ public final class ActivityThread {
}
public final void requestRelaunchActivity(IBinder token,
- List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+ List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config,
boolean fromServer) {
ActivityClientRecord target = null;
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 82b6e35..9062892 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -638,6 +638,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
if (decorView != null) {
decorView.getLocationOnScreen(decorLoc);
}
+ Matrix tempMatrix = new Matrix();
for (String name: names) {
Bundle sharedElementBundle = state.getBundle(name);
if (sharedElementBundle != null) {
@@ -647,7 +648,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
snapshot = mListener.onCreateSnapshotView(context, parcelable);
}
if (snapshot != null) {
- setSharedElementState(snapshot, name, state, null, null, decorLoc);
+ setSharedElementState(snapshot, name, state, tempMatrix, null, decorLoc);
}
snapshots.add(snapshot);
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 854719d..967e97e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1609,6 +1609,18 @@ final class ApplicationPackageManager extends PackageManager {
return null;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean isUpgrade() {
+ try {
+ return mPM.isUpgrade();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
@Override
public PackageInstaller getPackageInstaller() {
synchronized (mLock) {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 0123e16..d1b77b9 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -36,6 +36,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -140,19 +141,21 @@ public abstract class ApplicationThreadNative extends Binder
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
+ String referrer = data.readString();
IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
data.readStrongBinder());
int procState = data.readInt();
Bundle state = data.readBundle();
PersistableBundle persistentState = data.readPersistableBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
- List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
+ List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
boolean notResumed = data.readInt() != 0;
boolean isForward = data.readInt() != 0;
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
- scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, voiceInteractor,
- procState, state, persistentState, ri, pi, notResumed, isForward, profilerInfo);
+ scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, referrer,
+ voiceInteractor, procState, state, persistentState, ri, pi,
+ notResumed, isForward, profilerInfo);
return true;
}
@@ -161,7 +164,7 @@ public abstract class ApplicationThreadNative extends Binder
data.enforceInterface(IApplicationThread.descriptor);
IBinder b = data.readStrongBinder();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
- List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
+ List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
int configChanges = data.readInt();
boolean notResumed = data.readInt() != 0;
Configuration config = null;
@@ -175,7 +178,7 @@ public abstract class ApplicationThreadNative extends Binder
case SCHEDULE_NEW_INTENT_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
- List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
+ List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
IBinder b = data.readStrongBinder();
scheduleNewIntent(pi, b);
return true;
@@ -764,9 +767,9 @@ class ApplicationThreadProxy implements IApplicationThread {
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
- List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+ List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
ProfilerInfo profilerInfo) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -776,6 +779,7 @@ class ApplicationThreadProxy implements IApplicationThread {
info.writeToParcel(data, 0);
curConfig.writeToParcel(data, 0);
compatInfo.writeToParcel(data, 0);
+ data.writeString(referrer);
data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
data.writeInt(procState);
data.writeBundle(state);
@@ -796,7 +800,7 @@ class ApplicationThreadProxy implements IApplicationThread {
}
public final void scheduleRelaunchActivity(IBinder token,
- List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+ List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config)
throws RemoteException {
Parcel data = Parcel.obtain();
@@ -817,7 +821,7 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
- public void scheduleNewIntent(List<Intent> intents, IBinder token)
+ public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
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/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 7894887..ecf19c7 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -133,16 +133,17 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
return;
}
mAreViewsReady = true;
+ final ViewGroup decor = getDecor();
// Ensure the views have been laid out before capturing the views -- we need the epicenter.
- if (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()) {
+ if (decor == null || (decor.isAttachedToWindow() &&
+ (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()))) {
viewsReady(sharedElements);
} else {
- final View sharedElement = sharedElements.valueAt(0);
- sharedElement.getViewTreeObserver()
+ decor.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
+ decor.getViewTreeObserver().removeOnPreDrawListener(this);
viewsReady(sharedElements);
return true;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index be26f30..6433f3f 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -373,7 +373,7 @@ public interface IActivityManager extends IInterface {
public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException;
public int[] getRunningUserIds() throws RemoteException;
- public boolean removeTask(int taskId, int flags) throws RemoteException;
+ public boolean removeTask(int taskId) throws RemoteException;
public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
@@ -456,6 +456,9 @@ public interface IActivityManager extends IInterface {
throws RemoteException;
public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
+ public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
+ throws RemoteException;
+
public boolean requestVisibleBehind(IBinder token, boolean visible) throws RemoteException;
public boolean isBackgroundVisibleBehind(IBinder token) throws RemoteException;
public void backgroundResourcesReleased(IBinder token) throws RemoteException;
@@ -781,4 +784,5 @@ public interface IActivityManager extends IInterface {
int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237;
int GET_TASK_DESCRIPTION_ICON_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+238;
int LAUNCH_ASSIST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+239;
+ int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index f53075c..42acbc6 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -35,6 +35,7 @@ import android.os.IBinder;
import android.os.IInterface;
import android.service.voice.IVoiceInteractionSession;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.content.ReferrerIntent;
import java.io.FileDescriptor;
import java.util.List;
@@ -59,14 +60,14 @@ public interface IApplicationThread extends IInterface {
void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
- List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
+ List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
ProfilerInfo profilerInfo) throws RemoteException;
void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults,
- List<Intent> pendingNewIntents, int configChanges,
+ List<ReferrerIntent> pendingNewIntents, int configChanges,
boolean notResumed, Configuration config) throws RemoteException;
- void scheduleNewIntent(List<Intent> intent, IBinder token) throws RemoteException;
+ void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException;
void scheduleDestroyActivity(IBinder token, boolean finished,
int configChanges) throws RemoteException;
void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 60a013e..d96153a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -45,6 +45,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.Window;
+import com.android.internal.content.ReferrerIntent;
import java.io.File;
import java.util.ArrayList;
@@ -1042,7 +1043,7 @@ public class Instrumentation {
activity.attach(context, aThread, this, token, 0, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
- new Configuration(), null);
+ new Configuration(), null, null);
return activity;
}
@@ -1207,7 +1208,17 @@ public class Instrumentation {
* @param intent The new intent being received.
*/
public void callActivityOnNewIntent(Activity activity, Intent intent) {
- activity.onNewIntent(intent);
+ final String oldReferrer = activity.mReferrer;
+ try {
+ try {
+ activity.mReferrer = ((ReferrerIntent)intent).mReferrer;
+ } catch (ClassCastException e) {
+ activity.mReferrer = null;
+ }
+ activity.onNewIntent(intent);
+ } finally {
+ activity.mReferrer = oldReferrer;
+ }
}
/**
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index b654a6a..873e337 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -22,6 +22,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
+import com.android.internal.content.ReferrerIntent;
import java.util.ArrayList;
import java.util.HashMap;
@@ -310,8 +311,8 @@ public class LocalActivityManager {
if (aInfo.launchMode != ActivityInfo.LAUNCH_MULTIPLE ||
(intent.getFlags()&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0) {
// The activity wants onNewIntent() called.
- ArrayList<Intent> intents = new ArrayList<Intent>(1);
- intents.add(intent);
+ ArrayList<ReferrerIntent> intents = new ArrayList<>(1);
+ intents.add(new ReferrerIntent(intent, mParent.getPackageName()));
if (localLOGV) Log.v(TAG, r.id + ": new intent");
mActivityThread.performNewIntents(r, intents);
r.intent = intent;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9849c51..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;
+ }
}
}
@@ -4340,10 +4429,23 @@ public class Notification implements Parcelable
*/
public static final int SIZE_FULL_SCREEN = 5;
+ /**
+ * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a
+ * short amount of time when this notification is displayed on the screen. This
+ * is the default value.
+ */
+ public static final int SCREEN_TIMEOUT_SHORT = 0;
+
+ /**
+ * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on
+ * for a longer amount of time when this notification is displayed on the screen.
+ */
+ public static final int SCREEN_TIMEOUT_LONG = -1;
+
/** 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";
@@ -4355,12 +4457,14 @@ public class Notification implements Parcelable
private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset";
private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight";
private static final String KEY_GRAVITY = "gravity";
+ private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout";
// Flags bitwise-ored to mFlags
private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1;
private static final int FLAG_HINT_HIDE_ICON = 1 << 1;
private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2;
private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3;
+ private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4;
// Default value for flags integer
private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE;
@@ -4379,6 +4483,7 @@ public class Notification implements Parcelable
private int mCustomSizePreset = SIZE_DEFAULT;
private int mCustomContentHeight;
private int mGravity = DEFAULT_GRAVITY;
+ private int mHintScreenTimeout;
/**
* Create a {@link android.app.Notification.WearableExtender} with default
@@ -4414,6 +4519,7 @@ public class Notification implements Parcelable
SIZE_DEFAULT);
mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT);
mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY);
+ mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT);
}
}
@@ -4461,6 +4567,9 @@ public class Notification implements Parcelable
if (mGravity != DEFAULT_GRAVITY) {
wearableBundle.putInt(KEY_GRAVITY, mGravity);
}
+ if (mHintScreenTimeout != 0) {
+ wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout);
+ }
builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
return builder;
@@ -4480,6 +4589,7 @@ public class Notification implements Parcelable
that.mCustomSizePreset = this.mCustomSizePreset;
that.mCustomContentHeight = this.mCustomContentHeight;
that.mGravity = this.mGravity;
+ that.mHintScreenTimeout = this.mHintScreenTimeout;
return that;
}
@@ -4875,6 +4985,48 @@ public class Notification implements Parcelable
return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0;
}
+ /**
+ * Set a hint that this notification's background should not be clipped if possible.
+ * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible.
+ * @return this object for method chaining
+ */
+ public WearableExtender setHintAvoidBackgroundClipping(
+ boolean hintAvoidBackgroundClipping) {
+ setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping);
+ return this;
+ }
+
+ /**
+ * Get a hint that this notification's background should not be clipped if possible.
+ * @return {@code true} if it's ok if the background is clipped on the screen, false
+ * otherwise. The default value is {@code false} if this was never set.
+ */
+ public boolean getHintAvoidBackgroundClipping() {
+ return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0;
+ }
+
+ /**
+ * Set a hint that the screen should remain on for at least this duration when
+ * this notification is displayed on the screen.
+ * @param timeout The requested screen timeout in milliseconds. Can also be either
+ * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
+ * @return this object for method chaining
+ */
+ public WearableExtender setHintScreenTimeout(int timeout) {
+ mHintScreenTimeout = timeout;
+ return this;
+ }
+
+ /**
+ * Get the duration, in milliseconds, that the screen should remain on for
+ * when this notification is displayed.
+ * @return the duration in milliseconds if > 0, or either one of the sentinel values
+ * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
+ */
+ public int getHintScreenTimeout() {
+ return mHintScreenTimeout;
+ }
+
private void setFlag(int mask, boolean value) {
if (value) {
mFlags |= mask;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a30ae57..9157b1b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -31,6 +31,7 @@ import android.content.pm.ResolveInfo;
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.Handler;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -40,6 +41,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.security.Credentials;
import android.service.restrictions.RestrictionsReceiver;
+import android.service.trust.TrustAgentService;
import android.util.Log;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -60,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>
@@ -2584,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.
*
@@ -2591,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) {
@@ -2604,25 +2615,29 @@ public class DevicePolicyManager {
}
/**
- * Sets a list of features to enable for a TrustAgent component. This is meant to be
- * used in conjunction with {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which will disable all
- * trust agents but those with features enabled by this function call.
+ * Sets a list of configuration features to enable for a TrustAgent component. This is meant
+ * to be used in conjunction with {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, which disables all
+ * trust agents but those enabled by this function call. If flag
+ * {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is not set, then this call has no effect.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_KEYGUARD_FEATURES} to be able to call
- * this method; if it has not, a security exception will be thrown.
+ * this method; if not, a security exception will be thrown.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @param agent Which component to enable features for.
- * @param features List of features to enable. Consult specific TrustAgent documentation for
- * the feature list.
- * @hide
+ * @param target Component name of the agent to be enabled.
+ * @param options TrustAgent-specific feature bundle. If null for any admin, agent
+ * will be strictly disabled according to the state of the
+ * {@link #KEYGUARD_DISABLE_TRUST_AGENTS} flag.
+ * <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
+ * then it's up to the TrustAgent itself to aggregate the values from all device admins.
+ * <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
*/
- public void setTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent,
- List<String> features) {
+ public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
+ PersistableBundle options) {
if (mService != null) {
try {
- mService.setTrustAgentFeaturesEnabled(admin, agent, features, UserHandle.myUserId());
+ mService.setTrustAgentConfiguration(admin, target, options, UserHandle.myUserId());
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -2630,24 +2645,30 @@ public class DevicePolicyManager {
}
/**
- * Gets list of enabled features for the given TrustAgent component. If admin is
- * null, this will return the intersection of all features enabled for the given agent by all
- * admins.
+ * Gets configuration for the given trust agent based on aggregating all calls to
+ * {@link #setTrustAgentConfiguration(ComponentName, ComponentName, PersistableBundle)} for
+ * all device admins.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param agent Which component to get enabled features for.
- * @return List of enabled features.
- * @hide
+ * @return configuration for the given trust agent.
*/
- public List<String> getTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent) {
+ public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
+ ComponentName agent) {
+ return getTrustAgentConfiguration(admin, agent, UserHandle.myUserId());
+ }
+
+ /** @hide per-user version */
+ public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
+ ComponentName agent, int userHandle) {
if (mService != null) {
try {
- return mService.getTrustAgentFeaturesEnabled(admin, agent, UserHandle.myUserId());
+ return mService.getTrustAgentConfiguration(admin, agent, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
}
- return new ArrayList<String>(); // empty list
+ return new ArrayList<PersistableBundle>(); // empty list
}
/**
@@ -3133,9 +3154,10 @@ public class DevicePolicyManager {
}
/**
- * Called by a profile owner to disable account management for a specific type of account.
+ * Called by a device owner or profile owner to disable account management for a specific type
+ * of account.
*
- * <p>The calling device admin must be a profile owner. If it is not, a
+ * <p>The calling device admin must be a device owner or profile owner. If it is not, a
* security exception will be thrown.
*
* <p>When account management is disabled for an account type, adding or removing an account
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c8e1780..07aa800 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -22,6 +22,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.ProxyInfo;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.UserHandle;
import java.util.List;
@@ -183,8 +184,10 @@ interface IDevicePolicyManager {
boolean getCrossProfileCallerIdDisabled(in ComponentName who);
boolean getCrossProfileCallerIdDisabledForUser(int userId);
- void setTrustAgentFeaturesEnabled(in ComponentName admin, in ComponentName agent, in List<String> features, int userId);
- List<String> getTrustAgentFeaturesEnabled(in ComponentName admin, in ComponentName agent, int userId);
+ void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent,
+ in PersistableBundle args, int userId);
+ List<PersistableBundle> getTrustAgentConfiguration(in ComponentName admin,
+ in ComponentName agent, int userId);
boolean addCrossProfileWidgetProvider(in ComponentName admin, String packageName);
boolean removeCrossProfileWidgetProvider(in ComponentName admin, String packageName);
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/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index f2e03cf..c262bae 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1445,7 +1445,7 @@ public final class BluetoothAdapter {
if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
synchronized (mManagerCallback) {
mService = null;
- mLeScanClients.clear();
+ if (mLeScanClients != null) mLeScanClients.clear();
if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
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/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 2853c58..c8f9b7d 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -515,7 +515,10 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
// last chance, check against any uri grants
- if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ final int callingUserId = UserHandle.getUserId(uid);
+ final Uri userUri = (mSingleUser && !UserHandle.isSameUser(mMyUid, uid))
+ ? maybeAddUserId(uri, callingUserId) : uri;
+ if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
== PERMISSION_GRANTED) {
return;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7676e4b..57f6028 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -41,6 +41,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
import android.provider.DocumentsContract;
@@ -1400,14 +1401,36 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.ORIGINATING_URI";
/**
- * Used as a URI extra field with {@link #ACTION_INSTALL_PACKAGE} and
- * {@link #ACTION_VIEW} to indicate the HTTP referrer URI associated with the Intent
- * data field or {@link #EXTRA_ORIGINATING_URI}.
+ * This extra can be used with any Intent used to launch an activity, supplying information
+ * about who is launching that activity. This field contains a {@link android.net.Uri}
+ * object, typically an http: or https: URI of the web site that the referral came from;
+ * it can also use the {@link #URI_ANDROID_APP_SCHEME android-app:} scheme to identify
+ * a native application that it came from.
+ *
+ * <p>To retrieve this value in a client, use {@link android.app.Activity#getReferrer}
+ * instead of directly retrieving the extra. It is also valid for applications to
+ * instead supply {@link #EXTRA_REFERRER_NAME} for cases where they can only create
+ * a string, not a Uri; the field here, if supplied, will always take precedence,
+ * however.</p>
+ *
+ * @see #EXTRA_REFERRER_NAME
*/
public static final String EXTRA_REFERRER
= "android.intent.extra.REFERRER";
/**
+ * Alternate version of {@link #EXTRA_REFERRER} that supplies the URI as a String rather
+ * than a {@link android.net.Uri} object. Only for use in cases where Uri objects can
+ * not be created, in particular when Intent extras are supplied through the
+ * {@link #URI_INTENT_SCHEME intent:} or {@link #URI_ANDROID_APP_SCHEME android-app:}
+ * schemes.
+ *
+ * @see #EXTRA_REFERRER
+ */
+ public static final String EXTRA_REFERRER_NAME
+ = "android.intent.extra.REFERRER_NAME";
+
+ /**
* Used as an int extra field with {@link #ACTION_INSTALL_PACKAGE} and
* {@link} #ACTION_VIEW} to indicate the uid of the package that initiated the install
* @hide
@@ -3918,6 +3941,75 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final int URI_INTENT_SCHEME = 1<<0;
+ /**
+ * Flag for use with {@link #toUri} and {@link #parseUri}: the URI string
+ * always has the "android-app:" scheme. This is a variation of
+ * {@link #URI_INTENT_SCHEME} whose format is simpler for the case of an
+ * http/https URI being delivered to a specific package name. The format
+ * is:
+ *
+ * <pre class="prettyprint">
+ * android-app://{package_id}/{scheme}/{host}/{path}{#Intent;...}</pre>
+ *
+ * <p>In this scheme, only the <code>pacakge_id</code> is required, and all
+ * other components can be included as desired. Note that this can not be
+ * used with intents that have a {@link #setSelector}, since the base intent
+ * will always have an explicit package name.</p>
+ *
+ * <p>Some examples of how this scheme maps to Intent objects:</p>
+ * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
+ * <colgroup align="left" />
+ * <colgroup align="left" />
+ * <thead>
+ * <tr><th>URI</th> <th>Intent</th></tr>
+ * </thead>
+ *
+ * <tbody>
+ * <tr><td><code>android-app://com.example.app</code></td>
+ * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+ * <tr><td>Action: </td><td>{@link #ACTION_MAIN}</td></tr>
+ * <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+ * </table></td>
+ * </tr>
+ * <tr><td><code>android-app://com.example.app/http/example.com</code></td>
+ * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+ * <tr><td>Action: </td><td>{@link #ACTION_VIEW}</td></tr>
+ * <tr><td>Data: </td><td><code>http://example.com/</code></td></tr>
+ * <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+ * </table></td>
+ * </tr>
+ * <tr><td><code>android-app://com.example.app/http/example.com/foo?1234</code></td>
+ * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+ * <tr><td>Action: </td><td>{@link #ACTION_VIEW}</td></tr>
+ * <tr><td>Data: </td><td><code>http://example.com/foo?1234</code></td></tr>
+ * <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+ * </table></td>
+ * </tr>
+ * <tr><td><code>android-app://com.example.app/<br />#Intent;action=com.example.MY_ACTION;end</code></td>
+ * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+ * <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr>
+ * <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+ * </table></td>
+ * </tr>
+ * <tr><td><code>android-app://com.example.app/http/example.com/foo?1234<br />#Intent;action=com.example.MY_ACTION;end</code></td>
+ * <td><table style="margin:0;border:0;cellpadding:0;cellspacing:0">
+ * <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr>
+ * <tr><td>Data: </td><td><code>http://example.com/foo?1234</code></td></tr>
+ * <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+ * </table></td>
+ * </tr>
+ * <tr><td><code>android-app://com.example.app/<br />#Intent;action=com.example.MY_ACTION;<br />i.some_int=100;S.some_str=hello;end</code></td>
+ * <td><table border="" style="margin:0" >
+ * <tr><td>Action: </td><td><code>com.example.MY_ACTION</code></td></tr>
+ * <tr><td>Package: </td><td><code>com.example.app</code></td></tr>
+ * <tr><td>Extras: </td><td><code>some_int=(int)100<br />some_str=(String)hello</code></td></tr>
+ * </table></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ */
+ public static final int URI_ANDROID_APP_SCHEME = 1<<1;
+
// ---------------------------------------------------------------------
private String mAction;
@@ -4178,8 +4270,8 @@ public class Intent implements Parcelable, Cloneable {
* the scheme and full path.
*
* @param uri The URI to turn into an Intent.
- * @param flags Additional processing flags. Either 0 or
- * {@link #URI_INTENT_SCHEME}.
+ * @param flags Additional processing flags. Either 0,
+ * {@link #URI_INTENT_SCHEME}, or {@link #URI_ANDROID_APP_SCHEME}.
*
* @return Intent The newly created Intent object.
*
@@ -4192,9 +4284,11 @@ public class Intent implements Parcelable, Cloneable {
public static Intent parseUri(String uri, int flags) throws URISyntaxException {
int i = 0;
try {
- // Validate intent scheme for if requested.
- if ((flags&URI_INTENT_SCHEME) != 0) {
- if (!uri.startsWith("intent:")) {
+ final boolean androidApp = uri.startsWith("android-app:");
+
+ // Validate intent scheme if requested.
+ if ((flags&(URI_INTENT_SCHEME|URI_ANDROID_APP_SCHEME)) != 0) {
+ if (!uri.startsWith("intent:") && !androidApp) {
Intent intent = new Intent(ACTION_VIEW);
try {
intent.setData(Uri.parse(uri));
@@ -4205,24 +4299,40 @@ public class Intent implements Parcelable, Cloneable {
}
}
- // simple case
i = uri.lastIndexOf("#");
- if (i == -1) return new Intent(ACTION_VIEW, Uri.parse(uri));
+ // simple case
+ if (i == -1) {
+ if (!androidApp) {
+ return new Intent(ACTION_VIEW, Uri.parse(uri));
+ }
// old format Intent URI
- if (!uri.startsWith("#Intent;", i)) return getIntentOld(uri);
+ } else if (!uri.startsWith("#Intent;", i)) {
+ if (!androidApp) {
+ return getIntentOld(uri);
+ } else {
+ i = -1;
+ }
+ }
// new format
Intent intent = new Intent(ACTION_VIEW);
Intent baseIntent = intent;
+ boolean explicitAction = false;
+ boolean inSelector = false;
// fetch data part, if present
- String data = i >= 0 ? uri.substring(0, i) : null;
String scheme = null;
- i += "#Intent;".length();
+ String data;
+ if (i >= 0) {
+ data = uri.substring(0, i);
+ i += 8; // length of "#Intent;"
+ } else {
+ data = uri;
+ }
// loop over contents of Intent, all name=value;
- while (!uri.startsWith("end", i)) {
+ while (i >= 0 && !uri.startsWith("end", i)) {
int eq = uri.indexOf('=', i);
if (eq < 0) eq = i-1;
int semi = uri.indexOf(';', i);
@@ -4231,6 +4341,9 @@ public class Intent implements Parcelable, Cloneable {
// action
if (uri.startsWith("action=", i)) {
intent.setAction(value);
+ if (!inSelector) {
+ explicitAction = true;
+ }
}
// categories
@@ -4260,7 +4373,11 @@ public class Intent implements Parcelable, Cloneable {
// scheme
else if (uri.startsWith("scheme=", i)) {
- scheme = value;
+ if (inSelector) {
+ intent.mData = Uri.parse(value);
+ } else {
+ scheme = value;
+ }
}
// source bounds
@@ -4271,6 +4388,7 @@ public class Intent implements Parcelable, Cloneable {
// selector
else if (semi == (i+3) && uri.startsWith("SEL", i)) {
intent = new Intent();
+ inSelector = true;
}
// extra
@@ -4296,9 +4414,11 @@ public class Intent implements Parcelable, Cloneable {
i = semi + 1;
}
- if (intent != baseIntent) {
+ if (inSelector) {
// The Intent had a selector; fix it up.
- baseIntent.setSelector(intent);
+ if (baseIntent.mPackage == null) {
+ baseIntent.setSelector(intent);
+ }
intent = baseIntent;
}
@@ -4308,6 +4428,47 @@ public class Intent implements Parcelable, Cloneable {
if (scheme != null) {
data = scheme + ':' + data;
}
+ } else if (data.startsWith("android-app:")) {
+ if (data.charAt(12) == '/' && data.charAt(13) == '/') {
+ // Correctly formed android-app, first part is package name.
+ int end = data.indexOf('/', 14);
+ if (end < 0) {
+ // All we have is a package name.
+ intent.mPackage = data.substring(14);
+ if (!explicitAction) {
+ intent.setAction(ACTION_MAIN);
+ }
+ data = "";
+ } else {
+ // Target the Intent at the given package name always.
+ String authority = null;
+ intent.mPackage = data.substring(14, end);
+ int newEnd;
+ if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) {
+ // Found a scheme, remember it.
+ scheme = data.substring(end+1, newEnd);
+ end = newEnd;
+ if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) {
+ // Found a authority, remember it.
+ authority = data.substring(end+1, newEnd);
+ end = newEnd;
+ }
+ }
+ if (scheme == null) {
+ // If there was no scheme, then this just targets the package.
+ if (!explicitAction) {
+ intent.setAction(ACTION_MAIN);
+ }
+ data = "";
+ } else if (authority == null) {
+ data = scheme + ":";
+ } else {
+ data = scheme + "://" + authority + data.substring(end);
+ }
+ }
+ } else {
+ data = "";
+ }
}
if (data.length() > 0) {
@@ -7083,14 +7244,53 @@ public class Intent implements Parcelable, Cloneable {
* <p>You can convert the returned string back to an Intent with
* {@link #getIntent}.
*
- * @param flags Additional operating flags. Either 0 or
- * {@link #URI_INTENT_SCHEME}.
+ * @param flags Additional operating flags. Either 0,
+ * {@link #URI_INTENT_SCHEME}, or {@link #URI_ANDROID_APP_SCHEME}.
*
* @return Returns a URI encoding URI string describing the entire contents
* of the Intent.
*/
public String toUri(int flags) {
StringBuilder uri = new StringBuilder(128);
+ if ((flags&URI_ANDROID_APP_SCHEME) != 0) {
+ if (mPackage == null) {
+ throw new IllegalArgumentException(
+ "Intent must include an explicit package name to build an android-app: "
+ + this);
+ }
+ uri.append("android-app://");
+ uri.append(mPackage);
+ String scheme = null;
+ if (mData != null) {
+ scheme = mData.getScheme();
+ if (scheme != null) {
+ uri.append('/');
+ uri.append(scheme);
+ String authority = mData.getEncodedAuthority();
+ if (authority != null) {
+ uri.append('/');
+ uri.append(authority);
+ String path = mData.getEncodedPath();
+ if (path != null) {
+ uri.append(path);
+ }
+ String queryParams = mData.getEncodedQuery();
+ if (queryParams != null) {
+ uri.append('?');
+ uri.append(queryParams);
+ }
+ String fragment = mData.getEncodedFragment();
+ if (fragment != null) {
+ uri.append('#');
+ uri.append(fragment);
+ }
+ }
+ }
+ }
+ toUriFragment(uri, null, scheme == null ? Intent.ACTION_MAIN : Intent.ACTION_VIEW,
+ mPackage, flags);
+ return uri.toString();
+ }
String scheme = null;
if (mData != null) {
String data = mData.toString();
@@ -7120,27 +7320,38 @@ public class Intent implements Parcelable, Cloneable {
uri.append("intent:");
}
- uri.append("#Intent;");
+ toUriFragment(uri, scheme, Intent.ACTION_VIEW, null, flags);
+
+ return uri.toString();
+ }
+
+ private void toUriFragment(StringBuilder uri, String scheme, String defAction,
+ String defPackage, int flags) {
+ StringBuilder frag = new StringBuilder(128);
- toUriInner(uri, scheme, flags);
+ toUriInner(frag, scheme, defAction, defPackage, flags);
if (mSelector != null) {
uri.append("SEL;");
// Note that for now we are not going to try to handle the
// data part; not clear how to represent this as a URI, and
// not much utility in it.
- mSelector.toUriInner(uri, null, flags);
+ mSelector.toUriInner(frag, mSelector.mData != null ? mSelector.mData.getScheme() : null,
+ null, null, flags);
}
- uri.append("end");
-
- return uri.toString();
+ if (frag.length() > 0) {
+ uri.append("#Intent;");
+ uri.append(frag);
+ uri.append("end");
+ }
}
- private void toUriInner(StringBuilder uri, String scheme, int flags) {
+ private void toUriInner(StringBuilder uri, String scheme, String defAction,
+ String defPackage, int flags) {
if (scheme != null) {
uri.append("scheme=").append(scheme).append(';');
}
- if (mAction != null) {
+ if (mAction != null && !mAction.equals(defAction)) {
uri.append("action=").append(Uri.encode(mAction)).append(';');
}
if (mCategories != null) {
@@ -7154,7 +7365,7 @@ public class Intent implements Parcelable, Cloneable {
if (mFlags != 0) {
uri.append("launchFlags=0x").append(Integer.toHexString(mFlags)).append(';');
}
- if (mPackage != null) {
+ if (mPackage != null && !mPackage.equals(defPackage)) {
uri.append("package=").append(Uri.encode(mPackage)).append(';');
}
if (mComponent != null) {
@@ -7498,8 +7709,10 @@ public class Intent implements Parcelable, Cloneable {
*/
public void prepareToEnterProcess() {
if (mContentUserHint != UserHandle.USER_CURRENT) {
- fixUris(mContentUserHint);
- mContentUserHint = UserHandle.USER_CURRENT;
+ if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
+ fixUris(mContentUserHint);
+ mContentUserHint = UserHandle.USER_CURRENT;
+ }
}
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c37534a..0dc86ad 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -436,6 +436,7 @@ interface IPackageManager {
boolean isFirstBoot();
boolean isOnlyCoreApps();
+ boolean isUpgrade();
void setPermissionEnforced(String permission, boolean enforced);
boolean isPermissionEnforced(String permission);
diff --git a/core/java/android/content/pm/LabeledIntent.aidl b/core/java/android/content/pm/LabeledIntent.aidl
new file mode 100644
index 0000000..ad96759
--- /dev/null
+++ b/core/java/android/content/pm/LabeledIntent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable LabeledIntent;
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 5ee0b67..c164340 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -499,20 +499,4 @@ public class LauncherApps {
obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
}
}
-
- /**
- * TODO Remove after 2014-09-22
- * @hide
- */
- public void addCallback(Callback callback) {
- registerCallback(callback);
- }
-
- /**
- * TODO Remove after 2014-09-22
- * @hide
- */
- public void removeCallback(Callback callback) {
- unregisterCallback(callback);
- }
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ab90b66..e9f7c50 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3867,6 +3867,13 @@ public abstract class PackageManager {
public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
/**
+ * Returns true if the device is upgrading, such as first boot after OTA.
+ *
+ * @hide
+ */
+ public abstract boolean isUpgrade();
+
+ /**
* Return interface that offers the ability to install, upgrade, and remove
* applications on the device.
*/
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index acdd87e..14af584 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1371,7 +1371,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
}
}
- if (!config.locale.getLanguage().isEmpty()) {
+ if (config.locale != null && !config.locale.getLanguage().isEmpty()) {
parts.add(localeToResourceQualifier(config.locale));
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 6e9efe1..0145e05 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -18,6 +18,7 @@ package android.content.res;
import android.animation.Animator;
import android.animation.StateListAnimator;
+import android.annotation.NonNull;
import android.util.Pools.SynchronizedPool;
import android.view.ViewDebug;
import com.android.internal.util.XmlUtils;
@@ -1548,20 +1549,21 @@ public class Resources {
* contents of the typed array are ultimately filled in by
* {@link Resources#getValue}.
*
- * @param values The base set of attribute values, must be equal
- * in length to {@code attrs} or {@code null}. All values
- * must be of type {@link TypedValue#TYPE_ATTRIBUTE}.
+ * @param values The base set of attribute values, must be equal in
+ * length to {@code attrs}. All values must be of type
+ * {@link TypedValue#TYPE_ATTRIBUTE}.
* @param attrs The desired attributes to be retrieved.
* @return Returns a TypedArray holding an array of the attribute
* values. Be sure to call {@link TypedArray#recycle()}
* when done with it.
* @hide
*/
- public TypedArray resolveAttributes(int[] values, int[] attrs) {
+ @NonNull
+ public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
final int len = attrs.length;
- if (values != null && len != values.length) {
+ if (values == null || len != values.length) {
throw new IllegalArgumentException(
- "Base attribute values must be null or the same length as attrs");
+ "Base attribute values must the same length as attrs");
}
final TypedArray array = TypedArray.obtain(Resources.this, len);
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 73b93c6..02602fb 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -807,6 +807,9 @@ public class TypedArray {
/**
* Determines whether there is an attribute at <var>index</var>.
+ * <p>
+ * <strong>Note:</strong> If the attribute was set to {@code @empty} or
+ * {@code @undefined}, this method returns {@code false}.
*
* @param index Index of attribute to retrieve.
*
@@ -824,6 +827,27 @@ public class TypedArray {
}
/**
+ * Determines whether there is an attribute at <var>index</var>, returning
+ * {@code true} if the attribute was explicitly set to {@code @empty} and
+ * {@code false} only if the attribute was undefined.
+ *
+ * @param index Index of attribute to retrieve.
+ *
+ * @return True if the attribute has a value or is empty, false otherwise.
+ */
+ public boolean hasValueOrEmpty(int index) {
+ if (mRecycled) {
+ throw new RuntimeException("Cannot make calls to a recycled instance!");
+ }
+
+ index *= AssetManager.STYLE_NUM_ENTRIES;
+ final int[] data = mData;
+ final int type = data[index+AssetManager.STYLE_TYPE];
+ return type != TypedValue.TYPE_NULL
+ || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
+ }
+
+ /**
* Retrieve the raw TypedValue for the attribute at <var>index</var>
* and return a temporary object holding its data. This object is only
* valid until the next call on to {@link TypedArray}.
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 8447dde..bb162153 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -172,9 +172,12 @@ public abstract class DisplayManagerInternal {
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
- //If true, scales the brightness to half of desired.
+ // If true, scales the brightness to half of desired.
public boolean lowPowerMode;
+ // If true, applies a brightness boost.
+ public boolean boostScreenBrightness;
+
// If true, prevents the screen from completely turning on if it is currently off.
// The display does not enter a "ready" state if this flag is true and screen on is
// blocked. The window manager policy blocks screen on while it prepares the keyguard to
@@ -216,6 +219,7 @@ public abstract class DisplayManagerInternal {
useAutoBrightness = other.useAutoBrightness;
blockScreenOn = other.blockScreenOn;
lowPowerMode = other.lowPowerMode;
+ boostScreenBrightness = other.boostScreenBrightness;
dozeScreenBrightness = other.dozeScreenBrightness;
dozeScreenState = other.dozeScreenState;
}
@@ -235,6 +239,7 @@ public abstract class DisplayManagerInternal {
&& useAutoBrightness == other.useAutoBrightness
&& blockScreenOn == other.blockScreenOn
&& lowPowerMode == other.lowPowerMode
+ && boostScreenBrightness == other.boostScreenBrightness
&& dozeScreenBrightness == other.dozeScreenBrightness
&& dozeScreenState == other.dozeScreenState;
}
@@ -253,6 +258,7 @@ public abstract class DisplayManagerInternal {
+ ", useAutoBrightness=" + useAutoBrightness
+ ", blockScreenOn=" + blockScreenOn
+ ", lowPowerMode=" + lowPowerMode
+ + ", boostScreenBrightness=" + boostScreenBrightness
+ ", dozeScreenBrightness=" + dozeScreenBrightness
+ ", dozeScreenState=" + Display.stateToString(dozeScreenState);
}
diff --git a/core/java/android/hardware/hdmi/HdmiRecordListener.java b/core/java/android/hardware/hdmi/HdmiRecordListener.java
index 29f6cfc..90b7768 100644
--- a/core/java/android/hardware/hdmi/HdmiRecordListener.java
+++ b/core/java/android/hardware/hdmi/HdmiRecordListener.java
@@ -39,6 +39,8 @@ public abstract class HdmiRecordListener {
/**
* Called when one touch record is started or failed during initialization.
*
+ * @param recorderAddress An address of recorder that reports result of one touch record
+ * request
* @param result result code. For more details, please look at all constants starting with
* "ONE_TOUCH_RECORD_". Only
* {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE},
@@ -47,15 +49,17 @@ public abstract class HdmiRecordListener {
* {@link HdmiControlManager#ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT} mean normal
* start of recording; otherwise, describes failure.
*/
- public void onOneTouchRecordResult(int result) {
+ public void onOneTouchRecordResult(int recorderAddress, int result) {
}
/**
* Called when timer recording is started or failed during initialization.
*
+ * @param recorderAddress An address of recorder that reports result of timer recording
+ * request
* @param data timer status data. For more details, look at {@link TimerStatusData}.
*/
- public void onTimerRecordingResult(TimerStatusData data) {
+ public void onTimerRecordingResult(int recorderAddress, TimerStatusData data) {
}
/**
@@ -230,6 +234,8 @@ public abstract class HdmiRecordListener {
/**
* Called when receiving result for clear timer recording request.
*
+ * @param recorderAddress An address of recorder that reports result of clear timer recording
+ * request
* @param result result of clear timer. It should be one of
* {@link HdmiControlManager#CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING}
* {@link HdmiControlManager#CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING},
@@ -239,6 +245,6 @@ public abstract class HdmiRecordListener {
* {@link HdmiControlManager#CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE},
* {@link HdmiControlManager#CLEAR_TIMER_STATUS_CEC_DISABLE}.
*/
- public void onClearTimerRecordingResult(int result) {
+ public void onClearTimerRecordingResult(int recorderAddress, int result) {
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index dbfb4ef..cef17dd 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -226,19 +226,19 @@ public final class HdmiTvClient extends HdmiClient {
}
@Override
- public void onOneTouchRecordResult(int result) {
- callback.onOneTouchRecordResult(result);
+ public void onOneTouchRecordResult(int recorderAddress, int result) {
+ callback.onOneTouchRecordResult(recorderAddress, result);
}
@Override
- public void onTimerRecordingResult(int result) {
- callback.onTimerRecordingResult(
+ public void onTimerRecordingResult(int recorderAddress, int result) {
+ callback.onTimerRecordingResult(recorderAddress,
HdmiRecordListener.TimerStatusData.parseFrom(result));
}
@Override
- public void onClearTimerRecordingResult(int result) {
- callback.onClearTimerRecordingResult(result);
+ public void onClearTimerRecordingResult(int recorderAddress, int result) {
+ callback.onClearTimerRecordingResult(recorderAddress, result);
}
};
}
diff --git a/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl b/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl
index 44d9065..d2deb38 100644
--- a/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiRecordListener.aidl
@@ -31,19 +31,25 @@ package android.hardware.hdmi;
/**
* Called when one touch record is started or failed during initialization.
*
+ * @param recorderAddress An address of recorder that reports result of one touch record
+ * request
* @param result result code for one touch record
*/
- void onOneTouchRecordResult(int result);
+ void onOneTouchRecordResult(int recorderAddress, int result);
/**
* Called when timer recording is started or failed during initialization.
-
+ *
+ * @param recorderAddress An address of recorder that reports result of timer recording
+ * request
* @param result result code for timer recording
*/
- void onTimerRecordingResult(int result);
+ void onTimerRecordingResult(int recorderAddress, int result);
/**
* Called when receiving result for clear timer recording request.
*
- * @param result result of clear timer.
+ * @param recorderAddress An address of recorder that reports result of clear timer recording
+ * request
+ * @param result result of clear timer
*/
- void onClearTimerRecordingResult(int result);
+ void onClearTimerRecordingResult(int recorderAddress, int result);
} \ No newline at end of file
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9194ca8..1c9f4c6 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1012,60 +1012,57 @@ public class ConnectivityManager {
return null;
}
+ /**
+ * Guess what the network request was trying to say so that the resulting
+ * network is accessible via the legacy (deprecated) API such as
+ * requestRouteToHost.
+ * This means we should try to be fairly preceise about transport and
+ * capability but ignore things such as networkSpecifier.
+ * If the request has more than one transport or capability it doesn't
+ * match the old legacy requests (they selected only single transport/capability)
+ * so this function cannot map the request to a single legacy type and
+ * the resulting network will not be available to the legacy APIs.
+ *
+ * TODO - This should be removed when the legacy APIs are removed.
+ */
private int inferLegacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
if (netCap == null) {
return TYPE_NONE;
}
+
if (!netCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return TYPE_NONE;
}
+
+ String type = null;
+ int result = TYPE_NONE;
+
if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
- if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableCBS"))) {
- return TYPE_MOBILE_CBS;
- } else {
- return TYPE_NONE;
- }
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
- if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableIMS"))) {
- return TYPE_MOBILE_IMS;
- } else {
- return TYPE_NONE;
- }
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
- if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableFOTA"))) {
- return TYPE_MOBILE_FOTA;
- } else {
- return TYPE_NONE;
- }
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
- if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableDUN"))) {
- return TYPE_MOBILE_DUN;
- } else {
- return TYPE_NONE;
- }
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
- if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableSUPL"))) {
- return TYPE_MOBILE_SUPL;
- } else {
- return TYPE_NONE;
- }
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
- if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableMMS"))) {
- return TYPE_MOBILE_MMS;
- } else {
- return TYPE_NONE;
- }
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
- if (netCap.equals(networkCapabilitiesForFeature(TYPE_MOBILE, "enableHIPRI"))) {
- return TYPE_MOBILE_HIPRI;
- } else {
- return TYPE_NONE;
+ type = "enableCBS";
+ result = TYPE_MOBILE_CBS;
+ } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
+ type = "enableIMS";
+ result = TYPE_MOBILE_IMS;
+ } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
+ type = "enableFOTA";
+ result = TYPE_MOBILE_FOTA;
+ } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
+ type = "enableDUN";
+ result = TYPE_MOBILE_DUN;
+ } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
+ type = "enableSUPL";
+ result = TYPE_MOBILE_SUPL;
+ } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+ type = "enableMMS";
+ result = TYPE_MOBILE_MMS;
+ } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+ type = "enableHIPRI";
+ result = TYPE_MOBILE_HIPRI;
+ }
+ if (type != null) {
+ NetworkCapabilities testCap = networkCapabilitiesForFeature(TYPE_MOBILE, type);
+ if (testCap.equalsNetCapabilities(netCap) && testCap.equalsTransportTypes(netCap)) {
+ return result;
}
}
return TYPE_NONE;
@@ -2381,17 +2378,15 @@ public class ConnectivityManager {
/**
* The lookup key for a {@link Network} object included with the intent after
- * succesfully finding a network for the applications request. Retrieve it with
+ * successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
- * @hide
*/
public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork";
/**
* The lookup key for a {@link NetworkRequest} object included with the intent after
- * succesfully finding a network for the applications request. Retrieve it with
+ * successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
- * @hide
*/
public static final String EXTRA_NETWORK_REQUEST_NETWORK_REQUEST =
"networkRequestNetworkRequest";
@@ -2400,7 +2395,7 @@ public class ConnectivityManager {
/**
* Request a network to satisfy a set of {@link NetworkCapabilities}.
*
- * This function behavies identically to the version that takes a NetworkCallback, but instead
+ * This function behaves identically to the version that takes a NetworkCallback, but instead
* of {@link NetworkCallback} a {@link PendingIntent} is used. This means
* the request may outlive the calling application and get called back when a suitable
* network is found.
@@ -2421,21 +2416,46 @@ public class ConnectivityManager {
* two Intents defined by {@link Intent#filterEquals}), then it will be removed and
* replaced by this one, effectively releasing the previous {@link NetworkRequest}.
* <p>
- * The request may be released normally by calling {@link #unregisterNetworkCallback}.
+ * The request may be released normally by calling
+ * {@link #releaseNetworkRequest(android.app.PendingIntent)}.
*
* @param request {@link NetworkRequest} describing this request.
* @param operation Action to perform when the network is available (corresponds
* to the {@link NetworkCallback#onAvailable} call. Typically
- * comes from {@link PendingIntent#getBroadcast}.
- * @hide
+ * comes from {@link PendingIntent#getBroadcast}. Cannot be null.
*/
public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+ checkPendingIntent(operation);
try {
mService.pendingRequestForNetwork(request.networkCapabilities, operation);
} catch (RemoteException e) {}
}
/**
+ * Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)}
+ * <p>
+ * This method has the same behavior as {@link #unregisterNetworkCallback} with respect to
+ * releasing network resources and disconnecting.
+ *
+ * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the
+ * PendingIntent passed to
+ * {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the
+ * corresponding NetworkRequest you'd like to remove. Cannot be null.
+ */
+ public void releaseNetworkRequest(PendingIntent operation) {
+ checkPendingIntent(operation);
+ try {
+ mService.releasePendingNetworkRequest(operation);
+ } catch (RemoteException e) {}
+ }
+
+ private void checkPendingIntent(PendingIntent intent) {
+ if (intent == null) {
+ throw new IllegalArgumentException("PendingIntent cannot be null.");
+ }
+ }
+
+ /**
* Registers to receive notifications about all networks which satisfy the given
* {@link NetworkRequest}. The callbacks will continue to be called until
* either the application exits or {@link #unregisterNetworkCallback} is called
@@ -2451,7 +2471,7 @@ public class ConnectivityManager {
/**
* Unregisters callbacks about and possibly releases networks originating from
* {@link #requestNetwork} and {@link #registerNetworkCallback} calls. If the
- * given {@code NetworkCallback} had previosuly been used with {@code #requestNetwork},
+ * given {@code NetworkCallback} had previously been used with {@code #requestNetwork},
* any networks that had been connected to only to satisfy that request will be
* disconnected.
*
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 71df60a..6159e1e 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -200,7 +200,7 @@ public class DhcpResults extends StaticIpConfiguration {
vendorInfo = info;
}
- public void setDomains(String domains) {
- domains = domains;
+ public void setDomains(String newDomains) {
+ domains = newDomains;
}
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index a983d88..a7bbc53 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -156,6 +156,8 @@ interface IConnectivityManager
NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation);
+ void releasePendingNetworkRequest(in PendingIntent operation);
+
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
in Messenger messenger, in IBinder binder);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index c387055..384ab1c 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -21,12 +21,14 @@ import android.os.Parcelable;
import android.util.Pair;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
import static android.system.OsConstants.IFA_F_DADFAILED;
import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_OPTIMISTIC;
import static android.system.OsConstants.IFA_F_TENTATIVE;
import static android.system.OsConstants.RT_SCOPE_HOST;
import static android.system.OsConstants.RT_SCOPE_LINK;
@@ -93,6 +95,20 @@ public class LinkAddress implements Parcelable {
}
/**
+ * Utility function to check if |address| is a Unique Local IPv6 Unicast Address
+ * (a.k.a. "ULA"; RFC 4193).
+ *
+ * Per RFC 4193 section 8, fc00::/7 identifies these addresses.
+ */
+ private boolean isIPv6ULA() {
+ if (address != null && address instanceof Inet6Address) {
+ byte[] bytes = address.getAddress();
+ return ((bytes[0] & (byte)0xfc) == (byte)0xfc);
+ }
+ return false;
+ }
+
+ /**
* Utility function for the constructors.
*/
private void init(InetAddress address, int prefixLength, int flags, int scope) {
@@ -268,8 +284,16 @@ public class LinkAddress implements Parcelable {
* @hide
*/
public boolean isGlobalPreferred() {
+ /**
+ * Note that addresses flagged as IFA_F_OPTIMISTIC are
+ * simultaneously flagged as IFA_F_TENTATIVE (when the tentative
+ * state has cleared either DAD has succeeded or failed, and both
+ * flags are cleared regardless).
+ */
return (scope == RT_SCOPE_UNIVERSE &&
- (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L);
+ !isIPv6ULA() &&
+ (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L &&
+ ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L));
}
/**
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 1efe478..ce7ad65 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -235,7 +235,8 @@ public final class NetworkCapabilities implements Parcelable {
return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities);
}
- private boolean equalsNetCapabilities(NetworkCapabilities nc) {
+ /** @hide */
+ public boolean equalsNetCapabilities(NetworkCapabilities nc) {
return (nc.mNetworkCapabilities == this.mNetworkCapabilities);
}
@@ -344,7 +345,8 @@ public final class NetworkCapabilities implements Parcelable {
return ((this.mTransportTypes == 0) ||
((this.mTransportTypes & nc.mTransportTypes) != 0));
}
- private boolean equalsTransportTypes(NetworkCapabilities nc) {
+ /** @hide */
+ public boolean equalsTransportTypes(NetworkCapabilities nc) {
return (nc.mTransportTypes == this.mTransportTypes);
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 3f68a44..a939cce 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -41,10 +41,10 @@ import android.os.UserHandle;
* <ul>
* <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
* <li>Includes a receiver for {@link #ACTION_SCORE_NETWORKS} guarded by the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission which scores networks
- * and (eventually) calls {@link #updateScores} with the results. If this receiver specifies an
- * android:label attribute, this label will be used when referring to the application throughout
- * system settings; otherwise, the application label will be used.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission which scores
+ * networks and (eventually) calls {@link #updateScores} with the results. If this receiver
+ * specifies an android:label attribute, this label will be used when referring to the
+ * application throughout system settings; otherwise, the application label will be used.
* </ul>
*
* <p>The system keeps track of an active scorer application; at any time, only this application
@@ -192,12 +192,15 @@ public class NetworkScoreManager {
/**
* Set the active scorer to a new package and clear existing scores.
*
+ * <p>Should never be called directly without obtaining user consent. This can be done by using
+ * the {@link #ACTION_CHANGE_ACTIVE} broadcast, or using a custom configuration activity.
+ *
* @return true if the operation succeeded, or false if the new package is not a valid scorer.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating
- * that it can manage scorer applications.
+ * {@link android.Manifest.permission#SCORE_NETWORKS} permission.
* @hide
*/
+ @SystemApi
public boolean setActiveScorer(String packageName) throws SecurityException {
try {
return mService.setActiveScorer(packageName);
@@ -228,7 +231,7 @@ public class NetworkScoreManager {
*
* @return true if the broadcast was sent, or false if there is no active scorer.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* @hide
*/
public boolean requestScores(NetworkKey[] networks) throws SecurityException {
@@ -252,7 +255,7 @@ public class NetworkScoreManager {
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
* @hide
*/
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index c33f5ec..46f7194 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -79,7 +79,7 @@ public final class NetworkScorerAppManager {
* <ul>
* <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
* <li>Includes a receiver for {@link NetworkScoreManager#ACTION_SCORE_NETWORKS} guarded by the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* </ul>
*
* @return the list of scorers, or the empty list if there are no valid scorers.
@@ -98,8 +98,8 @@ public final class NetworkScorerAppManager {
// Should never happen with queryBroadcastReceivers, but invalid nonetheless.
continue;
}
- if (!permission.BROADCAST_SCORE_NETWORKS.equals(receiverInfo.permission)) {
- // Receiver doesn't require the BROADCAST_SCORE_NETWORKS permission, which means
+ if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) {
+ // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means
// anyone could trigger network scoring and flood the framework with score requests.
continue;
}
diff --git a/core/java/android/net/PskKeyManager.java b/core/java/android/net/PskKeyManager.java
index d162282..f82e635 100644
--- a/core/java/android/net/PskKeyManager.java
+++ b/core/java/android/net/PskKeyManager.java
@@ -81,6 +81,13 @@ import javax.net.ssl.SSLEngine;
* Subclasses should normally provide their own implementation of {@code getKey} because the default
* implementation returns no key, which aborts the handshake.
*
+ * <h3>Known issues</h3>
+ * The implementation of {@code ECDHE_PSK} cipher suites in API Level 21 contains a bug which breaks
+ * compatibility with other implementations. {@code ECDHE_PSK} cipher suites are enabled by default
+ * on platforms with API Level 21 when an {@code SSLContext} is initialized with a
+ * {@code PskKeyManager}. A workaround is to disable {@code ECDHE_PSK} cipher suites on platforms
+ * with API Level 21.
+ *
* <h3>Example</h3>
* The following example illustrates how to create an {@code SSLContext} which enables the use of
* TLS-PSK in {@code SSLSocket}, {@code SSLServerSocket} and {@code SSLEngine} instances obtained
diff --git a/core/java/android/net/RssiCurve.java b/core/java/android/net/RssiCurve.java
index f653f37..8ebe9e8 100644
--- a/core/java/android/net/RssiCurve.java
+++ b/core/java/android/net/RssiCurve.java
@@ -27,8 +27,8 @@ import java.util.Objects;
* A curve defining the network score over a range of RSSI values.
*
* <p>For each RSSI bucket, the score may be any byte. Scores have no absolute meaning and are only
- * considered relative to other scores assigned by the same scorer. Networks with no score are all
- * considered equivalent and ranked below any network with a score.
+ * considered relative to other scores assigned by the same scorer. Networks with no score are
+ * treated equivalently to a network with score {@link Byte#MIN_VALUE}, and will not be used.
*
* <p>For example, consider a curve starting at -110 dBm with a bucket width of 10 and the
* following buckets: {@code [-20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]}.
@@ -52,6 +52,7 @@ import java.util.Objects;
*/
@SystemApi
public class RssiCurve implements Parcelable {
+ private static final int DEFAULT_ACTIVE_NETWORK_RSSI_BOOST = 25;
/** The starting dBm of the curve. */
public final int start;
@@ -63,6 +64,15 @@ public class RssiCurve implements Parcelable {
public final byte[] rssiBuckets;
/**
+ * The RSSI boost to give this network when active, in dBm.
+ *
+ * <p>When the system is connected to this network, it will pretend that the network has this
+ * much higher of an RSSI. This is to avoid switching networks when another network has only a
+ * slightly higher score.
+ */
+ public final int activeNetworkRssiBoost;
+
+ /**
* Construct a new {@link RssiCurve}.
*
* @param start the starting dBm of the curve.
@@ -70,12 +80,25 @@ public class RssiCurve implements Parcelable {
* @param rssiBuckets the score for each RSSI bucket.
*/
public RssiCurve(int start, int bucketWidth, byte[] rssiBuckets) {
+ this(start, bucketWidth, rssiBuckets, DEFAULT_ACTIVE_NETWORK_RSSI_BOOST);
+ }
+
+ /**
+ * Construct a new {@link RssiCurve}.
+ *
+ * @param start the starting dBm of the curve.
+ * @param bucketWidth the width of each RSSI bucket, in dBm.
+ * @param rssiBuckets the score for each RSSI bucket.
+ * @param activeNetworkRssiBoost the RSSI boost to apply when this network is active, in dBm.
+ */
+ public RssiCurve(int start, int bucketWidth, byte[] rssiBuckets, int activeNetworkRssiBoost) {
this.start = start;
this.bucketWidth = bucketWidth;
if (rssiBuckets == null || rssiBuckets.length == 0) {
throw new IllegalArgumentException("rssiBuckets must be at least one element large.");
}
this.rssiBuckets = rssiBuckets;
+ this.activeNetworkRssiBoost = activeNetworkRssiBoost;
}
private RssiCurve(Parcel in) {
@@ -84,6 +107,7 @@ public class RssiCurve implements Parcelable {
int bucketCount = in.readInt();
rssiBuckets = new byte[bucketCount];
in.readByteArray(rssiBuckets);
+ activeNetworkRssiBoost = in.readInt();
}
@Override
@@ -97,6 +121,7 @@ public class RssiCurve implements Parcelable {
out.writeInt(bucketWidth);
out.writeInt(rssiBuckets.length);
out.writeByteArray(rssiBuckets);
+ out.writeInt(activeNetworkRssiBoost);
}
/**
@@ -108,6 +133,23 @@ public class RssiCurve implements Parcelable {
* @return the score for the given RSSI.
*/
public byte lookupScore(int rssi) {
+ return lookupScore(rssi, false /* isActiveNetwork */);
+ }
+
+ /**
+ * Lookup the score for a given RSSI value.
+ *
+ * @param rssi The RSSI to lookup. If the RSSI falls below the start of the curve, the score at
+ * the start of the curve will be returned. If it falls after the end of the curve, the
+ * score at the end of the curve will be returned.
+ * @param isActiveNetwork Whether this network is currently active.
+ * @return the score for the given RSSI.
+ */
+ public byte lookupScore(int rssi, boolean isActiveNetwork) {
+ if (isActiveNetwork) {
+ rssi += activeNetworkRssiBoost;
+ }
+
int index = (rssi - start) / bucketWidth;
// Snap the index to the closest bucket if it falls outside the curve.
@@ -136,12 +178,13 @@ public class RssiCurve implements Parcelable {
return start == rssiCurve.start &&
bucketWidth == rssiCurve.bucketWidth &&
- Arrays.equals(rssiBuckets, rssiCurve.rssiBuckets);
+ Arrays.equals(rssiBuckets, rssiCurve.rssiBuckets) &&
+ activeNetworkRssiBoost == rssiCurve.activeNetworkRssiBoost;
}
@Override
public int hashCode() {
- return Objects.hash(start, bucketWidth, rssiBuckets);
+ return Objects.hash(start, bucketWidth, rssiBuckets, activeNetworkRssiBoost);
}
@Override
@@ -150,7 +193,9 @@ public class RssiCurve implements Parcelable {
sb.append("RssiCurve[start=")
.append(start)
.append(",bucketWidth=")
- .append(bucketWidth);
+ .append(bucketWidth)
+ .append(",activeNetworkRssiBoost=")
+ .append(activeNetworkRssiBoost);
sb.append(",buckets=");
for (int i = 0; i < rssiBuckets.length; i++) {
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 5a273cf..598a503 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -107,6 +107,7 @@ public class StaticIpConfiguration implements Parcelable {
for (InetAddress dns : dnsServers) {
lp.addDnsServer(dns);
}
+ lp.setDomains(domains);
return lp;
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 084ca30..3f42d25 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -165,7 +165,7 @@ public final class Debug
public int otherSwappedOut;
/** @hide */
- public static final int NUM_OTHER_STATS = 16;
+ public static final int NUM_OTHER_STATS = 17;
/** @hide */
public static final int NUM_DVK_STATS = 5;
@@ -296,23 +296,24 @@ public final class Debug
case 1: return "Stack";
case 2: return "Cursor";
case 3: return "Ashmem";
- case 4: return "Other dev";
- case 5: return ".so mmap";
- case 6: return ".jar mmap";
- case 7: return ".apk mmap";
- case 8: return ".ttf mmap";
- case 9: return ".dex mmap";
- case 10: return "code mmap";
- case 11: return "image mmap";
- case 12: return "Other mmap";
- case 13: return "Graphics";
- case 14: return "GL";
- case 15: return "Memtrack";
- case 16: return ".Heap";
- case 17: return ".LOS";
- case 18: return ".LinearAlloc";
- case 19: return ".GC";
- case 20: return ".JITCache";
+ case 4: return "Gfx driver";
+ case 5: return "Other dev";
+ case 6: return ".so mmap";
+ case 7: return ".jar mmap";
+ case 8: return ".apk mmap";
+ case 9: return ".ttf mmap";
+ case 10: return ".dex mmap";
+ case 11: return ".oat mmap";
+ case 12: return ".art mmap";
+ case 13: return "Other mmap";
+ case 14: return "Graphics";
+ case 15: return "GL";
+ case 16: return "Memtrack";
+ case 17: return ".Heap";
+ case 18: return ".LOS";
+ case 19: return ".LinearAlloc";
+ case 20: return ".GC";
+ case 21: return ".JITCache";
default: return "????";
}
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 16250c7..5d5d2b3 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -92,6 +92,11 @@ interface INetworkManagementService
void enableIpv6(String iface);
/**
+ * Enables or enables IPv6 ND offload.
+ */
+ void setInterfaceIpv6NdOffload(String iface, boolean enable);
+
+ /**
* Retrieves the network routes currently configured on the specified
* interface
*/
@@ -336,19 +341,19 @@ interface INetworkManagementService
void removeVpnUidRanges(int netId, in UidRange[] ranges);
/**
- * Start the clatd (464xlat) service
+ * Start the clatd (464xlat) service on the given interface.
*/
void startClatd(String interfaceName);
/**
- * Stop the clatd (464xlat) service
+ * Stop the clatd (464xlat) service on the given interface.
*/
- void stopClatd();
+ void stopClatd(String interfaceName);
/**
- * Determine whether the clatd (464xlat) service has been started
+ * Determine whether the clatd (464xlat) service has been started on the given interface.
*/
- boolean isClatdStarted();
+ boolean isClatdStarted(String interfaceName);
/**
* Start listening for mobile activity state changes.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 182dbee..16dac7d 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -49,7 +49,7 @@ interface IPowerManager
void crash(String message);
void setStayOnSetting(int val);
- void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs);
+ void boostScreenBrightness(long time);
// temporarily overrides the screen brightness settings to allow the user to
// see the effect of a settings change without applying it immediately
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3b6ce53..8307d9b 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -669,6 +669,28 @@ public final class PowerManager {
}
/**
+ * Boosts the brightness of the screen to maximum for a predetermined
+ * period of time. This is used to make the screen more readable in bright
+ * daylight for a short duration.
+ * <p>
+ * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+ * </p>
+ *
+ * @param time The time when the request to boost was issued, in the
+ * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
+ * order the boost request with other power management functions. It should be set
+ * to the timestamp of the input event that caused the request to boost.
+ *
+ * @hide Requires signature permission.
+ */
+ public void boostScreenBrightness(long time) {
+ try {
+ mService.boostScreenBrightness(time);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Sets the brightness of the backlights (screen, keyboard, button).
* <p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 14f4a83..9d78360 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -56,6 +56,13 @@ public abstract class PowerManagerInternal {
public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
/**
+ * Used by device administration to set the maximum screen off timeout.
+ *
+ * This method must only be called by the device administration policy manager.
+ */
+ public abstract void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs);
+
+ /**
* Used by the dream manager to override certain properties while dozing.
*
* @param screenState The overridden screen state, or {@link Display.STATE_UNKNOWN}
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/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl
index 9d384fb..8f33e0b 100644
--- a/core/java/android/print/IPrintDocumentAdapter.aidl
+++ b/core/java/android/print/IPrintDocumentAdapter.aidl
@@ -37,4 +37,5 @@ oneway interface IPrintDocumentAdapter {
void write(in PageRange[] pages, in ParcelFileDescriptor fd,
IWriteResultCallback callback, int sequence);
void finish();
+ void kill(String reason);
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index bf8ac65..3fb812e 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -634,6 +634,17 @@ public final class PrintManager {
}
@Override
+ public void kill(String reason) {
+ synchronized (mLock) {
+ // If destroyed the handler is null.
+ if (!isDestroyedLocked()) {
+ mHandler.obtainMessage(MyHandler.MSG_ON_KILL,
+ reason).sendToTarget();
+ }
+ }
+ }
+
+ @Override
public void onActivityPaused(Activity activity) {
/* do nothing */
}
@@ -719,6 +730,7 @@ public final class PrintManager {
public static final int MSG_ON_LAYOUT = 2;
public static final int MSG_ON_WRITE = 3;
public static final int MSG_ON_FINISH = 4;
+ public static final int MSG_ON_KILL = 5;
public MyHandler(Looper looper) {
super(looper, null, true);
@@ -794,6 +806,15 @@ public final class PrintManager {
}
} break;
+ case MSG_ON_KILL: {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onKill()");
+ }
+
+ String reason = (String) message.obj;
+ throw new RuntimeException(reason);
+ }
+
default: {
throw new IllegalArgumentException("Unknown message: "
+ message.what);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 3e80ed0..3ec45e9 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -24,13 +24,17 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.database.Cursor;
+import android.location.Country;
+import android.location.CountryDetector;
import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract.CommonDataKinds.Callable;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.DataUsageFeedback;
import android.telecom.PhoneAccountHandle;
+import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import com.android.internal.telephony.CallerInfo;
@@ -404,7 +408,6 @@ public class CallLog {
* @param accountHandle The accountHandle object identifying the provider of the call
* @param start time stamp for the call in milliseconds
* @param duration call duration in seconds
- * @param subId the subscription id.
* @param dataUsage data usage for the call in bytes, null if data usage was not tracked for
* the call.
* @param addForAllUsers If true, the call is added to the call log of all currently
@@ -503,12 +506,13 @@ public class CallLog {
if (cursor != null) {
try {
if (cursor.getCount() > 0 && cursor.moveToFirst()) {
- final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
- .appendPath(cursor.getString(0))
- .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
- DataUsageFeedback.USAGE_TYPE_CALL)
- .build();
- resolver.update(feedbackUri, new ContentValues(), null, null);
+ final String dataId = cursor.getString(0);
+ updateDataUsageStatForData(resolver, dataId);
+ if (duration >= MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS
+ && callType == Calls.OUTGOING_TYPE
+ && TextUtils.isEmpty(ci.normalizedNumber)) {
+ updateNormalizedNumber(context, resolver, dataId, number);
+ }
}
} finally {
cursor.close();
@@ -581,5 +585,50 @@ public class CallLog {
+ " LIMIT -1 OFFSET 500)", null);
return result;
}
+
+ private static void updateDataUsageStatForData(ContentResolver resolver, String dataId) {
+ final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon()
+ .appendPath(dataId)
+ .appendQueryParameter(DataUsageFeedback.USAGE_TYPE,
+ DataUsageFeedback.USAGE_TYPE_CALL)
+ .build();
+ resolver.update(feedbackUri, new ContentValues(), null, null);
+ }
+
+ /*
+ * Update the normalized phone number for the given dataId in the ContactsProvider, based
+ * on the user's current country.
+ */
+ private static void updateNormalizedNumber(Context context, ContentResolver resolver,
+ String dataId, String number) {
+ if (TextUtils.isEmpty(number) || TextUtils.isEmpty(dataId)) {
+ return;
+ }
+ final String countryIso = getCurrentCountryIso(context);
+ if (TextUtils.isEmpty(countryIso)) {
+ return;
+ }
+ final String normalizedNumber = PhoneNumberUtils.formatNumberToE164(number,
+ getCurrentCountryIso(context));
+ if (TextUtils.isEmpty(normalizedNumber)) {
+ return;
+ }
+ final ContentValues values = new ContentValues();
+ values.put(Phone.NORMALIZED_NUMBER, normalizedNumber);
+ resolver.update(Data.CONTENT_URI, values, Data._ID + "=?", new String[] {dataId});
+ }
+
+ private static String getCurrentCountryIso(Context context) {
+ String countryIso = null;
+ final CountryDetector detector = (CountryDetector) context.getSystemService(
+ Context.COUNTRY_DETECTOR);
+ if (detector != null) {
+ final Country country = detector.detectCountry();
+ if (country != null) {
+ countryIso = country.getCountryIso();
+ }
+ }
+ return countryIso;
+ }
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4eeb852..1f45f0a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -787,11 +787,10 @@ public final class Settings {
* <p>
* Output: Nothing.
* @see android.service.notification.NotificationListenerService
- * @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS
- = "android.settings.NOTIFICATION_LISTENER_SETTINGS";
+ = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
/**
* @hide
@@ -873,8 +872,9 @@ public final class Settings {
/**
* Activity Action: Show battery saver settings.
- *
- * @hide
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you safeguard
+ * against this.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_BATTERY_SAVER_SETTINGS
@@ -2625,12 +2625,6 @@ public final class Settings {
public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
/**
- * Whether lock-to-app will lock the keyguard when exiting.
- * @hide
- */
- public static final String LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked";
-
- /**
* I am the lolrus.
* <p>
* Nonzero values indicate that the user has a bukkit.
@@ -2704,6 +2698,7 @@ public final class Settings {
POINTER_SPEED,
VIBRATE_WHEN_RINGING,
RINGTONE,
+ LOCK_TO_APP_ENABLED,
NOTIFICATION_SOUND
};
@@ -3666,6 +3661,12 @@ public final class Settings {
"lock_biometric_weak_flags";
/**
+ * Whether lock-to-app will lock the keyguard when exiting.
+ * @hide
+ */
+ public static final String LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked";
+
+ /**
* Whether autolock is enabled (0 = false, 1 = true)
*/
public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
@@ -4587,13 +4588,6 @@ public final class Settings {
public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
/**
- * (Experimental). If nonzero, WebView uses data reduction proxy to save network
- * bandwidth. Otherwise, WebView does not use data reduction proxy.
- * @hide
- */
- public static final String WEBVIEW_DATA_REDUCTION_PROXY = "webview_data_reduction_proxy";
-
- /**
* The {@link ComponentName} string of the service to be used as the voice recognition
* service.
*
@@ -4738,8 +4732,8 @@ public final class Settings {
public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
/**
- * Name of a package that the current user has explicitly allowed to see all of that
- * user's notifications.
+ * Names of the packages that the current user has explicitly allowed to
+ * see all of the user's notifications, separated by ':'.
*
* @hide
*/
@@ -6637,7 +6631,8 @@ public final class Settings {
WIFI_NUM_OPEN_NETWORKS_KEPT,
EMERGENCY_TONE,
CALL_AUTO_RETRY,
- DOCK_AUDIO_MEDIA_ENABLED
+ DOCK_AUDIO_MEDIA_ENABLED,
+ LOW_POWER_MODE_TRIGGER_LEVEL
};
// Populated lazily, guarded by class object:
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 9a84a1e..36401eb 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -78,6 +78,7 @@ public class ZenModeConfig implements Parcelable {
private static final String ALLOW_ATT_EVENTS = "events";
private static final String SLEEP_TAG = "sleep";
private static final String SLEEP_ATT_MODE = "mode";
+ private static final String SLEEP_ATT_NONE = "none";
private static final String SLEEP_ATT_START_HR = "startHour";
private static final String SLEEP_ATT_START_MIN = "startMin";
@@ -107,6 +108,7 @@ public class ZenModeConfig implements Parcelable {
public int sleepStartMinute; // 0-59
public int sleepEndHour;
public int sleepEndMinute;
+ public boolean sleepNone; // false = priority, true = none
public ComponentName[] conditionComponents;
public Uri[] conditionIds;
public Condition exitCondition;
@@ -125,6 +127,7 @@ public class ZenModeConfig implements Parcelable {
sleepStartMinute = source.readInt();
sleepEndHour = source.readInt();
sleepEndMinute = source.readInt();
+ sleepNone = source.readInt() == 1;
int len = source.readInt();
if (len > 0) {
conditionComponents = new ComponentName[len];
@@ -155,6 +158,7 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(sleepStartMinute);
dest.writeInt(sleepEndHour);
dest.writeInt(sleepEndMinute);
+ dest.writeInt(sleepNone ? 1 : 0);
if (conditionComponents != null && conditionComponents.length > 0) {
dest.writeInt(conditionComponents.length);
dest.writeTypedArray(conditionComponents, 0);
@@ -182,6 +186,7 @@ public class ZenModeConfig implements Parcelable {
.append(",sleepMode=").append(sleepMode)
.append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
.append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
+ .append(",sleepNone=").append(sleepNone)
.append(",conditionComponents=")
.append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
.append(",conditionIds=")
@@ -214,6 +219,7 @@ public class ZenModeConfig implements Parcelable {
&& other.allowFrom == allowFrom
&& other.allowEvents == allowEvents
&& Objects.equals(other.sleepMode, sleepMode)
+ && other.sleepNone == sleepNone
&& other.sleepStartHour == sleepStartHour
&& other.sleepStartMinute == sleepStartMinute
&& other.sleepEndHour == sleepEndHour
@@ -226,7 +232,7 @@ public class ZenModeConfig implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(allowCalls, allowMessages, allowFrom, allowEvents, sleepMode,
+ return Objects.hash(allowCalls, allowMessages, allowFrom, allowEvents, sleepMode, sleepNone,
sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute,
Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
exitCondition, exitConditionComponent);
@@ -302,6 +308,7 @@ public class ZenModeConfig implements Parcelable {
} else if (SLEEP_TAG.equals(tag)) {
final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
rt.sleepMode = isValidSleepMode(mode)? mode : null;
+ rt.sleepNone = safeBoolean(parser, SLEEP_ATT_NONE, false);
final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
@@ -345,6 +352,7 @@ public class ZenModeConfig implements Parcelable {
if (sleepMode != null) {
out.attribute(null, SLEEP_ATT_MODE, sleepMode);
}
+ out.attribute(null, SLEEP_ATT_NONE, Boolean.toString(sleepNone));
out.attribute(null, SLEEP_ATT_START_HR, Integer.toString(sleepStartHour));
out.attribute(null, SLEEP_ATT_START_MIN, Integer.toString(sleepStartMinute));
out.attribute(null, SLEEP_ATT_END_HR, Integer.toString(sleepEndHour));
@@ -498,7 +506,7 @@ public class ZenModeConfig implements Parcelable {
}
// For built-in conditions
- private static final String SYSTEM_AUTHORITY = "android";
+ public static final String SYSTEM_AUTHORITY = "android";
// Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
private static final String COUNTDOWN_PATH = "countdown";
diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl
index bd80a3f..bb0c2b2 100644
--- a/core/java/android/service/trust/ITrustAgentService.aidl
+++ b/core/java/android/service/trust/ITrustAgentService.aidl
@@ -15,7 +15,7 @@
*/
package android.service.trust;
-import android.os.Bundle;
+import android.os.PersistableBundle;
import android.service.trust.ITrustAgentServiceCallback;
/**
@@ -25,6 +25,6 @@ import android.service.trust.ITrustAgentServiceCallback;
interface ITrustAgentService {
oneway void onUnlockAttempt(boolean successful);
oneway void onTrustTimeout();
+ oneway void onConfigure(in List<PersistableBundle> options, IBinder token);
oneway void setCallback(ITrustAgentServiceCallback callback);
- oneway void setTrustAgentFeaturesEnabled(in Bundle options, IBinder token);
}
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index b107bcc..76b2be0 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -27,5 +27,5 @@ oneway interface ITrustAgentServiceCallback {
void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser);
void revokeTrust();
void setManagingTrust(boolean managingTrust);
- void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token);
+ void onConfigureCompleted(boolean result, IBinder token);
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 3ef5b37..d6c997f 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -29,11 +29,14 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.Slog;
+import java.util.List;
+
/**
* A service that notifies the system about whether it believes the environment of the device
* to be trusted.
@@ -86,17 +89,22 @@ public class TrustAgentService extends Service {
*/
public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
- /**
- * A white list of features that the given trust agent should support when otherwise disabled
- * by device policy.
- * @hide
- */
- public static final String KEY_FEATURES = "trust_agent_features";
-
private static final int MSG_UNLOCK_ATTEMPT = 1;
- private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2;
+ private static final int MSG_CONFIGURE = 2;
private static final int MSG_TRUST_TIMEOUT = 3;
+ /**
+ * Class containing raw data for a given configuration request.
+ */
+ private static final class ConfigurationData {
+ final IBinder token;
+ final List<PersistableBundle> options;
+ ConfigurationData(List<PersistableBundle> opts, IBinder t) {
+ options = opts;
+ token = t;
+ }
+ }
+
private ITrustAgentServiceCallback mCallback;
private Runnable mPendingGrantTrustTask;
@@ -112,13 +120,12 @@ public class TrustAgentService extends Service {
case MSG_UNLOCK_ATTEMPT:
onUnlockAttempt(msg.arg1 != 0);
break;
- case MSG_SET_TRUST_AGENT_FEATURES_ENABLED:
- Bundle features = msg.peekData();
- IBinder token = (IBinder) msg.obj;
- boolean result = onSetTrustAgentFeaturesEnabled(features);
+ case MSG_CONFIGURE:
+ ConfigurationData data = (ConfigurationData) msg.obj;
+ boolean result = onConfigure(data.options);
try {
synchronized (mLock) {
- mCallback.onSetTrustAgentFeaturesEnabledCompleted(result, token);
+ mCallback.onConfigureCompleted(result, data.token);
}
} catch (RemoteException e) {
onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
@@ -171,23 +178,16 @@ public class TrustAgentService extends Service {
}
/**
- * Called when device policy wants to restrict features in the agent in response to
- * {@link DevicePolicyManager#setTrustAgentFeaturesEnabled(ComponentName, ComponentName, java.util.List) }.
- * Agents that support this feature should overload this method and return 'true'.
+ * Called when device policy admin wants to enable specific options for agent in response to
+ * {@link DevicePolicyManager#setKeyguardDisabledFeatures(ComponentName, int)} and
+ * {@link DevicePolicyManager#setTrustAgentConfiguration(ComponentName, ComponentName,
+ * PersistableBundle)}.
+ * <p>Agents that support configuration options should overload this method and return 'true'.
*
- * The list of options can be obtained by calling
- * options.getStringArrayList({@link #KEY_FEATURES}). Presence of a feature string in the list
- * means it should be enabled ("white-listed"). Absence of the feature means it should be
- * disabled. An empty list means all features should be disabled.
- *
- * This function is only called if {@link DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} is
- * set.
- *
- * @param options Option feature bundle.
- * @return true if the {@link TrustAgentService} supports this feature.
- * @hide
+ * @param options bundle containing all options or null if none.
+ * @return true if the {@link TrustAgentService} supports configuration options.
*/
- public boolean onSetTrustAgentFeaturesEnabled(Bundle options) {
+ public boolean onConfigure(List<PersistableBundle> options) {
return false;
}
@@ -295,6 +295,12 @@ public class TrustAgentService extends Service {
}
@Override /* Binder API */
+ public void onConfigure(List<PersistableBundle> args, IBinder token) {
+ mHandler.obtainMessage(MSG_CONFIGURE, new ConfigurationData(args, token))
+ .sendToTarget();
+ }
+
+ @Override /* Binder API */
public void setCallback(ITrustAgentServiceCallback callback) {
synchronized (mLock) {
mCallback = callback;
@@ -313,13 +319,6 @@ public class TrustAgentService extends Service {
}
}
}
-
- @Override /* Binder API */
- public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) {
- Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token);
- msg.setData(features);
- msg.sendToTarget();
- }
}
}
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/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 9fec9a1..933bcee 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -60,27 +60,45 @@ import libcore.icu.LocaleData;
* {@code SimpleDateFormat}.
*/
public class DateFormat {
- /** @deprecated Use a literal {@code '} instead. */
+ /**
+ * @deprecated Use a literal {@code '} instead.
+ * @removed
+ */
@Deprecated
public static final char QUOTE = '\'';
- /** @deprecated Use a literal {@code 'a'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'a'} instead.
+ * @removed
+ */
@Deprecated
public static final char AM_PM = 'a';
- /** @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'. */
+ /**
+ * @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'.
+ * @removed
+ */
@Deprecated
public static final char CAPITAL_AM_PM = 'A';
- /** @deprecated Use a literal {@code 'd'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'd'} instead.
+ * @removed
+ */
@Deprecated
public static final char DATE = 'd';
- /** @deprecated Use a literal {@code 'E'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'E'} instead.
+ * @removed
+ */
@Deprecated
public static final char DAY = 'E';
- /** @deprecated Use a literal {@code 'h'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'h'} instead.
+ * @removed
+ */
@Deprecated
public static final char HOUR = 'h';
@@ -88,31 +106,51 @@ public class DateFormat {
* @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat}
* and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including
* Jelly Bean MR-1) instead. Note that the two are incompatible.
+ *
+ * @removed
*/
@Deprecated
public static final char HOUR_OF_DAY = 'k';
- /** @deprecated Use a literal {@code 'm'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'm'} instead.
+ * @removed
+ */
@Deprecated
public static final char MINUTE = 'm';
- /** @deprecated Use a literal {@code 'M'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'M'} instead.
+ * @removed
+ */
@Deprecated
public static final char MONTH = 'M';
- /** @deprecated Use a literal {@code 'L'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'L'} instead.
+ * @removed
+ */
@Deprecated
public static final char STANDALONE_MONTH = 'L';
- /** @deprecated Use a literal {@code 's'} instead. */
+ /**
+ * @deprecated Use a literal {@code 's'} instead.
+ * @removed
+ */
@Deprecated
public static final char SECONDS = 's';
- /** @deprecated Use a literal {@code 'z'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'z'} instead.
+ * @removed
+ */
@Deprecated
public static final char TIME_ZONE = 'z';
- /** @deprecated Use a literal {@code 'y'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'y'} instead.
+ * @removed
+ */
@Deprecated
public static final char YEAR = 'y';
@@ -306,9 +344,9 @@ public class DateFormat {
}
/**
- * Gets the current date format stored as a char array. The array will contain
- * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order
- * specified by the user's format preference. Note that this order is
+ * Gets the current date format stored as a char array. Returns a 3 element
+ * array containing the day ({@code 'd'}), month ({@code 'M'}), and year ({@code 'y'}))
+ * in the order specified by the user's format preference. Note that this order is
* <i>only</i> appropriate for all-numeric dates; spelled-out (MEDIUM and LONG)
* dates will generally contain other punctuation, spaces, or words,
* not just the day, month, and year, and not necessarily in the same
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index b0cbcd2..b467f5a 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -110,6 +110,7 @@ public final class Formatter {
private static final int SECONDS_PER_MINUTE = 60;
private static final int SECONDS_PER_HOUR = 60 * 60;
private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+ private static final int MILLIS_PER_MINUTE = 1000 * 60;
/**
* Returns elapsed time for the given millis, in the following format:
@@ -171,4 +172,24 @@ public final class Formatter {
return context.getString(com.android.internal.R.string.durationSeconds, seconds);
}
}
+
+ /**
+ * Returns elapsed time for the given millis, in the following format:
+ * 1 day 5 hrs; will include at most two units, can go down to minutes precision.
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
+ * @return the formatted elapsed time
+ * @hide
+ */
+ public static String formatShortElapsedTimeRoundingUpToMinutes(Context context, long millis) {
+ long minutesRoundedUp = (millis + MILLIS_PER_MINUTE - 1) / MILLIS_PER_MINUTE;
+
+ if (minutesRoundedUp == 0) {
+ return context.getString(com.android.internal.R.string.durationMinutes, 0);
+ } else if (minutesRoundedUp == 1) {
+ return context.getString(com.android.internal.R.string.durationMinute, 1);
+ }
+
+ return formatShortElapsedTime(context, minutesRoundedUp * MILLIS_PER_MINUTE);
+ }
}
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/transition/Transition.java b/core/java/android/transition/Transition.java
index e99c2cf..2705bcf 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -84,8 +84,8 @@ import com.android.internal.R;
*
* <p>Custom transition classes may be instantiated with a <code>transition</code> tag:</p>
* <pre>&lt;transition class="my.app.transition.CustomTransition"/></pre>
- * <p>Custom transition classes loaded from XML must have a public nullary (no argument)
- * constructor.</p>
+ * <p>Custom transition classes loaded from XML should have a public constructor taking
+ * a {@link android.content.Context} and {@link android.util.AttributeSet}.</p>
*
* <p>Note that attributes for the transition are not required, just as they are
* optional when declared in code; Transitions created from XML resources will use
@@ -955,7 +955,7 @@ public abstract class Transition implements Cloneable {
* Views with different IDs, or no IDs whatsoever, will be ignored.
*
* <p>Note that using ids to specify targets implies that ids should be unique
- * within the view hierarchy underneat the scene root.</p>
+ * within the view hierarchy underneath the scene root.</p>
*
* @see View#getId()
* @param targetId The id of a target view, must be a positive number.
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 931fb81..74d4245 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -139,6 +139,17 @@ public class TypedValue {
/* ------------------------------------------------------------ */
/**
+ * {@link #TYPE_NULL} data indicating the value was not specified.
+ */
+ public static final int DATA_NULL_UNDEFINED = 0;
+ /**
+ * {@link #TYPE_NULL} data indicating the value was explicitly set to null.
+ */
+ public static final int DATA_NULL_EMPTY = 1;
+
+ /* ------------------------------------------------------------ */
+
+ /**
* If {@link #density} is equal to this value, then the density should be
* treated as the system's default density value: {@link DisplayMetrics#DENSITY_DEFAULT}.
*/
@@ -301,6 +312,18 @@ public class TypedValue {
}
/**
+ * Return the complex unit type for this value. For example, a dimen type
+ * with value 12sp will return {@link #COMPLEX_UNIT_SP}. Only use for values
+ * whose type is {@link #TYPE_DIMENSION}.
+ *
+ * @return The complex unit type.
+ */
+ public int getComplexUnit()
+ {
+ return COMPLEX_UNIT_MASK & (data>>TypedValue.COMPLEX_UNIT_SHIFT);
+ }
+
+ /**
* Converts an unpacked complex data value holding a dimension to its final floating
* point value. The two parameters <var>unit</var> and <var>value</var>
* are as in {@link #TYPE_DIMENSION}.
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 1cadf69..5e05683 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -1109,15 +1109,17 @@ final class AccessibilityInteractionController {
|| accessibilityViewId == providerHost.getAccessibilityViewId()) {
final AccessibilityNodeInfo parent;
if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- parent = provider.createAccessibilityNodeInfo(
- virtualDescendantId);
+ parent = provider.createAccessibilityNodeInfo(virtualDescendantId);
} else {
- parent= provider.createAccessibilityNodeInfo(
+ parent = provider.createAccessibilityNodeInfo(
AccessibilityNodeProvider.HOST_VIEW_ID);
}
- if (parent != null) {
- outInfos.add(parent);
+ if (parent == null) {
+ // Couldn't obtain the parent, which means we have a
+ // disconnected sub-tree. Abort prefetch immediately.
+ return;
}
+ outInfos.add(parent);
parentNodeId = parent.getParentNodeId();
accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
parentNodeId);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 1b57c24..b86455a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -242,7 +242,7 @@ class GLES20Canvas extends HardwareCanvas {
void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
layer.setLayerPaint(paint);
- nDrawLayer(mRenderer, layer.getLayer(), x, y);
+ nDrawLayer(mRenderer, layer.getLayerHandle(), x, y);
}
private static native void nDrawLayer(long renderer, long layer, float x, float y);
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 0c2e944..a130bda 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -126,8 +126,8 @@ final class HardwareLayer {
mRenderer.detachSurfaceTexture(mFinalizer.get());
}
- public long getLayer() {
- return nGetLayer(mFinalizer.get());
+ public long getLayerHandle() {
+ return mFinalizer.get();
}
public void setSurfaceTexture(SurfaceTexture surface) {
@@ -153,6 +153,5 @@ final class HardwareLayer {
private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
int left, int top, int right, int bottom);
- private static native long nGetLayer(long layerUpdater);
private static native int nGetTexName(long layerUpdater);
}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3e7aae0..9fc80fc 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -85,4 +85,9 @@ oneway interface IWindow {
* is done.
*/
void doneAnimating();
+
+ /**
+ * Called for non-application windows when the enter animation has completed.
+ */
+ void dispatchWindowShown();
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 6aa86c7..7b20e72 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -96,6 +96,7 @@ interface IWindowManager
void overridePendingAppTransitionAspectScaledThumb(in Bitmap srcThumb, int startX,
int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
boolean scaleUp);
+ void overridePendingAppTransitionInPlace(String packageName, int anim);
void executeAppTransition();
void setAppStartingWindow(IBinder token, String pkg, int theme,
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
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/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index debf45d..b95f9a4 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -219,7 +219,7 @@ public class RenderNodeAnimator extends Animator {
@Override
public void cancel() {
- if (mState != STATE_FINISHED) {
+ if (mState != STATE_PREPARE && mState != STATE_FINISHED) {
if (mState == STATE_DELAYED) {
getHelper().removeDelayedAnimation(this);
notifyStartListeners();
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 562d138..19142b8 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -319,6 +319,7 @@ public class Surface implements Parcelable {
* @return A canvas for drawing into the surface.
*
* @throws IllegalStateException If the canvas cannot be locked.
+ * @hide
*/
public Canvas lockHardwareCanvas() {
synchronized (mLock) {
@@ -603,15 +604,6 @@ public class Surface implements Parcelable {
mHwuiRenderer = 0;
}
}
-
- @Override
- protected void finalize() throws Throwable {
- try {
- destroy();
- } finally {
- super.finalize();
- }
- }
}
private static native long nHwuiCreate(long rootNode, long surface);
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 0711aed..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,
@@ -191,7 +193,8 @@ public class ThreadedRenderer extends HardwareRenderer {
final float lightX = width / 2.0f;
mWidth = width;
mHeight = height;
- if (surfaceInsets != null && !surfaceInsets.isEmpty()) {
+ if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
+ || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
mHasInsets = true;
mInsetLeft = surfaceInsets.left;
mInsetTop = surfaceInsets.top;
@@ -335,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/View.java b/core/java/android/view/View.java
index e7b98ca..1d09696 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3109,6 +3109,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
private MatchLabelForPredicate mMatchLabelForPredicate;
/**
+ * Specifies a view before which this one is visited in accessibility traversal.
+ */
+ private int mAccessibilityTraversalBeforeId = NO_ID;
+
+ /**
+ * Specifies a view after which this one is visited in accessibility traversal.
+ */
+ private int mAccessibilityTraversalAfterId = NO_ID;
+
+ /**
* Predicate for matching a view by its id.
*/
private MatchIdPredicate mMatchIdPredicate;
@@ -3229,6 +3239,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
+ protected OnScrollChangeListener mOnScrollChangeListener;
+
/**
* Listeners for attach events.
*/
@@ -3886,6 +3898,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
case com.android.internal.R.styleable.View_contentDescription:
setContentDescription(a.getString(attr));
break;
+ case com.android.internal.R.styleable.View_accessibilityTraversalBefore:
+ setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID));
+ break;
+ case com.android.internal.R.styleable.View_accessibilityTraversalAfter:
+ setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID));
+ break;
case com.android.internal.R.styleable.View_labelFor:
setLabelFor(a.getResourceId(attr, NO_ID));
break;
@@ -4606,6 +4624,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Register a callback to be invoked when the scroll position of this view
+ * changed.
+ *
+ * @param l The callback that will run.
+ * @hide Only used internally.
+ */
+ public void setOnScrollChangeListener(OnScrollChangeListener l) {
+ getListenerInfo().mOnScrollChangeListener = l;
+ }
+
+ /**
* Register a callback to be invoked when focus of this view changed.
*
* @param l The callback that will run.
@@ -5598,6 +5627,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (rootView == null) {
rootView = this;
}
+
View label = rootView.findLabelForView(this, mID);
if (label != null) {
info.setLabeledBy(label);
@@ -5626,6 +5656,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ if (mAccessibilityTraversalBeforeId != View.NO_ID) {
+ View rootView = getRootView();
+ if (rootView == null) {
+ rootView = this;
+ }
+ View next = rootView.findViewInsideOutShouldExist(this,
+ mAccessibilityTraversalBeforeId);
+ if (next != null) {
+ info.setTraversalBefore(next);
+ }
+ }
+
+ if (mAccessibilityTraversalAfterId != View.NO_ID) {
+ View rootView = getRootView();
+ if (rootView == null) {
+ rootView = this;
+ }
+ View next = rootView.findViewInsideOutShouldExist(this,
+ mAccessibilityTraversalAfterId);
+ if (next != null) {
+ info.setTraversalAfter(next);
+ }
+ }
+
info.setVisibleToUser(isVisibleToUser());
info.setPackageName(mContext.getPackageName());
@@ -6030,6 +6084,94 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Sets the id of a view before which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of this view before the content of the one
+ * it precedes. For example, if view B is set to be before view A, then a screen-reader
+ * will traverse the entire content of B before traversing the entire content of A,
+ * regardles of what traversal strategy it is using.
+ * <p>
+ * Views that do not have specified before/after relationships are traversed in order
+ * determined by the screen-reader.
+ * </p>
+ * <p>
+ * Setting that this view is before a view that is not important for accessibility
+ * or if this view is not important for accessibility will have no effect as the
+ * screen-reader is not aware of unimportant views.
+ * </p>
+ *
+ * @param beforeId The id of a view this one precedes in accessibility traversal.
+ *
+ * @attr ref android.R.styleable#View_accessibilityTraversalBefore
+ *
+ * @see #setImportantForAccessibility(int)
+ */
+ @RemotableViewMethod
+ public void setAccessibilityTraversalBefore(int beforeId) {
+ if (mAccessibilityTraversalBeforeId == beforeId) {
+ return;
+ }
+ mAccessibilityTraversalBeforeId = beforeId;
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+
+ /**
+ * Gets the id of a view before which this one is visited in accessibility traversal.
+ *
+ * @return The id of a view this one precedes in accessibility traversal if
+ * specified, otherwise {@link #NO_ID}.
+ *
+ * @see #setAccessibilityTraversalBefore(int)
+ */
+ public int getAccessibilityTraversalBefore() {
+ return mAccessibilityTraversalBeforeId;
+ }
+
+ /**
+ * Sets the id of a view after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other view before the content of this
+ * one. For example, if view B is set to be after view A, then a screen-reader
+ * will traverse the entire content of A before traversing the entire content of B,
+ * regardles of what traversal strategy it is using.
+ * <p>
+ * Views that do not have specified before/after relationships are traversed in order
+ * determined by the screen-reader.
+ * </p>
+ * <p>
+ * Setting that this view is after a view that is not important for accessibility
+ * or if this view is not important for accessibility will have no effect as the
+ * screen-reader is not aware of unimportant views.
+ * </p>
+ *
+ * @param afterId The id of a view this one succedees in accessibility traversal.
+ *
+ * @attr ref android.R.styleable#View_accessibilityTraversalAfter
+ *
+ * @see #setImportantForAccessibility(int)
+ */
+ @RemotableViewMethod
+ public void setAccessibilityTraversalAfter(int afterId) {
+ if (mAccessibilityTraversalAfterId == afterId) {
+ return;
+ }
+ mAccessibilityTraversalAfterId = afterId;
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
+
+ /**
+ * Gets the id of a view after which this one is visited in accessibility traversal.
+ *
+ * @return The id of a view this one succeedes in accessibility traversal if
+ * specified, otherwise {@link #NO_ID}.
+ *
+ * @see #setAccessibilityTraversalAfter(int)
+ */
+ public int getAccessibilityTraversalAfter() {
+ return mAccessibilityTraversalAfterId;
+ }
+
+ /**
* Gets the id of a view for which this view serves as a label for
* accessibility purposes.
*
@@ -6048,11 +6190,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@RemotableViewMethod
public void setLabelFor(int id) {
+ if (mLabelForId == id) {
+ return;
+ }
mLabelForId = id;
if (mLabelForId != View.NO_ID
&& mID == View.NO_ID) {
mID = generateViewId();
}
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
/**
@@ -9794,6 +9941,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (ai != null) {
ai.mViewScrollChanged = true;
}
+
+ if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) {
+ mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
+ }
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the scroll
+ * position of a view changes.
+ *
+ * @hide Only used internally.
+ */
+ public interface OnScrollChangeListener {
+ /**
+ * Called when the scroll position of a view changes.
+ *
+ * @param v The view whose scroll position has changed.
+ * @param scrollX Current horizontal scroll origin.
+ * @param scrollY Current vertical scroll origin.
+ * @param oldScrollX Previous horizontal scroll origin.
+ * @param oldScrollY Previous vertical scroll origin.
+ */
+ void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
}
/**
@@ -14062,7 +14232,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
draw(canvas);
}
- drawAccessibilityFocus(canvas);
}
} finally {
renderNode.end(canvas);
@@ -14357,7 +14526,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
draw(canvas);
}
- drawAccessibilityFocus(canvas);
canvas.restoreToCount(restoreCount);
canvas.setBitmap(null);
@@ -14432,7 +14600,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
draw(canvas);
}
- drawAccessibilityFocus(canvas);
mPrivateFlags = flags;
@@ -15030,13 +15197,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
dispatchDraw(canvas);
- if (mOverlay != null && !mOverlay.isEmpty()) {
- mOverlay.getOverlayView().draw(canvas);
- }
} else {
draw(canvas);
}
- drawAccessibilityFocus(canvas);
} else {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
((HardwareCanvas) canvas).drawRenderNode(renderNode, null, flags);
@@ -15288,50 +15451,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Draws the accessibility focus rect onto the specified canvas.
- *
- * @param canvas Canvas on which to draw the focus rect
- */
- private void drawAccessibilityFocus(Canvas canvas) {
- if (mAttachInfo == null) {
- return;
- }
-
- final Rect bounds = mAttachInfo.mTmpInvalRect;
- final ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot == null || viewRoot.getAccessibilityFocusedHost() != this) {
- return;
- }
-
- final AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
- if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
- return;
- }
-
- final Drawable drawable = viewRoot.getAccessibilityFocusedDrawable();
- if (drawable == null) {
- return;
- }
-
- final AccessibilityNodeInfo virtualView = viewRoot.getAccessibilityFocusedVirtualView();
- if (virtualView != null) {
- virtualView.getBoundsInScreen(bounds);
- final int[] offset = mAttachInfo.mTmpLocation;
- getLocationOnScreen(offset);
- bounds.offset(-offset[0], -offset[1]);
- } else {
- bounds.set(0, 0, mRight - mLeft, mBottom - mTop);
- }
-
- canvas.save();
- canvas.translate(mScrollX, mScrollY);
- canvas.clipRect(bounds, Region.Op.REPLACE);
- drawable.setBounds(bounds);
- drawable.draw(canvas);
- canvas.restore();
- }
-
- /**
* Draws the background onto the specified canvas.
*
* @param canvas Canvas on which to draw the background
@@ -16353,6 +16472,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (tintInfo.mHasTintMode) {
mBackground.setTintMode(tintInfo.mTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mBackground.isStateful()) {
+ mBackground.setState(getDrawableState());
+ }
}
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7c7e3e7..5c433c1 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2582,15 +2582,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* Returns true if this ViewGroup should be considered as a single entity for removal
* when executing an Activity transition. If this is false, child elements will move
* individually during the transition.
+ *
* @return True if the ViewGroup should be acted on together during an Activity transition.
- * The default value is false when the background is null and true when the background
- * is not null or if {@link #getTransitionName()} is not null.
+ * The default value is true when there is a non-null background or if
+ * {@link #getTransitionName()} is not null or if a
+ * non-null {@link android.view.ViewOutlineProvider} other than
+ * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
+ * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
*/
public boolean isTransitionGroup() {
if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
} else {
- return getBackground() != null || getTransitionName() != null;
+ final ViewOutlineProvider outlineProvider = getOutlineProvider();
+ return getBackground() != null || getTransitionName() != null ||
+ (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
}
}
@@ -4250,9 +4256,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
clearChildFocus = true;
}
- if (view.isAccessibilityFocused()) {
- view.clearAccessibilityFocus();
- }
+ view.clearAccessibilityFocus();
cancelTouchTarget(view);
cancelHoverTarget(view);
@@ -4345,9 +4349,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
clearChildFocus = true;
}
- if (view.isAccessibilityFocused()) {
- view.clearAccessibilityFocus();
- }
+ view.clearAccessibilityFocus();
cancelTouchTarget(view);
cancelHoverTarget(view);
@@ -4432,9 +4434,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
clearChildFocus = true;
}
- if (view.isAccessibilityFocused()) {
- view.clearAccessibilityFocus();
- }
+ view.clearAccessibilityFocus();
cancelTouchTarget(view);
cancelHoverTarget(view);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 81fc966..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;
@@ -727,7 +727,10 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mHardwareRenderer.destroy();
}
- final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+ final Rect insets = attrs.surfaceInsets;
+ final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
+ || insets.top != 0 || insets.bottom != 0;
+ final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
@@ -1646,6 +1649,9 @@ public final class ViewRootImpl implements ViewParent,
mLastScrolledFocus.clear();
}
mScrollY = mCurScrollY = 0;
+ if (mView instanceof RootViewSurfaceTaker) {
+ ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
+ }
if (mScroller != null) {
mScroller.abortAnimation();
}
@@ -1740,8 +1746,8 @@ public final class ViewRootImpl implements ViewParent,
if (hwInitialized ||
mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
- final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
- mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight, surfaceInsets);
+ mAttachInfo.mHardwareRenderer.setup(
+ mWidth, mHeight, mWindowAttributes.surfaceInsets);
if (!hwInitialized) {
mAttachInfo.mHardwareRenderer.invalidate(mSurface);
mFullRedrawNeeded = true;
@@ -2255,6 +2261,7 @@ public final class ViewRootImpl implements ViewParent,
canvas.drawHardwareLayer(mResizeBuffer, mHardwareXOffset, mHardwareYOffset,
mResizePaint);
}
+ drawAccessibilityFocusedDrawableIfNeeded(canvas);
}
/**
@@ -2415,6 +2422,9 @@ public final class ViewRootImpl implements ViewParent,
if (mCurScrollY != curScrollY) {
mCurScrollY = curScrollY;
fullRedrawNeeded = true;
+ if (mView instanceof RootViewSurfaceTaker) {
+ ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
+ }
}
final float appScale = mAttachInfo.mApplicationScale;
@@ -2474,18 +2484,38 @@ public final class ViewRootImpl implements ViewParent,
dirty.offset(surfaceInsets.left, surfaceInsets.right);
}
- if (!dirty.isEmpty() || mIsAnimating) {
+ boolean accessibilityFocusDirty = false;
+ final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
+ if (drawable != null) {
+ final Rect bounds = mAttachInfo.mTmpInvalRect;
+ final boolean hasFocus = getAccessibilityFocusedRect(bounds);
+ if (!hasFocus) {
+ bounds.setEmpty();
+ }
+ if (!bounds.equals(drawable.getBounds())) {
+ accessibilityFocusDirty = true;
+ }
+ }
+
+ if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
+ // If accessibility focus moved, always invalidate the root.
+ boolean invalidateRoot = accessibilityFocusDirty;
+
// Draw with hardware renderer.
mIsAnimating = false;
- boolean invalidateRoot = false;
+
if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
mHardwareYOffset = yOffset;
mHardwareXOffset = xOffset;
- mAttachInfo.mHardwareRenderer.invalidateRoot();
+ invalidateRoot = true;
}
mResizeAlpha = resizeAlpha;
+ if (invalidateRoot) {
+ mAttachInfo.mHardwareRenderer.invalidateRoot();
+ }
+
dirty.setEmpty();
mBlockResizeBuffer = false;
@@ -2604,6 +2634,8 @@ public final class ViewRootImpl implements ViewParent,
attachInfo.mSetIgnoreDirtyState = false;
mView.draw(canvas);
+
+ drawAccessibilityFocusedDrawableIfNeeded(canvas);
} finally {
if (!attachInfo.mSetIgnoreDirtyState) {
// Only clear the flag if it was not set during the mView.draw() call
@@ -2627,7 +2659,56 @@ public final class ViewRootImpl implements ViewParent,
return true;
}
- Drawable getAccessibilityFocusedDrawable() {
+ /**
+ * We want to draw a highlight around the current accessibility focused.
+ * Since adding a style for all possible view is not a viable option we
+ * have this specialized drawing method.
+ *
+ * Note: We are doing this here to be able to draw the highlight for
+ * virtual views in addition to real ones.
+ *
+ * @param canvas The canvas on which to draw.
+ */
+ private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
+ final Rect bounds = mAttachInfo.mTmpInvalRect;
+ if (getAccessibilityFocusedRect(bounds)) {
+ final Drawable drawable = getAccessibilityFocusedDrawable();
+ if (drawable != null) {
+ drawable.setBounds(bounds);
+ drawable.draw(canvas);
+ }
+ } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
+ mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
+ }
+ }
+
+ private boolean getAccessibilityFocusedRect(Rect bounds) {
+ final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
+ if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
+ return false;
+ }
+
+ final View host = mAccessibilityFocusedHost;
+ if (host == null || host.mAttachInfo == null) {
+ return false;
+ }
+
+ final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
+ if (provider == null) {
+ host.getBoundsOnScreen(bounds);
+ } else if (mAccessibilityFocusedVirtualView != null) {
+ mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
+ } else {
+ return false;
+ }
+
+ final AttachInfo attachInfo = mAttachInfo;
+ bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
+ bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, attachInfo.mViewRootImpl.mHeight);
+ return !bounds.isEmpty();
+ }
+
+ private Drawable getAccessibilityFocusedDrawable() {
// Lazily load the accessibility focus drawable.
if (mAttachInfo.mAccessibilityFocusDrawable == null) {
final TypedValue value = new TypedValue();
@@ -3014,6 +3095,7 @@ public final class ViewRootImpl implements ViewParent,
private final static int MSG_INVALIDATE_WORLD = 23;
private final static int MSG_WINDOW_MOVED = 24;
private final static int MSG_SYNTHESIZE_INPUT_EVENT = 25;
+ private final static int MSG_DISPATCH_WINDOW_SHOWN = 26;
final class ViewRootHandler extends Handler {
@Override
@@ -3063,6 +3145,8 @@ public final class ViewRootImpl implements ViewParent,
return "MSG_WINDOW_MOVED";
case MSG_SYNTHESIZE_INPUT_EVENT:
return "MSG_SYNTHESIZE_INPUT_EVENT";
+ case MSG_DISPATCH_WINDOW_SHOWN:
+ return "MSG_DISPATCH_WINDOW_SHOWN";
}
return super.getMessageName(message);
}
@@ -3291,6 +3375,9 @@ public final class ViewRootImpl implements ViewParent,
invalidateWorld(mView);
}
} break;
+ case MSG_DISPATCH_WINDOW_SHOWN: {
+ handleDispatchWindowShown();
+ }
}
}
}
@@ -5137,6 +5224,10 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ public void handleDispatchWindowShown() {
+ mAttachInfo.mTreeObserver.dispatchOnWindowShown();
+ }
+
public void getLastTouchPoint(Point outLocation) {
outLocation.x = (int) mLastTouchPoint.x;
outLocation.y = (int) mLastTouchPoint.y;
@@ -5997,6 +6088,10 @@ public final class ViewRootImpl implements ViewParent,
mHandler.sendMessage(msg);
}
+ public void dispatchWindowShown() {
+ mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
+ }
+
public void dispatchCloseSystemDialogs(String reason) {
Message msg = Message.obtain();
msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
@@ -6507,6 +6602,14 @@ public final class ViewRootImpl implements ViewParent,
viewAncestor.dispatchDoneAnimating();
}
}
+
+ @Override
+ public void dispatchWindowShown() {
+ final ViewRootImpl viewAncestor = mViewAncestor.get();
+ if (viewAncestor != null) {
+ viewAncestor.dispatchWindowShown();
+ }
+ }
}
public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index a9444b4..b85fec8 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -44,10 +44,15 @@ public final class ViewTreeObserver {
private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
+ private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners;
// These listeners cannot be mutated during dispatch
private ArrayList<OnDrawListener> mOnDrawListeners;
+ /** Remains false until #dispatchOnWindowShown() is called. If a listener registers after
+ * that the listener will be immediately called. */
+ private boolean mWindowShown;
+
private boolean mAlive = true;
/**
@@ -174,6 +179,19 @@ public final class ViewTreeObserver {
}
/**
+ * Interface definition for a callback noting when a system window has been displayed.
+ * This is only used for non-Activity windows. Activity windows can use
+ * Activity.onEnterAnimationComplete() to get the same signal.
+ * @hide
+ */
+ public interface OnWindowShownListener {
+ /**
+ * Callback method to be invoked when a non-activity window is fully shown.
+ */
+ void onWindowShown();
+ }
+
+ /**
* Parameters used with OnComputeInternalInsetsListener.
*
* We are not yet ready to commit to this API and support it, so
@@ -375,6 +393,14 @@ public final class ViewTreeObserver {
}
}
+ if (observer.mOnWindowShownListeners != null) {
+ if (mOnWindowShownListeners != null) {
+ mOnWindowShownListeners.addAll(observer.mOnWindowShownListeners);
+ } else {
+ mOnWindowShownListeners = observer.mOnWindowShownListeners;
+ }
+ }
+
observer.kill();
}
@@ -568,6 +594,45 @@ public final class ViewTreeObserver {
}
/**
+ * Register a callback to be invoked when the view tree window has been shown
+ *
+ * @param listener The callback to add
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ * @hide
+ */
+ public void addOnWindowShownListener(OnWindowShownListener listener) {
+ checkIsAlive();
+
+ if (mOnWindowShownListeners == null) {
+ mOnWindowShownListeners = new CopyOnWriteArray<OnWindowShownListener>();
+ }
+
+ mOnWindowShownListeners.add(listener);
+ if (mWindowShown) {
+ listener.onWindowShown();
+ }
+ }
+
+ /**
+ * Remove a previously installed window shown callback
+ *
+ * @param victim The callback to remove
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @see #addOnWindowShownListener(OnWindowShownListener)
+ * @hide
+ */
+ public void removeOnWindowShownListener(OnWindowShownListener victim) {
+ checkIsAlive();
+ if (mOnWindowShownListeners == null) {
+ return;
+ }
+ mOnWindowShownListeners.remove(victim);
+ }
+
+ /**
* <p>Register a callback to be invoked when the view tree is about to be drawn.</p>
* <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
* {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
@@ -854,6 +919,27 @@ public final class ViewTreeObserver {
}
/**
+ * Notifies registered listeners that the window is now shown
+ * @hide
+ */
+ @SuppressWarnings("unchecked")
+ public final void dispatchOnWindowShown() {
+ mWindowShown = true;
+ final CopyOnWriteArray<OnWindowShownListener> listeners = mOnWindowShownListeners;
+ if (listeners != null && listeners.size() > 0) {
+ CopyOnWriteArray.Access<OnWindowShownListener> access = listeners.start();
+ try {
+ int count = access.size();
+ for (int i = 0; i < count; i++) {
+ access.get(i).onWindowShown();
+ }
+ } finally {
+ listeners.end();
+ }
+ }
+ }
+
+ /**
* Notifies registered listeners that the drawing pass is about to start.
*/
public final void dispatchOnDraw() {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 20edeb8..0076abf 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1074,17 +1074,36 @@ public abstract class Window {
public abstract void onConfigurationChanged(Configuration newConfig);
/**
+ * Sets the window elevation.
+ *
+ * @param elevation The window elevation.
+ * @see View#setElevation(float)
+ * @see android.R.styleable#Window_windowElevation
+ */
+ public void setElevation(float elevation) {}
+
+ /**
+ * Sets whether window content should be clipped to the outline of the
+ * window background.
+ *
+ * @param clipToOutline Whether window content should be clipped to the
+ * outline of the window background.
+ * @see View#setClipToOutline(boolean)
+ * @see android.R.styleable#Window_windowClipToOutline
+ */
+ public void setClipToOutline(boolean clipToOutline) {}
+
+ /**
* Change the background of this window to a Drawable resource. Setting the
* background to null will make the window be opaque. To make the window
* transparent, you can use an empty drawable (for instance a ColorDrawable
* with the color 0 or the system drawable android:drawable/empty.)
*
- * @param resid The resource identifier of a drawable resource which will be
- * installed as the new background.
+ * @param resId The resource identifier of a drawable resource which will
+ * be installed as the new background.
*/
- public void setBackgroundDrawableResource(int resid)
- {
- setBackgroundDrawable(mContext.getDrawable(resid));
+ public void setBackgroundDrawableResource(int resId) {
+ setBackgroundDrawable(mContext.getDrawable(resId));
}
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 5b48c0d..f4f047e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1324,7 +1324,7 @@ public interface WindowManager extends ViewManager {
*
* @hide
*/
- public Rect surfaceInsets = new Rect();
+ public final Rect surfaceInsets = new Rect();
/**
* The desired bitmap format. May be one of the constants in
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 5926d5f..82b1073 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -118,6 +118,9 @@ public final class WindowManagerGlobal {
private Runnable mSystemPropertyUpdater;
+ /** Default token to apply to added views. */
+ private IBinder mDefaultToken;
+
private WindowManagerGlobal() {
}
@@ -169,6 +172,17 @@ public final class WindowManagerGlobal {
}
}
+ /**
+ * Sets the default token to use in {@link #addView} when no parent window
+ * token is available and no token has been explicitly set in the view's
+ * layout params.
+ *
+ * @param token Default window token to apply to added views.
+ */
+ public void setDefaultToken(IBinder token) {
+ mDefaultToken = token;
+ }
+
public String[] getViewRootNames() {
synchronized (mLock) {
final int numRoots = mRoots.size();
@@ -216,6 +230,10 @@ public final class WindowManagerGlobal {
}
}
+ if (wparams.token == null && mDefaultToken != null) {
+ wparams.token = mDefaultToken;
+ }
+
ViewRootImpl root;
View panelParentView = 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/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 3987fbc..b5afdf7 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -547,6 +547,8 @@ public class AccessibilityNodeInfo implements Parcelable {
private long mParentNodeId = ROOT_NODE_ID;
private long mLabelForId = ROOT_NODE_ID;
private long mLabeledById = ROOT_NODE_ID;
+ private long mTraversalBefore = ROOT_NODE_ID;
+ private long mTraversalAfter = ROOT_NODE_ID;
private int mBooleanProperties;
private final Rect mBoundsInParent = new Rect();
@@ -1046,6 +1048,126 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the node before which this one is visited during traversal. A screen-reader
+ * must visit the content of this node before the content of the one it precedes.
+ *
+ * @return The succeeding node if such or <code>null</code>.
+ *
+ * @see #setTraversalBefore(android.view.View)
+ * @see #setTraversalBefore(android.view.View, int)
+ */
+ public AccessibilityNodeInfo getTraversalBefore() {
+ enforceSealed();
+ return getNodeForAccessibilityId(mTraversalBefore);
+ }
+
+ /**
+ * Sets the view before whose node this one should be visited during traversal. A
+ * screen-reader must visit the content of this node before the content of the one
+ * it precedes.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param view The view providing the preceding node.
+ *
+ * @see #getTraversalBefore()
+ */
+ public void setTraversalBefore(View view) {
+ setTraversalBefore(view, UNDEFINED_ITEM_ID);
+ }
+
+ /**
+ * Sets the node before which this one is visited during traversal. A screen-reader
+ * must visit the content of this node before the content of the one it precedes.
+ * The successor is a virtual descendant of the given <code>root</code>. If
+ * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
+ * as the successor.
+ * <p>
+ * A virtual descendant is an imaginary View that is reported as a part of the view
+ * hierarchy for accessibility purposes. This enables custom views that draw complex
+ * content to report them selves as a tree of virtual views, thus conveying their
+ * logical structure.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public void setTraversalBefore(View root, int virtualDescendantId) {
+ enforceNotSealed();
+ final int rootAccessibilityViewId = (root != null)
+ ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
+ mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+ }
+
+ /**
+ * Gets the node after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one.
+ *
+ * @return The succeeding node if such or <code>null</code>.
+ *
+ * @see #setTraversalAfter(android.view.View)
+ * @see #setTraversalAfter(android.view.View, int)
+ */
+ public AccessibilityNodeInfo getTraversalAfter() {
+ enforceSealed();
+ return getNodeForAccessibilityId(mTraversalAfter);
+ }
+
+ /**
+ * Sets the view whose node is visited after this one in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param view The previous view.
+ *
+ * @see #getTraversalAfter()
+ */
+ public void setTraversalAfter(View view) {
+ setTraversalAfter(view, UNDEFINED_ITEM_ID);
+ }
+
+ /**
+ * Sets the node after which this one is visited in accessibility traversal.
+ * A screen-reader must visit the content of the other node before the content
+ * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
+ * the root is set as the predecessor.
+ * <p>
+ * A virtual descendant is an imaginary View that is reported as a part of the view
+ * hierarchy for accessibility purposes. This enables custom views that draw complex
+ * content to report them selves as a tree of virtual views, thus conveying their
+ * logical structure.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public void setTraversalAfter(View root, int virtualDescendantId) {
+ enforceNotSealed();
+ final int rootAccessibilityViewId = (root != null)
+ ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
+ mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+ }
+
+ /**
* Sets the maximum text length, or -1 for no limit.
* <p>
* Typically used to indicate that an editable text field has a limit on
@@ -1229,13 +1351,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getParent() {
enforceSealed();
- if (!canPerformRequestOverConnection(mParentNodeId)) {
- return null;
- }
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mParentNodeId, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ return getNodeForAccessibilityId(mParentNodeId);
}
/**
@@ -2055,13 +2171,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getLabelFor() {
enforceSealed();
- if (!canPerformRequestOverConnection(mLabelForId)) {
- return null;
- }
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mLabelForId, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ return getNodeForAccessibilityId(mLabelForId);
}
/**
@@ -2113,13 +2223,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getLabeledBy() {
enforceSealed();
- if (!canPerformRequestOverConnection(mLabeledById)) {
- return null;
- }
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, mLabeledById, false, FLAG_PREFETCH_PREDECESSORS
- | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ return getNodeForAccessibilityId(mLabeledById);
}
/**
@@ -2453,6 +2557,9 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeLong(mParentNodeId);
parcel.writeLong(mLabelForId);
parcel.writeLong(mLabeledById);
+ parcel.writeLong(mTraversalBefore);
+ parcel.writeLong(mTraversalAfter);
+
parcel.writeInt(mConnectionId);
final LongArray childIds = mChildNodeIds;
@@ -2571,6 +2678,8 @@ public class AccessibilityNodeInfo implements Parcelable {
mParentNodeId = other.mParentNodeId;
mLabelForId = other.mLabelForId;
mLabeledById = other.mLabeledById;
+ mTraversalBefore = other.mTraversalBefore;
+ mTraversalAfter = other.mTraversalAfter;
mWindowId = other.mWindowId;
mConnectionId = other.mConnectionId;
mBoundsInParent.set(other.mBoundsInParent);
@@ -2633,6 +2742,9 @@ public class AccessibilityNodeInfo implements Parcelable {
mParentNodeId = parcel.readLong();
mLabelForId = parcel.readLong();
mLabeledById = parcel.readLong();
+ mTraversalBefore = parcel.readLong();
+ mTraversalAfter = parcel.readLong();
+
mConnectionId = parcel.readInt();
final int childrenSize = parcel.readInt();
@@ -2725,6 +2837,8 @@ public class AccessibilityNodeInfo implements Parcelable {
mParentNodeId = ROOT_NODE_ID;
mLabelForId = ROOT_NODE_ID;
mLabeledById = ROOT_NODE_ID;
+ mTraversalBefore = ROOT_NODE_ID;
+ mTraversalAfter = ROOT_NODE_ID;
mWindowId = UNDEFINED_ITEM_ID;
mConnectionId = UNDEFINED_CONNECTION_ID;
mMaxTextLength = -1;
@@ -2911,6 +3025,8 @@ public class AccessibilityNodeInfo implements Parcelable {
builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
builder.append("; mParentNodeId: " + mParentNodeId);
+ builder.append("; traversalBefore: ").append(mTraversalBefore);
+ builder.append("; traversalAfter: ").append(mTraversalAfter);
int granularities = mMovementGranularities;
builder.append("; MovementGranularities: [");
@@ -2963,6 +3079,16 @@ public class AccessibilityNodeInfo implements Parcelable {
return builder.toString();
}
+ private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
+ if (!canPerformRequestOverConnection(accessibilityId)) {
+ return null;
+ }
+ AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+ mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
+ | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+ }
+
/**
* A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
* Each action has a unique id that is mandatory and optional data.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4aebaae..6927660 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2663,7 +2663,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @return True if the selector should be shown
*/
boolean shouldShowSelector() {
- return (!isInTouchMode()) || (touchModeDrawsInPressedState() && isPressed());
+ return (isFocused() && !isInTouchMode()) || (touchModeDrawsInPressedState() && isPressed());
}
private void drawSelector(Canvas canvas) {
@@ -4910,9 +4910,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (position >= headerViewsCount && position < footerViewsStart) {
// The view will be rebound to new data, clear any
// system-managed transient state.
- if (child.isAccessibilityFocused()) {
- child.clearAccessibilityFocus();
- }
+ child.clearAccessibilityFocus();
mRecycler.addScrapView(child, position);
}
}
@@ -4933,9 +4931,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (position >= headerViewsCount && position < footerViewsStart) {
// The view will be rebound to new data, clear any
// system-managed transient state.
- if (child.isAccessibilityFocused()) {
- child.clearAccessibilityFocus();
- }
+ child.clearAccessibilityFocus();
mRecycler.addScrapView(child, position);
}
}
@@ -6776,9 +6772,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
private void clearAccessibilityFromScrap(View view) {
- if (view.isAccessibilityFocused()) {
- view.clearAccessibilityFocus();
- }
+ view.clearAccessibilityFocus();
view.setAccessibilityDelegate(null);
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index b2cfdf7..d39960f 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -267,6 +267,12 @@ public abstract class AbsSeekBar extends ProgressBar {
if (mHasThumbTintMode) {
mThumb.setTintMode(mThumbTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mThumb.isStateful()) {
+ mThumb.setState(getDrawableState());
+ }
}
}
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 7198e52..0a8a01f 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -429,7 +429,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
final int childCount = getChildCount();
- final int midVertical = (top + bottom) / 2;
+ final int midVertical = (bottom - top) / 2;
final int dividerWidth = getDividerWidth();
int overflowWidth = 0;
int nonOverflowWidth = 0;
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index eb8e8aa..69969a9 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -267,6 +267,12 @@ public class CheckedTextView extends TextView implements Checkable {
if (mHasCheckMarkTintMode) {
mCheckMarkDrawable.setTintMode(mCheckMarkTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mCheckMarkDrawable.isStateful()) {
+ mCheckMarkDrawable.setState(getDrawableState());
+ }
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 092e31c..447ccc2 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -315,6 +315,12 @@ public abstract class CompoundButton extends Button implements Checkable {
if (mHasButtonTintMode) {
mButtonDrawable.setTintMode(mButtonTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mButtonDrawable.isStateful()) {
+ mButtonDrawable.setState(getDrawableState());
+ }
}
}
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 fcf66f6..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) {
@@ -107,60 +96,25 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener,
mAdapter.setRange(mMinDate, mMaxDate);
- if (constrainCalendar(mSelectedDay, mMinDate, mMaxDate)) {
- goTo(mSelectedDay, false, true, true);
- }
+ // Changing the min/max date changes the selection position since we
+ // don't really have stable IDs.
+ goTo(mSelectedDay, false, true, true);
}
/**
- * 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/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index e317524..d974c29 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -384,6 +384,12 @@ public class FrameLayout extends ViewGroup {
if (mHasForegroundTintMode) {
mForeground.setTintMode(mForegroundTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mForeground.isStateful()) {
+ mForeground.setState(getDrawableState());
+ }
}
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 75dfcca..c68bfca 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -386,21 +386,21 @@ public class ImageView extends View {
*/
@android.view.RemotableViewMethod
public void setImageResource(int resId) {
- if (mUri != null || mResource != resId) {
- final int oldWidth = mDrawableWidth;
- final int oldHeight = mDrawableHeight;
+ // The resource configuration may have changed, so we should always
+ // try to load the resource even if the resId hasn't changed.
+ final int oldWidth = mDrawableWidth;
+ final int oldHeight = mDrawableHeight;
- updateDrawable(null);
- mResource = resId;
- mUri = null;
+ updateDrawable(null);
+ mResource = resId;
+ mUri = null;
- resolveUri();
+ resolveUri();
- if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
- requestLayout();
- }
- invalidate();
+ if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
+ requestLayout();
}
+ invalidate();
}
/**
@@ -527,6 +527,12 @@ public class ImageView extends View {
if (mHasDrawableTintMode) {
mDrawable.setTintMode(mDrawableTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mDrawable.isStateful()) {
+ mDrawable.setState(getDrawableState());
+ }
}
}
@@ -820,6 +826,7 @@ public class ImageView extends View {
mDrawableHeight = d.getIntrinsicHeight();
applyImageTint();
applyColorMod();
+
configureBounds();
} else {
mDrawableWidth = mDrawableHeight = -1;
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 9f540c0..a31d37e 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1252,14 +1252,7 @@ public class ListPopupWindow {
final boolean wasForwarding = mForwarding;
final boolean forwarding;
if (wasForwarding) {
- if (mWasLongPress) {
- // If we started forwarding as a result of a long-press,
- // just silently stop forwarding events so that the window
- // stays open.
- forwarding = onTouchForwarded(event);
- } else {
- forwarding = onTouchForwarded(event) || !onForwardingStopped();
- }
+ forwarding = onTouchForwarded(event) || !onForwardingStopped();
} else {
forwarding = onTouchObserved(event) && onForwardingStarted();
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 7b3dd31..a40d4f8 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -904,6 +904,10 @@ public class OverScroller {
final long time = AnimationUtils.currentAnimationTimeMillis();
final long currentTime = time - mStartTime;
+ if (currentTime == 0) {
+ // Skip work but report that we're still going if we have a nonzero duration.
+ return mDuration > 0;
+ }
if (currentTime > mDuration) {
return false;
}
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/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 1c190c3..887a93b 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -673,6 +673,12 @@ public class ProgressBar extends View {
if (tintInfo.mHasIndeterminateTintMode) {
mIndeterminateDrawable.setTintMode(tintInfo.mIndeterminateTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (mIndeterminateDrawable.isStateful()) {
+ mIndeterminateDrawable.setState(getDrawableState());
+ }
}
}
}
@@ -781,6 +787,12 @@ public class ProgressBar extends View {
if (mProgressTintInfo.mHasProgressTintMode) {
target.setTintMode(mProgressTintInfo.mProgressTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (target.isStateful()) {
+ target.setState(getDrawableState());
+ }
}
}
}
@@ -800,6 +812,12 @@ public class ProgressBar extends View {
if (mProgressTintInfo.mHasProgressBackgroundTintMode) {
target.setTintMode(mProgressTintInfo.mProgressBackgroundTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (target.isStateful()) {
+ target.setState(getDrawableState());
+ }
}
}
}
@@ -819,6 +837,12 @@ public class ProgressBar extends View {
if (mProgressTintInfo.mHasSecondaryProgressTintMode) {
target.setTintMode(mProgressTintInfo.mSecondaryProgressTintMode);
}
+
+ // The drawable (or one of its children) may not have been
+ // stateful before applying the tint, so let's try again.
+ if (target.isStateful()) {
+ target.setState(getDrawableState());
+ }
}
}
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 80f364b..dd7fa18 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2528,6 +2528,26 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
+ * Equivalent to calling {@link android.view.View#setAccessibilityTraversalBefore(int)}.
+ *
+ * @param viewId The id of the view whose before view in accessibility traversal to set.
+ * @param nextId The id of the next in the accessibility traversal.
+ **/
+ public void setAccessibilityTraversalBefore(int viewId, int nextId) {
+ setInt(viewId, "setAccessibilityTraversalBefore", nextId);
+ }
+
+ /**
+ * Equivalent to calling {@link android.view.View#setAccessibilityTraversalAfter(int)}.
+ *
+ * @param viewId The id of the view whose after view in accessibility traversal to set.
+ * @param nextId The id of the next in the accessibility traversal.
+ **/
+ public void setAccessibilityTraversalAfter(int viewId, int nextId) {
+ setInt(viewId, "setAccessibilityTraversalAfter", nextId);
+ }
+
+ /**
* Equivalent to calling View.setLabelFor(int).
*
* @param viewId The id of the view whose property to set.
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/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 78ee247..7d01321 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -607,23 +607,32 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl
*/
@Override
public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
- if (pickerIndex == HOUR_INDEX) {
- if (mAllowAutoAdvance && autoAdvance) {
- updateHeaderHour(newValue, false);
- setCurrentItemShowing(MINUTE_INDEX, true, false);
- mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes);
- } else {
- updateHeaderHour(newValue, true);
- }
- } else if (pickerIndex == MINUTE_INDEX){
- updateHeaderMinute(newValue, true);
- } else if (pickerIndex == AMPM_INDEX) {
- updateAmPmLabelStates(newValue);
- } else if (pickerIndex == ENABLE_PICKER_INDEX) {
- if (!isTypedTimeFullyLegal()) {
- mTypedTimes.clear();
- }
- finishKbMode();
+ switch (pickerIndex) {
+ case HOUR_INDEX:
+ if (mAllowAutoAdvance && autoAdvance) {
+ updateHeaderHour(newValue, false);
+ setCurrentItemShowing(MINUTE_INDEX, true, false);
+ mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes);
+ } else {
+ updateHeaderHour(newValue, true);
+ }
+ break;
+ case MINUTE_INDEX:
+ updateHeaderMinute(newValue, true);
+ break;
+ case AMPM_INDEX:
+ updateAmPmLabelStates(newValue);
+ break;
+ case ENABLE_PICKER_INDEX:
+ if (!isTypedTimeFullyLegal()) {
+ mTypedTimes.clear();
+ }
+ finishKbMode();
+ break;
+ }
+
+ if (mOnTimeChangedListener != null) {
+ mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(), getCurrentMinute());
}
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index d8e39e3..f90d64a 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -104,6 +104,7 @@ public class Toolbar extends ViewGroup {
private ImageView mLogoView;
private Drawable mCollapseIcon;
+ private CharSequence mCollapseDescription;
private ImageButton mCollapseButtonView;
View mExpandedActionView;
@@ -238,6 +239,7 @@ public class Toolbar extends ViewGroup {
}
mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
+ mCollapseDescription = a.getText(R.styleable.Toolbar_collapseContentDescription);
final CharSequence title = a.getText(R.styleable.Toolbar_title);
if (!TextUtils.isEmpty(title)) {
@@ -998,6 +1000,7 @@ public class Toolbar extends ViewGroup {
if (mCollapseButtonView == null) {
mCollapseButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
mCollapseButtonView.setImageDrawable(mCollapseIcon);
+ mCollapseButtonView.setContentDescription(mCollapseDescription);
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
lp.mViewType = LayoutParams.EXPANDED;
@@ -1749,6 +1752,17 @@ public class Toolbar extends ViewGroup {
}
/**
+ * Accessor to enable LayoutLib to get ActionMenuPresenter directly.
+ */
+ ActionMenuPresenter getOuterActionMenuPresenter() {
+ return mOuterActionMenuPresenter;
+ }
+
+ Context getPopupContext() {
+ return mPopupContext;
+ }
+
+ /**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
*/
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 0183e45..35e03c3 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,7 +26,6 @@ import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
@@ -38,9 +37,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
@@ -449,11 +451,11 @@ public class AlertController {
}
private void setupView() {
- final LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
+ final ViewGroup contentPanel = (ViewGroup) mWindow.findViewById(R.id.contentPanel);
setupContent(contentPanel);
final boolean hasButtons = setupButtons();
- final LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
+ final ViewGroup topPanel = (ViewGroup) mWindow.findViewById(R.id.topPanel);
final TypedArray a = mContext.obtainStyledAttributes(
null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
final boolean hasTitle = setupTitle(topPanel);
@@ -521,13 +523,13 @@ public class AlertController {
a.recycle();
}
- private boolean setupTitle(LinearLayout topPanel) {
+ private boolean setupTitle(ViewGroup topPanel) {
boolean hasTitle = true;
if (mCustomTitleView != null) {
// Add the custom title view directly to the topPanel layout
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ LayoutParams lp = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
topPanel.addView(mCustomTitleView, 0, lp);
@@ -571,7 +573,7 @@ public class AlertController {
return hasTitle;
}
- private void setupContent(LinearLayout contentPanel) {
+ private void setupContent(ViewGroup contentPanel) {
mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
mScrollView.setFocusable(false);
@@ -588,14 +590,77 @@ public class AlertController {
mScrollView.removeView(mMessageView);
if (mListView != null) {
- contentPanel.removeView(mWindow.findViewById(R.id.scrollView));
- contentPanel.addView(mListView,
- new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- contentPanel.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f));
+ final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
+ final int childIndex = scrollParent.indexOfChild(mScrollView);
+ scrollParent.removeViewAt(childIndex);
+ scrollParent.addView(mListView, childIndex,
+ new LayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
contentPanel.setVisibility(View.GONE);
}
}
+
+ // Set up scroll indicators (if present).
+ final View indicatorUp = mWindow.findViewById(R.id.scrollIndicatorUp);
+ final View indicatorDown = mWindow.findViewById(R.id.scrollIndicatorDown);
+ if (indicatorUp != null || indicatorDown != null) {
+ if (mMessage != null) {
+ // We're just showing the ScrollView, set up listener.
+ mScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
+ @Override
+ public void onScrollChange(View v, int scrollX, int scrollY,
+ int oldScrollX, int oldScrollY) {
+ manageScrollIndicators(v, indicatorUp, indicatorDown);
+ }
+ });
+ // Set up the indicators following layout.
+ mScrollView.post(new Runnable() {
+ @Override
+ public void run() {
+ manageScrollIndicators(mScrollView, indicatorUp, indicatorDown);
+ }
+ });
+
+ } else if (mListView != null) {
+ // We're just showing the AbsListView, set up listener.
+ mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ // That's cool, I guess?
+ }
+
+ @Override
+ public void onScroll(AbsListView v, int firstVisibleItem,
+ int visibleItemCount, int totalItemCount) {
+ manageScrollIndicators(v, indicatorUp, indicatorDown);
+ }
+ });
+ // Set up the indicators following layout.
+ mListView.post(new Runnable() {
+ @Override
+ public void run() {
+ manageScrollIndicators(mListView, indicatorUp, indicatorDown);
+ }
+ });
+ } else {
+ // We don't have any content to scroll, remove the indicators.
+ if (indicatorUp != null) {
+ contentPanel.removeView(indicatorUp);
+ }
+ if (indicatorDown != null) {
+ contentPanel.removeView(indicatorDown);
+ }
+ }
+ }
+ }
+
+ private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
+ if (upIndicator != null) {
+ upIndicator.setVisibility(v.canScrollVertically(-1) ? View.VISIBLE : View.INVISIBLE);
+ }
+ if (downIndicator != null) {
+ downIndicator.setVisibility(v.canScrollVertically(1) ? View.VISIBLE : View.INVISIBLE);
+ }
}
private boolean setupButtons() {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 0bc1a8d..64bd6b6 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
@@ -75,16 +76,21 @@ public class ChooserActivity extends ResolverActivity {
}
@Override
- public Intent getReplacementIntent(String packageName, Intent defIntent) {
+ public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
+ Intent result = defIntent;
if (mReplacementExtras != null) {
- final Bundle replExtras = mReplacementExtras.getBundle(packageName);
+ final Bundle replExtras = mReplacementExtras.getBundle(aInfo.packageName);
if (replExtras != null) {
- final Intent result = new Intent(defIntent);
+ result = new Intent(defIntent);
result.putExtras(replExtras);
- return result;
}
}
- return defIntent;
+ if (aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER)
+ || aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+ result = Intent.createChooser(result,
+ getIntent().getCharSequenceExtra(Intent.EXTRA_TITLE));
+ }
+ return result;
}
@Override
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 6e2f84a..9656a21 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -58,21 +58,22 @@ public class IntentForwarderActivity extends Activity {
Intent intentReceived = getIntent();
String className = intentReceived.getComponent().getClassName();
- final UserHandle userDest;
+ final int targetUserId;
final int userMessageId;
if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
userMessageId = com.android.internal.R.string.forward_intent_to_owner;
- userDest = UserHandle.OWNER;
+ targetUserId = UserHandle.USER_OWNER;
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
userMessageId = com.android.internal.R.string.forward_intent_to_work;
- userDest = getManagedProfile();
+ targetUserId = getManagedProfile();
} else {
Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
userMessageId = -1;
- userDest = null;
+ targetUserId = UserHandle.USER_NULL;
}
- if (userDest == null) { // This covers the case where there is no managed profile.
+ if (targetUserId == UserHandle.USER_NULL) {
+ // This covers the case where there is no managed profile.
finish();
return;
}
@@ -83,31 +84,24 @@ public class IntentForwarderActivity extends Activity {
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
|Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
int callingUserId = getUserId();
- IPackageManager ipm = AppGlobals.getPackageManager();
- String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
- boolean canForward = false;
- Intent selector = newIntent.getSelector();
- if (selector == null) {
- selector = newIntent;
- }
- try {
- canForward = ipm.canForwardTo(selector, resolvedType, callingUserId,
- userDest.getIdentifier());
- } catch (RemoteException e) {
- Slog.e(TAG, "PackageManagerService is dead?");
- }
- if (canForward) {
- newIntent.setContentUserHint(callingUserId);
+
+ if (canForward(newIntent, targetUserId)) {
+ if (newIntent.getAction().equals(Intent.ACTION_CHOOSER)) {
+ Intent innerIntent = (Intent) newIntent.getParcelableExtra(Intent.EXTRA_INTENT);
+ innerIntent.setContentUserHint(callingUserId);
+ } else {
+ newIntent.setContentUserHint(callingUserId);
+ }
final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser(
- newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier());
+ newIntent, MATCH_DEFAULT_ONLY, targetUserId);
// Only show a disclosure if this is a normal (non-OS) app
final boolean shouldShowDisclosure =
!UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID);
try {
- startActivityAsCaller(newIntent, null, userDest.getIdentifier());
+ startActivityAsCaller(newIntent, null, targetUserId);
} catch (RuntimeException e) {
int launchedFromUid = -1;
String launchedFromPackage = "?";
@@ -129,26 +123,55 @@ public class IntentForwarderActivity extends Activity {
}
} else {
Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
- + callingUserId + " to user " + userDest.getIdentifier());
+ + callingUserId + " to user " + targetUserId);
}
finish();
}
+ boolean canForward(Intent intent, int targetUserId) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ if (intent.getAction().equals(Intent.ACTION_CHOOSER)) {
+ // The EXTRA_INITIAL_INTENTS may not be allowed to be forwarded.
+ if (intent.hasExtra(Intent.EXTRA_INITIAL_INTENTS)) {
+ Slog.wtf(TAG, "An chooser intent with extra initial intents cannot be forwarded to"
+ + " a different user");
+ return false;
+ }
+ if (intent.hasExtra(Intent.EXTRA_REPLACEMENT_EXTRAS)) {
+ Slog.wtf(TAG, "A chooser intent with replacement extras cannot be forwarded to a"
+ + " different user");
+ return false;
+ }
+ intent = (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ }
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ if (intent.getSelector() != null) {
+ intent = intent.getSelector();
+ }
+ try {
+ return ipm.canForwardTo(intent, resolvedType, getUserId(),
+ targetUserId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "PackageManagerService is dead?");
+ return false;
+ }
+ }
+
/**
- * Returns the managed profile for this device or null if there is no managed
- * profile.
+ * Returns the userId of the managed profile for this device or UserHandle.USER_NULL if there is
+ * no managed profile.
*
* TODO: Remove the assumption that there is only one managed profile
* on the device.
*/
- private UserHandle getManagedProfile() {
+ private int getManagedProfile() {
UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
for (UserInfo userInfo : relatedUsers) {
- if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id);
+ if (userInfo.isManagedProfile()) return userInfo.id;
}
Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
+ " has been called, but there is no managed profile");
- return null;
+ return UserHandle.USER_NULL;
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ccffa19..376db6e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -100,6 +100,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private int mMaxColumns;
private int mLastSelected = ListView.INVALID_POSITION;
private boolean mResolvingHome = false;
+ private int mProfileSwitchMessageId = -1;
private UsageStatsManager mUsm;
private Map<String, UsageStats> mStats;
@@ -200,6 +201,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
List<ResolveInfo> rList, boolean alwaysUseOption) {
setTheme(R.style.Theme_DeviceDefault_Resolver);
super.onCreate(savedInstanceState);
+
+ // Determine whether we should show that intent is forwarded
+ // from managed profile to owner or other way around.
+ setProfileSwitchMessageId(intent.getContentUserHint());
+
try {
mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
getActivityToken());
@@ -278,9 +284,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
if (rdl != null) {
- rdl.setOnClickOutsideListener(new View.OnClickListener() {
+ rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
@Override
- public void onClick(View v) {
+ public void onDismissed() {
finish();
}
});
@@ -320,6 +326,22 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
+ private void setProfileSwitchMessageId(int contentUserHint) {
+ if (contentUserHint != UserHandle.USER_CURRENT &&
+ contentUserHint != UserHandle.myUserId()) {
+ UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+ UserInfo originUserInfo = userManager.getUserInfo(contentUserHint);
+ boolean originIsManaged = originUserInfo != null ? originUserInfo.isManagedProfile()
+ : false;
+ boolean targetIsManaged = userManager.isManagedProfile();
+ if (originIsManaged && !targetIsManaged) {
+ mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_owner;
+ } else if (!originIsManaged && targetIsManaged) {
+ mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_work;
+ }
+ }
+ }
+
/**
* Turn on launch mode that is safe to use when forwarding intents received from
* applications and running in system processes. This mode uses Activity.startActivityAsCaller
@@ -529,7 +551,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
/**
* Replace me in subclasses!
*/
- public Intent getReplacementIntent(String packageName, Intent defIntent) {
+ public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
return defIntent;
}
@@ -642,6 +664,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
public void safelyStartActivity(Intent intent) {
+ // If needed, show that intent is forwarded
+ // from managed profile to owner or other way around.
+ if (mProfileSwitchMessageId != -1) {
+ Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
+ }
if (!mSafeForwardingMode) {
startActivity(intent);
onActivityStarted(intent);
@@ -943,7 +970,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
DisplayResolveInfo dri = filtered ? getItem(position) : mList.get(position);
Intent intent = new Intent(dri.origIntent != null ? dri.origIntent :
- getReplacementIntent(dri.ri.activityInfo.packageName, mIntent));
+ getReplacementIntent(dri.ri.activityInfo, mIntent));
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
|Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
ActivityInfo ai = dri.ri.activityInfo;
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 4410f25..34b9dcb 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -40,7 +40,6 @@ import com.android.internal.widget.ToolbarWidgetWrapper;
import java.util.ArrayList;
public class ToolbarActionBar extends ActionBar {
- private Toolbar mToolbar;
private DecorToolbar mDecorToolbar;
private boolean mToolbarMenuPrepared;
private Window.Callback mWindowCallback;
@@ -66,7 +65,6 @@ public class ToolbarActionBar extends ActionBar {
};
public ToolbarActionBar(Toolbar toolbar, CharSequence title, Window.Callback windowCallback) {
- mToolbar = toolbar;
mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false);
mWindowCallback = new ToolbarCallbackWrapper(windowCallback);
mDecorToolbar.setWindowCallback(mWindowCallback);
@@ -91,8 +89,8 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setCustomView(int resId) {
- final LayoutInflater inflater = LayoutInflater.from(mToolbar.getContext());
- setCustomView(inflater.inflate(resId, mToolbar, false));
+ final LayoutInflater inflater = LayoutInflater.from(mDecorToolbar.getContext());
+ setCustomView(inflater.inflate(resId, mDecorToolbar.getViewGroup(), false));
}
@Override
@@ -132,17 +130,17 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setElevation(float elevation) {
- mToolbar.setElevation(elevation);
+ mDecorToolbar.getViewGroup().setElevation(elevation);
}
@Override
public float getElevation() {
- return mToolbar.getElevation();
+ return mDecorToolbar.getViewGroup().getElevation();
}
@Override
public Context getThemedContext() {
- return mToolbar.getContext();
+ return mDecorToolbar.getContext();
}
@Override
@@ -152,12 +150,12 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setHomeAsUpIndicator(Drawable indicator) {
- mToolbar.setNavigationIcon(indicator);
+ mDecorToolbar.setNavigationIcon(indicator);
}
@Override
public void setHomeAsUpIndicator(int resId) {
- mToolbar.setNavigationIcon(resId);
+ mDecorToolbar.setNavigationIcon(resId);
}
@Override
@@ -280,7 +278,7 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setBackgroundDrawable(@Nullable Drawable d) {
- mToolbar.setBackground(d);
+ mDecorToolbar.setBackgroundDrawable(d);
}
@Override
@@ -290,12 +288,12 @@ public class ToolbarActionBar extends ActionBar {
@Override
public CharSequence getTitle() {
- return mToolbar.getTitle();
+ return mDecorToolbar.getTitle();
}
@Override
public CharSequence getSubtitle() {
- return mToolbar.getSubtitle();
+ return mDecorToolbar.getSubtitle();
}
@Override
@@ -389,44 +387,44 @@ public class ToolbarActionBar extends ActionBar {
@Override
public int getHeight() {
- return mToolbar.getHeight();
+ return mDecorToolbar.getHeight();
}
@Override
public void show() {
// TODO: Consider a better transition for this.
// Right now use no automatic transition so that the app can supply one if desired.
- mToolbar.setVisibility(View.VISIBLE);
+ mDecorToolbar.setVisibility(View.VISIBLE);
}
@Override
public void hide() {
// TODO: Consider a better transition for this.
// Right now use no automatic transition so that the app can supply one if desired.
- mToolbar.setVisibility(View.GONE);
+ mDecorToolbar.setVisibility(View.GONE);
}
@Override
public boolean isShowing() {
- return mToolbar.getVisibility() == View.VISIBLE;
+ return mDecorToolbar.getVisibility() == View.VISIBLE;
}
@Override
public boolean openOptionsMenu() {
- return mToolbar.showOverflowMenu();
+ return mDecorToolbar.showOverflowMenu();
}
@Override
public boolean invalidateOptionsMenu() {
- mToolbar.removeCallbacks(mMenuInvalidator);
- mToolbar.postOnAnimation(mMenuInvalidator);
+ mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
+ mDecorToolbar.getViewGroup().postOnAnimation(mMenuInvalidator);
return true;
}
@Override
public boolean collapseActionView() {
- if (mToolbar.hasExpandedActionView()) {
- mToolbar.collapseActionView();
+ if (mDecorToolbar.hasExpandedActionView()) {
+ mDecorToolbar.collapseActionView();
return true;
}
return false;
@@ -434,10 +432,10 @@ public class ToolbarActionBar extends ActionBar {
void populateOptionsMenu() {
if (!mMenuCallbackSet) {
- mToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback());
+ mDecorToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback());
mMenuCallbackSet = true;
}
- final Menu menu = mToolbar.getMenu();
+ final Menu menu = mDecorToolbar.getMenu();
final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
if (mb != null) {
mb.stopDispatchingItemsChanged();
@@ -518,7 +516,7 @@ public class ToolbarActionBar extends ActionBar {
}
mClosingActionMenu = true;
- mToolbar.dismissPopupMenus();
+ mDecorToolbar.dismissPopupMenus();
if (mWindowCallback != null) {
mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
}
@@ -536,7 +534,7 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void onMenuModeChange(MenuBuilder menu) {
if (mWindowCallback != null) {
- if (mToolbar.isOverflowMenuShowing()) {
+ if (mDecorToolbar.isOverflowMenuShowing()) {
mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
} else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL,
null, menu)) {
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 2377c22..d95f0e5 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -496,7 +496,7 @@ public class WindowDecorActionBar extends ActionBar implements
mOverlayLayout.setHideOnContentScrollEnabled(false);
mContextView.killMode();
- ActionModeImpl mode = new ActionModeImpl(callback);
+ ActionModeImpl mode = new ActionModeImpl(mContextView.getContext(), callback);
if (mode.dispatchOnCreate()) {
mode.invalidate();
mContextView.initForMode(mode);
@@ -876,7 +876,7 @@ public class WindowDecorActionBar extends ActionBar implements
currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
outValue, true);
final int targetThemeRes = outValue.resourceId;
-
+
if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) {
mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
} else {
@@ -885,7 +885,7 @@ public class WindowDecorActionBar extends ActionBar implements
}
return mThemedContext;
}
-
+
@Override
public boolean isTitleTruncated() {
return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
@@ -933,23 +933,26 @@ public class WindowDecorActionBar extends ActionBar implements
}
/**
- * @hide
+ * @hide
*/
public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
+ private final Context mActionModeContext;
+ private final MenuBuilder mMenu;
+
private ActionMode.Callback mCallback;
- private MenuBuilder mMenu;
private WeakReference<View> mCustomView;
-
- public ActionModeImpl(ActionMode.Callback callback) {
+
+ public ActionModeImpl(Context context, ActionMode.Callback callback) {
+ mActionModeContext = context;
mCallback = callback;
- mMenu = new MenuBuilder(getThemedContext())
+ mMenu = new MenuBuilder(context)
.setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
mMenu.setCallback(this);
}
@Override
public MenuInflater getMenuInflater() {
- return new MenuInflater(getThemedContext());
+ return new MenuInflater(mActionModeContext);
}
@Override
@@ -1042,7 +1045,7 @@ public class WindowDecorActionBar extends ActionBar implements
public CharSequence getSubtitle() {
return mContextView.getSubtitle();
}
-
+
@Override
public void setTitleOptionalHint(boolean titleOptional) {
super.setTitleOptionalHint(titleOptional);
diff --git a/core/java/com/android/internal/content/ReferrerIntent.aidl b/core/java/com/android/internal/content/ReferrerIntent.aidl
new file mode 100644
index 0000000..7cf6774
--- /dev/null
+++ b/core/java/com/android/internal/content/ReferrerIntent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content;
+
+parcelable ReferrerIntent;
diff --git a/core/java/com/android/internal/content/ReferrerIntent.java b/core/java/com/android/internal/content/ReferrerIntent.java
new file mode 100644
index 0000000..8d9a1cf
--- /dev/null
+++ b/core/java/com/android/internal/content/ReferrerIntent.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.content;
+
+import android.content.Intent;
+import android.os.Parcel;
+
+/**
+ * Subclass of Intent that also contains referrer (as a package name) information.
+ */
+public class ReferrerIntent extends Intent {
+ public final String mReferrer;
+
+ public ReferrerIntent(Intent baseIntent, String referrer) {
+ super(baseIntent);
+ mReferrer = referrer;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ super.writeToParcel(dest, parcelableFlags);
+ dest.writeString(mReferrer);
+ }
+
+ ReferrerIntent(Parcel in) {
+ readFromParcel(in);
+ mReferrer = in.readString();
+ }
+
+ public static final Creator<ReferrerIntent> CREATOR = new Creator<ReferrerIntent>() {
+ public ReferrerIntent createFromParcel(Parcel source) {
+ return new ReferrerIntent(source);
+ }
+ public ReferrerIntent[] newArray(int size) {
+ return new ReferrerIntent[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index ac915d1..183527c 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -16,6 +16,8 @@
package com.android.internal.inputmethod;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -34,7 +36,9 @@ import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.TextServicesManager;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
@@ -115,8 +119,8 @@ public class InputMethodUtils {
}
/**
- * @deprecated Use {@link Locale} returned from
- * {@link #getFallbackLocaleForDefaultIme(ArrayList)} instead.
+ * @deprecated Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean,
+ * Locale, boolean, String)} instead.
*/
@Deprecated
public static boolean isSystemImeThatHasEnglishKeyboardSubtype(InputMethodInfo imi) {
@@ -126,25 +130,60 @@ public class InputMethodUtils {
return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage(), SUBTYPE_MODE_KEYBOARD);
}
+ private static boolean isSystemImeThatHasSubtypeOf(final InputMethodInfo imi,
+ final Context context, final boolean checkDefaultAttribute,
+ @Nullable final Locale requiredLocale, final boolean checkCountry,
+ final String requiredSubtypeMode) {
+ if (!isSystemIme(imi)) {
+ return false;
+ }
+ if (checkDefaultAttribute && !imi.isDefault(context)) {
+ return false;
+ }
+ if (!containsSubtypeOf(imi, requiredLocale, checkCountry, requiredSubtypeMode)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Nullable
public static Locale getFallbackLocaleForDefaultIme(final ArrayList<InputMethodInfo> imis,
final Context context) {
+ // At first, find the fallback locale from the IMEs that are declared as "default" in the
+ // current locale. Note that IME developers can declare an IME as "default" only for
+ // some particular locales but "not default" for other locales.
for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (isSystemIme(imi) && imi.isDefault(context) &&
- containsSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_KEYBOARD)) {
+ if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
+ true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
+ return fallbackLocale;
+ }
+ }
+ }
+ // If no fallback locale is found in the above condition, find fallback locales regardless
+ // of the "default" attribute as a last resort.
+ for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
+ for (int i = 0; i < imis.size(); ++i) {
+ if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
+ false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
return fallbackLocale;
}
}
}
+ Slog.w(TAG, "Found no fallback locale. imis=" + Arrays.toString(imis.toArray()));
return null;
}
- private static boolean isSystemAuxilialyImeThatHasAutomaticSubtype(InputMethodInfo imi) {
+ private static boolean isSystemAuxilialyImeThatHasAutomaticSubtype(final InputMethodInfo imi,
+ final Context context, final boolean checkDefaultAttribute) {
if (!isSystemIme(imi)) {
return false;
}
+ if (checkDefaultAttribute && !imi.isDefault(context)) {
+ return false;
+ }
if (!imi.isAuxiliaryIme()) {
return false;
}
@@ -166,98 +205,184 @@ public class InputMethodUtils {
}
}
- public static ArrayList<InputMethodInfo> getDefaultEnabledImes(
- Context context, boolean isSystemReady, ArrayList<InputMethodInfo> imis) {
- // OK to store null in fallbackLocale because isImeThatHasSubtypeOf() is null-tolerant.
- final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
+ private static final class InputMethodListBuilder {
+ // Note: We use LinkedHashSet instead of android.util.ArraySet because the enumeration
+ // order can have non-trivial effect in the call sites.
+ @NonNull
+ private final LinkedHashSet<InputMethodInfo> mInputMethodSet = new LinkedHashSet<>();
- if (!isSystemReady) {
- final ArrayList<InputMethodInfo> retval = new ArrayList<>();
+ public InputMethodListBuilder fillImes(final ArrayList<InputMethodInfo> imis,
+ final Context context, final boolean checkDefaultAttribute,
+ @Nullable final Locale locale, final boolean checkCountry,
+ final String requiredSubtypeMode) {
for (int i = 0; i < imis.size(); ++i) {
final InputMethodInfo imi = imis.get(i);
- // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
- if (isSystemIme(imi) && imi.isDefault(context) &&
- isImeThatHasSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_KEYBOARD)) {
- retval.add(imi);
+ if (isSystemImeThatHasSubtypeOf(imi, context, checkDefaultAttribute, locale,
+ checkCountry, requiredSubtypeMode)) {
+ mInputMethodSet.add(imi);
}
}
- return retval;
+ return this;
}
- // OK to store null in fallbackLocale because isImeThatHasSubtypeOf() is null-tolerant.
- final Locale systemLocale = getSystemLocaleFromContext(context);
- // TODO: Use LinkedHashSet to simplify the code.
- final ArrayList<InputMethodInfo> retval = new ArrayList<>();
- boolean systemLocaleKeyboardImeFound = false;
-
- // First, try to find IMEs with taking the system locale country into consideration.
- for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (!isSystemIme(imi) || !imi.isDefault(context)) {
- continue;
- }
- final boolean isSystemLocaleKeyboardIme = isImeThatHasSubtypeOf(imi, systemLocale,
- false /* ignoreCountry */, SUBTYPE_MODE_KEYBOARD);
- // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
- // TODO: Use LinkedHashSet to simplify the code.
- if (isSystemLocaleKeyboardIme ||
- isImeThatHasSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_ANY)) {
- retval.add(imi);
+ // TODO: The behavior of InputMethodSubtype#overridesImplicitlyEnabledSubtype() should be
+ // documented more clearly.
+ public InputMethodListBuilder fillAuxiliaryImes(final ArrayList<InputMethodInfo> imis,
+ final Context context) {
+ // If one or more auxiliary input methods are available, OK to stop populating the list.
+ for (final InputMethodInfo imi : mInputMethodSet) {
+ if (imi.isAuxiliaryIme()) {
+ return this;
+ }
}
- systemLocaleKeyboardImeFound |= isSystemLocaleKeyboardIme;
- }
-
- // System locale country doesn't match any IMEs, try to find IMEs in a country-agnostic
- // way.
- if (!systemLocaleKeyboardImeFound) {
+ boolean added = false;
for (int i = 0; i < imis.size(); ++i) {
final InputMethodInfo imi = imis.get(i);
- if (!isSystemIme(imi) || !imi.isDefault(context)) {
- continue;
- }
- if (isImeThatHasSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_KEYBOARD)) {
- // IMEs that have fallback locale are already added in the previous loop. We
- // don't need to add them again here.
- // TODO: Use LinkedHashSet to simplify the code.
- continue;
+ if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
+ true /* checkDefaultAttribute */)) {
+ mInputMethodSet.add(imi);
+ added = true;
}
- if (isImeThatHasSubtypeOf(imi, systemLocale, true /* ignoreCountry */,
- SUBTYPE_MODE_ANY)) {
- retval.add(imi);
+ }
+ if (added) {
+ return this;
+ }
+ for (int i = 0; i < imis.size(); ++i) {
+ final InputMethodInfo imi = imis.get(i);
+ if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
+ false /* checkDefaultAttribute */)) {
+ mInputMethodSet.add(imi);
}
}
+ return this;
}
- // If one or more auxiliary input methods are available, OK to stop populating the list.
- for (int i = 0; i < retval.size(); ++i) {
- if (retval.get(i).isAuxiliaryIme()) {
- return retval;
- }
+ public boolean isEmpty() {
+ return mInputMethodSet.isEmpty();
}
- for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi)) {
- retval.add(imi);
- }
+
+ @NonNull
+ public ArrayList<InputMethodInfo> build() {
+ return new ArrayList<>(mInputMethodSet);
}
- return retval;
}
- public static boolean isImeThatHasSubtypeOf(final InputMethodInfo imi,
- final Locale locale, final boolean ignoreCountry, final String mode) {
- if (locale == null) {
- return false;
- }
- return containsSubtypeOf(imi, locale, ignoreCountry, mode);
+ private static InputMethodListBuilder getMinimumKeyboardSetWithoutSystemLocale(
+ final ArrayList<InputMethodInfo> imis, final Context context,
+ @Nullable final Locale fallbackLocale) {
+ // Before the system becomes ready, we pick up at least one keyboard in the following order.
+ // The first user (device owner) falls into this category.
+ // 1. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
+ // 2. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
+ // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
+ // 4. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: false
+ // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
+
+ final InputMethodListBuilder builder = new InputMethodListBuilder();
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ Slog.w(TAG, "No software keyboard is found. imis=" + Arrays.toString(imis.toArray())
+ + " fallbackLocale=" + fallbackLocale);
+ return builder;
+ }
+
+ private static InputMethodListBuilder getMinimumKeyboardSetWithSystemLocale(
+ final ArrayList<InputMethodInfo> imis, final Context context,
+ @Nullable final Locale systemLocale, @Nullable final Locale fallbackLocale) {
+ // Once the system becomes ready, we pick up at least one keyboard in the following order.
+ // Secondary users fall into this category in general.
+ // 1. checkDefaultAttribute: true, locale: systemLocale, checkCountry: true
+ // 2. checkDefaultAttribute: true, locale: systemLocale, checkCountry: false
+ // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
+ // 4. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
+ // 5. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
+ // 6. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: false
+ // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
+
+ final InputMethodListBuilder builder = new InputMethodListBuilder();
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ Slog.w(TAG, "No software keyboard is found. imis=" + Arrays.toString(imis.toArray())
+ + " systemLocale=" + systemLocale + " fallbackLocale=" + fallbackLocale);
+ return builder;
+ }
+
+ public static ArrayList<InputMethodInfo> getDefaultEnabledImes(final Context context,
+ final boolean isSystemReady, final ArrayList<InputMethodInfo> imis) {
+ final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
+ if (!isSystemReady) {
+ // When the system is not ready, the system locale is not stable and reliable. Hence
+ // we will pick up IMEs that support software keyboard based on the fallback locale.
+ // Also pick up suitable IMEs regardless of the software keyboard support.
+ // (e.g. Voice IMEs)
+ return getMinimumKeyboardSetWithoutSystemLocale(imis, context, fallbackLocale)
+ .fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_ANY)
+ .build();
+ }
+
+ // When the system is ready, we will primarily rely on the system locale, but also keep
+ // relying on the fallback locale as a last resort.
+ // Also pick up suitable IMEs regardless of the software keyboard support (e.g. Voice IMEs),
+ // then pick up suitable auxiliary IMEs when necessary (e.g. Voice IMEs with "automatic"
+ // subtype)
+ final Locale systemLocale = getSystemLocaleFromContext(context);
+ return getMinimumKeyboardSetWithSystemLocale(imis, context, systemLocale, fallbackLocale)
+ .fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ true /* checkCountry */, SUBTYPE_MODE_ANY)
+ .fillAuxiliaryImes(imis, context)
+ .build();
}
/**
- * @deprecated Use {@link #isSystemIme(InputMethodInfo)} and
- * {@link InputMethodInfo#isDefault(Context)} and
- * {@link #isImeThatHasSubtypeOf(InputMethodInfo, Locale, boolean, String))} instead.
+ * @deprecated Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean,
+ * Locale, boolean, String)} instead.
*/
@Deprecated
public static boolean isValidSystemDefaultIme(
@@ -285,22 +410,25 @@ public class InputMethodUtils {
}
public static boolean containsSubtypeOf(final InputMethodInfo imi,
- final Locale locale, final boolean ignoreCountry, final String mode) {
+ @Nullable final Locale locale, final boolean checkCountry, final String mode) {
+ if (locale == null) {
+ return false;
+ }
final int N = imi.getSubtypeCount();
for (int i = 0; i < N; ++i) {
final InputMethodSubtype subtype = imi.getSubtypeAt(i);
- if (ignoreCountry) {
- final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
- subtype.getLocale()));
- if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
- continue;
- }
- } else {
+ if (checkCountry) {
// TODO: Use {@link Locale#toLanguageTag()} and
// {@link Locale#forLanguageTag(languageTag)} instead.
if (!TextUtils.equals(subtype.getLocale(), locale.toString())) {
continue;
}
+ } else {
+ final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
+ subtype.getLocale()));
+ if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
+ continue;
+ }
}
if (mode == SUBTYPE_MODE_ANY || TextUtils.isEmpty(mode) ||
mode.equalsIgnoreCase(subtype.getMode())) {
@@ -465,19 +593,9 @@ public class InputMethodUtils {
return applicableSubtypes;
}
- private static List<InputMethodSubtype> getEnabledInputMethodSubtypeList(
- Context context, InputMethodInfo imi, List<InputMethodSubtype> enabledSubtypes,
- boolean allowsImplicitlySelectedSubtypes) {
- if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
- enabledSubtypes = InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
- context.getResources(), imi);
- }
- return InputMethodSubtype.sort(context, 0, imi, enabledSubtypes);
- }
-
/**
* Returns the language component of a given locale string.
- * TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}
+ * TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(String)}
*/
public static String getLanguageFromLocaleString(String locale) {
final int idx = locale.indexOf('_');
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/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 57472f8..a3c0db4 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -42,5 +42,6 @@ oneway interface IStatusBar
void toggleRecentApps();
void preloadRecentApps();
void cancelPreloadRecentApps();
+ void showScreenPinningRequest();
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index e6bcea1..5e610ed 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -51,7 +51,7 @@ interface IStatusBarService
void onNotificationVisibilityChanged(
in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys);
void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
- void setSystemUiVisibility(int vis, int mask);
+ void setSystemUiVisibility(int vis, int mask, String cause);
void setWindowState(int window, int state);
void showRecentApps(boolean triggeredFromAltTab);
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 1dd9464..b71fa06 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -106,4 +106,8 @@ public final class MemInfoReader {
public long getZramTotalSizeKb() {
return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
}
+
+ public long[] getRawInfo() {
+ return mInfos;
+ }
}
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/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 50a7a5e..993ab58 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -102,4 +102,8 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void doneAnimating() {
}
+
+ @Override
+ public void dispatchWindowShown() {
+ }
}
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index 9c1b558..433ec73 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.android.internal.view;
import android.view.InputQueue;
@@ -10,4 +25,5 @@ public interface RootViewSurfaceTaker {
void setSurfaceFormat(int format);
void setSurfaceKeepScreenOn(boolean keepOn);
InputQueue.Callback willYouTakeTheInputQueue();
+ void onRootViewScrollYChanged(int scrollY);
}
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 062a9b1..7c671e8 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -241,7 +241,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi
if (!mSplitActionBar) {
menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
- mMenuView.setBackgroundDrawable(null);
+ mMenuView.setBackground(null);
addView(mMenuView, layoutParams);
} else {
// Allow full screen width in split mode.
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index b9a85e5..654d08b 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1341,6 +1341,22 @@ public class ActionBarView extends AbsActionBarView implements DecorToolbar {
updateHomeAccessibility(mUpGoerFive.isEnabled());
}
+ @Override
+ public void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+ MenuBuilder.Callback menuBuilderCallback) {
+ if (mActionMenuPresenter != null) {
+ mActionMenuPresenter.setCallback(presenterCallback);
+ }
+ if (mOptionsMenu != null) {
+ mOptionsMenu.setCallback(menuBuilderCallback);
+ }
+ }
+
+ @Override
+ public Menu getMenu() {
+ return mOptionsMenu;
+ }
+
static class SavedState extends BaseSavedState {
int expandedMenuItemId;
boolean isOverflowOpen;
diff --git a/core/java/com/android/internal/widget/DecorToolbar.java b/core/java/com/android/internal/widget/DecorToolbar.java
index f89f0b7..fb413b5 100644
--- a/core/java/com/android/internal/widget/DecorToolbar.java
+++ b/core/java/com/android/internal/widget/DecorToolbar.java
@@ -27,6 +27,8 @@ import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.SpinnerAdapter;
+
+import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPresenter;
/**
@@ -93,4 +95,11 @@ public interface DecorToolbar {
void setDefaultNavigationIcon(Drawable icon);
void saveHierarchyState(SparseArray<Parcelable> toolbarStates);
void restoreHierarchyState(SparseArray<Parcelable> toolbarStates);
+ void setBackgroundDrawable(Drawable d);
+ int getHeight();
+ void setVisibility(int visible);
+ int getVisibility();
+ void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+ MenuBuilder.Callback menuBuilderCallback);
+ Menu getMenu();
}
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;
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 375822f..25b4945 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -63,18 +63,22 @@ public class ResolverDrawerLayout extends ViewGroup {
private float mCollapseOffset;
private int mCollapsibleHeight;
+ private int mUncollapsibleHeight;
private int mTopOffset;
private boolean mIsDragging;
private boolean mOpenOnClick;
private boolean mOpenOnLayout;
+ private boolean mDismissOnScrollerFinished;
private final int mTouchSlop;
private final float mMinFlingVelocity;
private final OverScroller mScroller;
private final VelocityTracker mVelocityTracker;
- private OnClickListener mClickOutsideListener;
+ private OnDismissedListener mOnDismissedListener;
+ private RunOnDismissedListener mRunOnDismissedListener;
+
private float mInitialTouchX;
private float mInitialTouchY;
private float mLastTouchY;
@@ -143,8 +147,8 @@ public class ResolverDrawerLayout extends ViewGroup {
return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
}
- public void setOnClickOutsideListener(OnClickListener listener) {
- mClickOutsideListener = listener;
+ public void setOnDismissedListener(OnDismissedListener listener) {
+ mOnDismissedListener = listener;
}
@Override
@@ -194,7 +198,7 @@ public class ResolverDrawerLayout extends ViewGroup {
}
if (mIsDragging) {
- mScroller.abortAnimation();
+ abortAnimation();
}
return mIsDragging || mOpenOnClick;
}
@@ -213,12 +217,9 @@ public class ResolverDrawerLayout extends ViewGroup {
mInitialTouchX = x;
mInitialTouchY = mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
- if (findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
- mClickOutsideListener != null) {
- mIsDragging = handled = true;
- }
- handled |= mCollapsibleHeight > 0;
- mScroller.abortAnimation();
+ mIsDragging = findChildUnder(mInitialTouchX, mInitialTouchY) != null;
+ handled = (!mIsDragging && mOnDismissedListener != null) || mCollapsibleHeight > 0;
+ abortAnimation();
}
break;
@@ -264,11 +265,12 @@ public class ResolverDrawerLayout extends ViewGroup {
break;
case MotionEvent.ACTION_UP: {
+ final boolean wasDragging = mIsDragging;
mIsDragging = false;
- if (!mIsDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
+ if (!wasDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
findChildUnder(ev.getX(), ev.getY()) == null) {
- if (mClickOutsideListener != null) {
- mClickOutsideListener.onClick(this);
+ if (mOnDismissedListener != null) {
+ dispatchOnDismissed();
resetTouch();
return true;
}
@@ -281,7 +283,13 @@ public class ResolverDrawerLayout extends ViewGroup {
mVelocityTracker.computeCurrentVelocity(1000);
final float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
if (Math.abs(yvel) > mMinFlingVelocity) {
- smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ if (mOnDismissedListener != null
+ && yvel > 0 && mCollapseOffset > mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
+ mDismissOnScrollerFinished = true;
+ } else {
+ smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ }
} else {
smoothScrollTo(
mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0);
@@ -327,17 +335,27 @@ public class ResolverDrawerLayout extends ViewGroup {
@Override
public void computeScroll() {
super.computeScroll();
- if (!mScroller.isFinished()) {
- final boolean keepGoing = mScroller.computeScrollOffset();
+ if (mScroller.computeScrollOffset()) {
+ final boolean keepGoing = !mScroller.isFinished();
performDrag(mScroller.getCurrY() - mCollapseOffset);
if (keepGoing) {
postInvalidateOnAnimation();
+ } else if (mDismissOnScrollerFinished && mOnDismissedListener != null) {
+ mRunOnDismissedListener = new RunOnDismissedListener();
+ post(mRunOnDismissedListener);
}
}
}
+ private void abortAnimation() {
+ mScroller.abortAnimation();
+ mRunOnDismissedListener = null;
+ mDismissOnScrollerFinished = false;
+ }
+
private float performDrag(float dy) {
- final float newPos = Math.max(0, Math.min(mCollapseOffset + dy, mCollapsibleHeight));
+ final float newPos = Math.max(0, Math.min(mCollapseOffset + dy,
+ mCollapsibleHeight + mUncollapsibleHeight));
if (newPos != mCollapseOffset) {
dy = newPos - mCollapseOffset;
final int childCount = getChildCount();
@@ -356,11 +374,18 @@ public class ResolverDrawerLayout extends ViewGroup {
return 0;
}
- private void smoothScrollTo(int yOffset, float velocity) {
- if (getMaxCollapsedHeight() == 0) {
- return;
+ void dispatchOnDismissed() {
+ if (mOnDismissedListener != null) {
+ mOnDismissedListener.onDismissed();
}
- mScroller.abortAnimation();
+ if (mRunOnDismissedListener != null) {
+ removeCallbacks(mRunOnDismissedListener);
+ mRunOnDismissedListener = null;
+ }
+ }
+
+ private void smoothScrollTo(int yOffset, float velocity) {
+ abortAnimation();
final int sy = (int) mCollapseOffset;
int dy = yOffset - sy;
if (dy == 0) {
@@ -490,6 +515,7 @@ public class ResolverDrawerLayout extends ViewGroup {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnTouchModeChangeListener(mTouchModeChangeListener);
+ abortAnimation();
}
@Override
@@ -585,6 +611,7 @@ public class ResolverDrawerLayout extends ViewGroup {
mCollapsibleHeight = Math.max(0,
heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
+ mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
if (isLaidOut()) {
mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
@@ -734,4 +761,15 @@ public class ResolverDrawerLayout extends ViewGroup {
}
};
}
+
+ public interface OnDismissedListener {
+ public void onDismissed();
+ }
+
+ private class RunOnDismissedListener implements Runnable {
+ @Override
+ public void run() {
+ dispatchOnDismissed();
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index 324a6c9..054ca30 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -657,4 +657,36 @@ public class ToolbarWidgetWrapper implements DecorToolbar {
mToolbar.restoreHierarchyState(toolbarStates);
}
+ @Override
+ public void setBackgroundDrawable(Drawable d) {
+ //noinspection deprecation
+ mToolbar.setBackgroundDrawable(d);
+ }
+
+ @Override
+ public int getHeight() {
+ return mToolbar.getHeight();
+ }
+
+ @Override
+ public void setVisibility(int visible) {
+ mToolbar.setVisibility(visible);
+ }
+
+ @Override
+ public int getVisibility() {
+ return mToolbar.getVisibility();
+ }
+
+ @Override
+ public void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+ MenuBuilder.Callback menuBuilderCallback) {
+ mToolbar.setMenuCallbacks(presenterCallback, menuBuilderCallback);
+ }
+
+ @Override
+ public Menu getMenu() {
+ return mToolbar.getMenu();
+ }
+
}