Merge "Content description for next alarm" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 73f10b8..07ebe1d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1028,6 +1028,8 @@
field public static final int readPermission = 16842759; // 0x1010007
field public static final int recognitionService = 16843932; // 0x101049c
field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
+ field public static final int reparent = 16843965; // 0x10104bd
+ field public static final int reparentWithOverlay = 16843966; // 0x10104be
field public static final int repeatCount = 16843199; // 0x10101bf
field public static final int repeatMode = 16843200; // 0x10101c0
field public static final int reqFiveWayNav = 16843314; // 0x1010232
@@ -1445,6 +1447,7 @@
field public static final int windowSharedElementExitTransition = 16843834; // 0x101043a
field public static final int windowSharedElementReenterTransition = 16843954; // 0x10104b2
field public static final int windowSharedElementReturnTransition = 16843953; // 0x10104b1
+ field public static final int windowSharedElementsUseOverlay = 16843964; // 0x10104bc
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -3595,8 +3598,11 @@
}
public class ActivityManager {
+ method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
method public boolean clearApplicationUserData();
method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
+ method public int getAppTaskThumbnailHeight();
+ method public int getAppTaskThumbnailWidth();
method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
method public int getLargeMemoryClass();
@@ -3630,6 +3636,7 @@
public static class ActivityManager.AppTask {
method public void finishAndRemoveTask();
method public android.app.ActivityManager.RecentTaskInfo getTaskInfo();
+ method public void setExcludeFromRecents(boolean);
}
public static class ActivityManager.MemoryInfo implements android.os.Parcelable {
@@ -5500,23 +5507,23 @@
field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
- field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.defaultManagedProfileName";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.deviceAdminPackageChecksum";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.deviceAdminPackageDownloadCookieHeader";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.deviceAdminPackageDownloadLocation";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName";
- field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.ManagedProfileEmailAddress";
- field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.locale";
- field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.localTime";
- field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.timeZone";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.wifiHidden";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.wifiPacUrl";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PASSWORD = "android.app.extra.wifiPassword";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS = "android.app.extra.wifiProxyBypassHosts";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_HOST = "android.app.extra.wifiProxyHost";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.wifiProxyPort";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.wifiSecurityType";
- field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.wifiSsid";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.DEFAULT_MANAGED_PROFILE_NAME";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.DEVICE_ADMIN_PACKAGE_CHECKSUM";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.DEVICE_ADMIN_PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.MANAGED_PROFILE_EMAIL_ADDRESS";
+ field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.LOCALE";
+ field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.LOCAL_TIME";
+ field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.TIME_ZONE";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.WIFI_HIDDEN";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.WIFI_PAC_URL";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PASSWORD = "android.app.extra.WIFI_PASSWORD";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS = "android.app.extra.WIFI_PROXY_BYPASS_HOSTS";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_HOST = "android.app.extra.WIFI_PROXY_HOST";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.WIFI_PROXY_PORT";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.WIFI_SECURITY_TYPE";
+ field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.WIFI_SSID";
field public static int FLAG_MANAGED_CAN_ACCESS_PARENT;
field public static int FLAG_PARENT_CAN_ACCESS_MANAGED;
field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
@@ -6325,7 +6332,6 @@
method public deprecated void abortReliableWrite(android.bluetooth.BluetoothDevice);
method public boolean beginReliableWrite();
method public void close();
- method public boolean configureMTU(int);
method public boolean connect();
method public void disconnect();
method public boolean discoverServices();
@@ -6339,14 +6345,15 @@
method public boolean readCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
method public boolean readDescriptor(android.bluetooth.BluetoothGattDescriptor);
method public boolean readRemoteRssi();
- method public boolean requestConnectionParameterUpdate(int);
+ method public boolean requestConnectionPriority(int);
+ method public boolean requestMtu(int);
method public boolean setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic, boolean);
method public boolean writeCharacteristic(android.bluetooth.BluetoothGattCharacteristic);
method public boolean writeDescriptor(android.bluetooth.BluetoothGattDescriptor);
- field public static final int GATT_CONNECTION_BALANCED = 0; // 0x0
+ field public static final int CONNECTION_PRIORITY_BALANCED = 0; // 0x0
+ field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1
+ field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2
field public static final int GATT_CONNECTION_CONGESTED = 143; // 0x8f
- field public static final int GATT_CONNECTION_HIGH_PRIORITY = 1; // 0x1
- field public static final int GATT_CONNECTION_LOW_POWER = 2; // 0x2
field public static final int GATT_FAILURE = 257; // 0x101
field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5
field public static final int GATT_INSUFFICIENT_ENCRYPTION = 15; // 0xf
@@ -6363,11 +6370,11 @@
method public void onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic);
method public void onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
method public void onCharacteristicWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int);
- method public void onConfigureMTU(android.bluetooth.BluetoothGatt, int, int);
method public void onConnectionCongested(android.bluetooth.BluetoothGatt, boolean);
method public void onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int);
method public void onDescriptorRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
method public void onDescriptorWrite(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattDescriptor, int);
+ method public void onMtuChanged(android.bluetooth.BluetoothGatt, int, int);
method public void onReadRemoteRssi(android.bluetooth.BluetoothGatt, int, int);
method public void onReliableWriteCompleted(android.bluetooth.BluetoothGatt, int);
method public void onServicesDiscovered(android.bluetooth.BluetoothGatt, int);
@@ -12682,7 +12689,7 @@
method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>);
method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys();
method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys();
- field public static final android.hardware.camera2.CameraCharacteristics.Key COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES;
+ field public static final android.hardware.camera2.CameraCharacteristics.Key COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_MODES;
field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
@@ -12796,9 +12803,9 @@
public abstract class CameraMetadata {
method public java.util.List<TKey> getKeys();
- field public static final int COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_FAST = 1; // 0x1
- field public static final int COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
- field public static final int COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_OFF = 0; // 0x0
+ field public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1; // 0x1
+ field public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2; // 0x2
+ field public static final int COLOR_CORRECTION_ABERRATION_MODE_OFF = 0; // 0x0
field public static final int COLOR_CORRECTION_MODE_FAST = 1; // 0x1
field public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int COLOR_CORRECTION_MODE_TRANSFORM_MATRIX = 0; // 0x0
@@ -12989,7 +12996,7 @@
method public java.lang.Object getTag();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.hardware.camera2.CaptureRequest.Key BLACK_LEVEL_LOCK;
- field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_ABERRATION_CORRECTION_MODE;
+ field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_ABERRATION_MODE;
field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_GAINS;
field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_MODE;
field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_TRANSFORM;
@@ -13061,7 +13068,7 @@
method public android.hardware.camera2.CaptureRequest getRequest();
method public int getSequenceId();
field public static final android.hardware.camera2.CaptureResult.Key BLACK_LEVEL_LOCK;
- field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_ABERRATION_CORRECTION_MODE;
+ field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_ABERRATION_MODE;
field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_GAINS;
field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_MODE;
field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_TRANSFORM;
@@ -18712,7 +18719,6 @@
method public boolean invokeBeam(android.app.Activity);
method public boolean isEnabled();
method public boolean isNdefPushEnabled();
- method public boolean registerLockscreenDispatch(android.nfc.NfcAdapter.NfcLockscreenDispatch, java.lang.String[]);
method public void setBeamPushUris(android.net.Uri[], android.app.Activity);
method public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
@@ -18748,10 +18754,6 @@
method public abstract android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
}
- public static abstract interface NfcAdapter.NfcLockscreenDispatch {
- method public abstract boolean onTagDetected(android.nfc.Tag);
- }
-
public static abstract interface NfcAdapter.OnNdefPushCompleteCallback {
method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
}
@@ -31803,7 +31805,7 @@
ctor public ChangeBounds(android.content.Context, android.util.AttributeSet);
method public void captureEndValues(android.transition.TransitionValues);
method public void captureStartValues(android.transition.TransitionValues);
- method public void setReparent(boolean);
+ method public deprecated void setReparent(boolean);
method public void setResizeClip(boolean);
}
@@ -31826,6 +31828,10 @@
ctor public ChangeTransform(android.content.Context, android.util.AttributeSet);
method public void captureEndValues(android.transition.TransitionValues);
method public void captureStartValues(android.transition.TransitionValues);
+ method public boolean getReparent();
+ method public boolean getReparentWithOverlay();
+ method public void setReparent(boolean);
+ method public void setReparentWithOverlay(boolean);
}
public class CircularPropagation extends android.transition.VisibilityPropagation {
@@ -35138,6 +35144,7 @@
method public android.transition.Transition getSharedElementExitTransition();
method public android.transition.Transition getSharedElementReenterTransition();
method public android.transition.Transition getSharedElementReturnTransition();
+ method public boolean getSharedElementsUseOverlay();
method public abstract int getStatusBarColor();
method public long getTransitionBackgroundFadeDuration();
method public android.transition.TransitionManager getTransitionManager();
@@ -35199,6 +35206,7 @@
method public void setSharedElementExitTransition(android.transition.Transition);
method public void setSharedElementReenterTransition(android.transition.Transition);
method public void setSharedElementReturnTransition(android.transition.Transition);
+ method public void setSharedElementsUseOverlay(boolean);
method public void setSoftInputMode(int);
method public abstract void setStatusBarColor(int);
method public abstract void setTitle(java.lang.CharSequence);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4b022ff..b86621f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,6 +16,11 @@
package android.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Point;
import android.os.BatteryStats;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -47,16 +52,13 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
-import android.util.Log;
import android.util.Slog;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* Interact with the overall activities running in the system.
@@ -297,6 +299,8 @@
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 13;
+ Point mAppTaskThumbnailSize;
+
/*package*/ ActivityManager(Context context, Handler handler) {
mContext = context;
mHandler = handler;
@@ -994,6 +998,103 @@
}
/**
+ * Return the current design width for {@link AppTask} thumbnails, for use
+ * with {@link #addAppTask}.
+ */
+ public int getAppTaskThumbnailWidth() {
+ synchronized (this) {
+ ensureAppTaskThumbnailSizeLocked();
+ return mAppTaskThumbnailSize.x;
+ }
+ }
+
+ /**
+ * Return the current design height for {@link AppTask} thumbnails, for use
+ * with {@link #addAppTask}.
+ */
+ public int getAppTaskThumbnailHeight() {
+ synchronized (this) {
+ ensureAppTaskThumbnailSizeLocked();
+ return mAppTaskThumbnailSize.y;
+ }
+ }
+
+ private void ensureAppTaskThumbnailSizeLocked() {
+ if (mAppTaskThumbnailSize == null) {
+ try {
+ mAppTaskThumbnailSize = ActivityManagerNative.getDefault().getAppTaskThumbnailSize();
+ } catch (RemoteException e) {
+ throw new IllegalStateException("System dead?", e);
+ }
+ }
+ }
+
+ /**
+ * Add a new {@link AppTask} for the calling application. This will create a new
+ * recents entry that is added to the <b>end</b> of all existing recents.
+ *
+ * @param activity The activity that is adding the entry. This is used to help determine
+ * the context that the new recents entry will be in.
+ * @param intent The Intent that describes the recents entry. This is the same Intent that
+ * you would have used to launch the activity for it. In generally you will want to set
+ * both {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT} and
+ * {@link Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS}; the latter is required since this recents
+ * entry will exist without an activity, so it doesn't make sense to not retain it when
+ * its activity disappears. The given Intent here also must have an explicit ComponentName
+ * set on it.
+ * @param description Optional additional description information.
+ * @param thumbnail Thumbnail to use for the recents entry. Should be the size given by
+ * {@link #getAppTaskThumbnailWidth()} and {@link #getAppTaskThumbnailHeight()}. If the
+ * bitmap is not that exact size, it will be recreated in your process, probably in a way
+ * you don't like, before the recents entry is added.
+ *
+ * @return Returns the task id of the newly added app task, or -1 if the add failed. The
+ * most likely cause of failure is that there is no more room for more tasks for your app.
+ */
+ public int addAppTask(@NonNull Activity activity, @NonNull Intent intent,
+ @Nullable TaskDescription description, @NonNull Bitmap thumbnail) {
+ Point size;
+ synchronized (this) {
+ ensureAppTaskThumbnailSizeLocked();
+ size = mAppTaskThumbnailSize;
+ }
+ final int tw = thumbnail.getWidth();
+ final int th = thumbnail.getHeight();
+ if (tw != size.x || th != size.y) {
+ Bitmap bm = Bitmap.createBitmap(size.x, size.y, thumbnail.getConfig());
+
+ // Use ScaleType.CENTER_CROP, except we leave the top edge at the top.
+ float scale;
+ float dx = 0, dy = 0;
+ if (tw * size.x > size.y * th) {
+ scale = (float) size.x / (float) th;
+ dx = (size.y - tw * scale) * 0.5f;
+ } else {
+ scale = (float) size.y / (float) tw;
+ dy = (size.x - th * scale) * 0.5f;
+ }
+ Matrix matrix = new Matrix();
+ matrix.setScale(scale, scale);
+ matrix.postTranslate((int) (dx + 0.5f), 0);
+
+ Canvas canvas = new Canvas(bm);
+ canvas.drawBitmap(thumbnail, matrix, null);
+ canvas.setBitmap(null);
+
+ thumbnail = bm;
+ }
+ if (description == null) {
+ description = new TaskDescription();
+ }
+ try {
+ return ActivityManagerNative.getDefault().addAppTask(activity.getActivityToken(),
+ intent, description, thumbnail);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("System dead?", e);
+ }
+ }
+
+ /**
* Return a list of the tasks that are currently running, with
* the most recent being first and older ones after in order. Note that
* "running" does not mean any of the task's code is currently loaded or
@@ -2514,5 +2615,20 @@
return null;
}
}
+
+ /**
+ * Modify the {@link Intent#FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS} flag in the root
+ * Intent of this AppTask.
+ *
+ * @param exclude If true, {@link Intent#FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS} will
+ * be set; otherwise, it will be cleared.
+ */
+ public void setExcludeFromRecents(boolean exclude) {
+ try {
+ mAppTaskImpl.setExcludeFromRecents(exclude);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Invalid AppTask", e);
+ }
+ }
}
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1cb1047..3dafa4b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -30,6 +30,8 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
@@ -564,6 +566,27 @@
return true;
}
+ case ADD_APP_TASK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder activityToken = data.readStrongBinder();
+ Intent intent = Intent.CREATOR.createFromParcel(data);
+ ActivityManager.TaskDescription descr
+ = ActivityManager.TaskDescription.CREATOR.createFromParcel(data);
+ Bitmap thumbnail = Bitmap.CREATOR.createFromParcel(data);
+ int res = addAppTask(activityToken, intent, descr, thumbnail);
+ reply.writeNoException();
+ reply.writeInt(res);
+ return true;
+ }
+
+ case GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ Point size = getAppTaskThumbnailSize();
+ reply.writeNoException();
+ size.writeToParcel(reply, 0);
+ return true;
+ }
+
case GET_TASKS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int maxNum = data.readInt();
@@ -2877,6 +2900,33 @@
reply.recycle();
return list;
}
+ public int addAppTask(IBinder activityToken, Intent intent,
+ ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(activityToken);
+ intent.writeToParcel(data, 0);
+ description.writeToParcel(data, 0);
+ thumbnail.writeToParcel(data, 0);
+ mRemote.transact(ADD_APP_TASK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+ public Point getAppTaskThumbnailSize() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Point size = Point.CREATOR.createFromParcel(reply);
+ data.recycle();
+ reply.recycle();
+ return size;
+ }
public List getTasks(int maxNum, int flags) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 7d2f677..e4f2b88 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -665,6 +665,9 @@
}
protected void moveSharedElementsToOverlay() {
+ if (!mWindow.getSharedElementsUseOverlay()) {
+ return;
+ }
int numSharedElements = mSharedElements.size();
ViewGroup decor = getDecor();
if (decor != null) {
@@ -700,6 +703,17 @@
}
protected void moveSharedElementsFromOverlay() {
+ int numListeners = mGhostViewListeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ GhostViewListeners listener = mGhostViewListeners.get(i);
+ ViewGroup parent = (ViewGroup) listener.getView().getParent();
+ parent.getViewTreeObserver().removeOnPreDrawListener(listener);
+ }
+ mGhostViewListeners.clear();
+
+ if (mWindow == null || !mWindow.getSharedElementsUseOverlay()) {
+ return;
+ }
ViewGroup decor = getDecor();
if (decor != null) {
ViewGroupOverlay overlay = decor.getOverlay();
@@ -709,13 +723,6 @@
GhostView.removeGhost(sharedElement);
}
}
- int numListeners = mGhostViewListeners.size();
- for (int i = 0; i < numListeners; i++) {
- GhostViewListeners listener = mGhostViewListeners.get(i);
- ViewGroup parent = (ViewGroup) listener.getView().getParent();
- parent.getViewTreeObserver().removeOnPreDrawListener(listener);
- }
- mGhostViewListeners.clear();
}
protected void setGhostVisibility(int visibility) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b2812e3..9342ae5 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -749,10 +749,10 @@
putCachedIcon(name, dr);
return dr;
} catch (NameNotFoundException e) {
- Log.w("PackageManager", "Failure retrieving resources for"
+ Log.w("PackageManager", "Failure retrieving resources for "
+ appInfo.packageName);
} catch (Resources.NotFoundException e) {
- Log.w("PackageManager", "Failure retrieving resources for"
+ Log.w("PackageManager", "Failure retrieving resources for "
+ appInfo.packageName + ": " + e.getMessage());
} catch (RuntimeException e) {
// If an exception was thrown, fall through to return
@@ -1100,7 +1100,7 @@
putCachedString(name, text);
return text;
} catch (NameNotFoundException e) {
- Log.w("PackageManager", "Failure retrieving resources for"
+ Log.w("PackageManager", "Failure retrieving resources for "
+ appInfo.packageName);
} catch (RuntimeException e) {
// If an exception was thrown, fall through to return
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8e21899..70514d8 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -36,6 +36,7 @@
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
@@ -119,6 +120,9 @@
public String getCallingPackage(IBinder token) throws RemoteException;
public ComponentName getCallingActivity(IBinder token) throws RemoteException;
public List<IAppTask> getAppTasks() throws RemoteException;
+ public int addAppTask(IBinder activityToken, Intent intent,
+ ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException;
+ public Point getAppTaskThumbnailSize() throws RemoteException;
public List<RunningTaskInfo> getTasks(int maxNum, int flags) throws RemoteException;
public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
int flags, int userId) throws RemoteException;
@@ -765,4 +769,6 @@
int NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+230;
int KEYGUARD_WAITING_FOR_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+231;
int START_ACTIVITY_AS_CALLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+232;
+ int ADD_APP_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+233;
+ int GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+234;
}
diff --git a/core/java/android/app/IAppTask.aidl b/core/java/android/app/IAppTask.aidl
index 268b4dd..4e38c36 100644
--- a/core/java/android/app/IAppTask.aidl
+++ b/core/java/android/app/IAppTask.aidl
@@ -22,4 +22,5 @@
interface IAppTask {
void finishAndRemoveTask();
ActivityManager.RecentTaskInfo getTaskInfo();
+ void setExcludeFromRecents(boolean exclude);
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8545e99..0dc8f66 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -126,7 +126,7 @@
* message containing an Nfc record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
- = "android.app.extra.deviceAdminPackageName";
+ = "android.app.extra.DEVICE_ADMIN_PACKAGE_NAME";
/**
* A String extra holding the default name of the profile that is created during managed profile
@@ -135,7 +135,7 @@
* <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}
*/
public static final String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME
- = "android.app.extra.defaultManagedProfileName";
+ = "android.app.extra.DEFAULT_MANAGED_PROFILE_NAME";
/**
* A String extra that, holds the email address of the account which a managed profile is
@@ -149,7 +149,7 @@
* It is usually used to avoid that the user has to enter their email address twice.
*/
public static final String EXTRA_PROVISIONING_EMAIL_ADDRESS
- = "android.app.extra.ManagedProfileEmailAddress";
+ = "android.app.extra.MANAGED_PROFILE_EMAIL_ADDRESS";
/**
* A String extra holding the time zone {@link android.app.AlarmManager} that the device
@@ -159,17 +159,17 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_TIME_ZONE
- = "android.app.extra.timeZone";
+ = "android.app.extra.TIME_ZONE";
/**
- * A Long extra holding the local time {@link android.app.AlarmManager} that the device
- * will be set to.
+ * A Long extra holding the wall clock time (in milliseconds) to be set on the device's
+ * {@link android.app.AlarmManager}.
*
* <p>Use in an Nfc record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_LOCAL_TIME
- = "android.app.extra.localTime";
+ = "android.app.extra.LOCAL_TIME";
/**
* A String extra holding the {@link java.util.Locale} that the device will be set to.
@@ -179,7 +179,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_LOCALE
- = "android.app.extra.locale";
+ = "android.app.extra.LOCALE";
/**
* A String extra holding the ssid of the wifi network that should be used during nfc device
@@ -189,7 +189,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_SSID
- = "android.app.extra.wifiSsid";
+ = "android.app.extra.WIFI_SSID";
/**
* A boolean extra indicating whether the wifi network in {@link #EXTRA_PROVISIONING_WIFI_SSID}
@@ -199,7 +199,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_HIDDEN
- = "android.app.extra.wifiHidden";
+ = "android.app.extra.WIFI_HIDDEN";
/**
* A String extra indicating the security type of the wifi network in
@@ -209,7 +209,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE
- = "android.app.extra.wifiSecurityType";
+ = "android.app.extra.WIFI_SECURITY_TYPE";
/**
* A String extra holding the password of the wifi network in
@@ -219,7 +219,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_PASSWORD
- = "android.app.extra.wifiPassword";
+ = "android.app.extra.WIFI_PASSWORD";
/**
* A String extra holding the proxy host for the wifi network in
@@ -229,7 +229,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_PROXY_HOST
- = "android.app.extra.wifiProxyHost";
+ = "android.app.extra.WIFI_PROXY_HOST";
/**
* An int extra holding the proxy port for the wifi network in
@@ -239,7 +239,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_PROXY_PORT
- = "android.app.extra.wifiProxyPort";
+ = "android.app.extra.WIFI_PROXY_PORT";
/**
* A String extra holding the proxy bypass for the wifi network in
@@ -249,7 +249,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS
- = "android.app.extra.wifiProxyBypassHosts";
+ = "android.app.extra.WIFI_PROXY_BYPASS_HOSTS";
/**
* A String extra holding the proxy auto-config (PAC) URL for the wifi network in
@@ -259,7 +259,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_WIFI_PAC_URL
- = "android.app.extra.wifiPacUrl";
+ = "android.app.extra.WIFI_PAC_URL";
/**
* A String extra holding a url that specifies the download location of the device admin
@@ -269,7 +269,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION
- = "android.app.extra.deviceAdminPackageDownloadLocation";
+ = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
/**
* A String extra holding a http cookie header which should be used in the http request to the
@@ -279,7 +279,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER
- = "android.app.extra.deviceAdminPackageDownloadCookieHeader";
+ = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
/**
* A String extra holding the SHA-1 checksum of the file at download location specified in
@@ -291,7 +291,7 @@
* provisioning via an Nfc bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
- = "android.app.extra.deviceAdminPackageChecksum";
+ = "android.app.extra.DEVICE_ADMIN_PACKAGE_CHECKSUM";
/**
* This MIME type is used for starting the Device Owner provisioning.
@@ -2160,6 +2160,7 @@
}
/** @hide */
+ @SystemApi
public String getDeviceOwner() {
if (mService != null) {
try {
@@ -2368,6 +2369,7 @@
* owner has been set for that user.
* @throws IllegalArgumentException if the userId is invalid.
*/
+ @SystemApi
public ComponentName getProfileOwner() throws IllegalArgumentException {
return getProfileOwnerAsUser(Process.myUserHandle().getIdentifier());
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 936e205..b7af544 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -434,6 +434,12 @@
* @return The job object to hand to the JobScheduler. This object is immutable.
*/
public JobInfo build() {
+ // Allow tasks with no constraints. What am I, a database?
+ if (!mHasEarlyConstraint && !mHasLateConstraint && !mRequiresCharging &&
+ !mRequiresDeviceIdle && mNetworkCapabilities == NetworkType.NONE) {
+ throw new IllegalArgumentException("You're trying to build a job with no " +
+ "constraints, this is not allowed.");
+ }
mExtras = new PersistableBundle(mExtras); // Make our own copy.
// Check that a deadline was not set on a periodic job.
if (mIsPeriodic && (mMaxExecutionDelayMillis != 0L)) {
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index 7fe192c..ca7022d 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -22,7 +22,13 @@
/**
* Class for scheduling various types of jobs with the scheduling framework on the device.
- *
+ * See {@link android.app.job.JobInfo} for more description of the types of jobs that can be run
+ * and how to construct them.
+ * The framework will be intelligent about when you receive your callbacks, and attempt to batch
+ * and defer them as much as possible. Typically if you don't specify a deadline on your job, it
+ * can be run at any moment depending on the current state of the JobScheduler's internal queue,
+ * however it might be deferred as long as until the next time the device is connected to a power
+ * source.
* <p>You do not
* instantiate this class directly; instead, retrieve it through
* {@link android.content.Context#getSystemService
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 59d7956..d77a77b 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -96,19 +96,19 @@
* Bluetooth SIG. This is the default value if no connection parameter update
* is requested.
*/
- public static final int GATT_CONNECTION_BALANCED = 0;
+ public static final int CONNECTION_PRIORITY_BALANCED = 0;
/**
* Connection paramter update - Request a high priority, low latency connection.
* An application should only request high priority connection paramters to transfer
* large amounts of data over LE quickly. Once the transfer is complete, the application
- * should request {@link BluetoothGatt#GATT_CONNECTION_BALANCED} connectoin parameters
+ * should request {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} connectoin parameters
* to reduce energy use.
*/
- public static final int GATT_CONNECTION_HIGH_PRIORITY = 1;
+ public static final int CONNECTION_PRIORITY_HIGH = 1;
/** Connection paramter update - Request low power, reduced data rate connection parameters. */
- public static final int GATT_CONNECTION_LOW_POWER = 2;
+ public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
/**
* No authentication required.
@@ -601,7 +601,7 @@
return;
}
try {
- mCallback.onConfigureMTU(BluetoothGatt.this, mtu, status);
+ mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
} catch (Exception ex) {
Log.w(TAG, "Unhandled exception in callback", ex);
}
@@ -1239,20 +1239,20 @@
}
/**
- * Configure the MTU used for a given connection.
+ * Request an MTU size used for a given connection.
*
* <p>When performing a write request operation (write without response),
* the data sent is truncated to the MTU size. This function may be used
- * to request a larget MTU size to be able to send more data at once.
+ * to request a larger MTU size to be able to send more data at once.
*
- * <p>A {@link BluetoothGattCallback#onConfigureMTU} callback will indicate
+ * <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
* whether this operation was successful.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @return true, if the new MTU value has been requested successfully
*/
- public boolean configureMTU(int mtu) {
+ public boolean requestMtu(int mtu) {
if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
+ " mtu: " + mtu);
if (mService == null || mClientIf == 0) return false;
@@ -1274,19 +1274,19 @@
* remote device.
*
* @param connectionPriority Request a specific connection priority. Must be one of
- * {@link BluetoothGatt#GATT_CONNECTION_BALANCED},
- * {@link BluetoothGatt#GATT_CONNECTION_HIGH_PRIORITY}
- * or {@link BluetoothGatt#GATT_CONNECTION_LOW_POWER}.
+ * {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED},
+ * {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}
+ * or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
* @throws IllegalArgumentException If the parameters are outside of their
* specified range.
*/
- public boolean requestConnectionParameterUpdate(int connectionPriority) {
- if (connectionPriority < GATT_CONNECTION_BALANCED ||
- connectionPriority > GATT_CONNECTION_LOW_POWER) {
+ public boolean requestConnectionPriority(int connectionPriority) {
+ if (connectionPriority < CONNECTION_PRIORITY_BALANCED ||
+ connectionPriority > CONNECTION_PRIORITY_LOW_POWER) {
throw new IllegalArgumentException("connectionPriority not within valid range");
}
- if (DBG) Log.d(TAG, "requestConnectionParameterUpdate() - params: " + connectionPriority);
+ if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority);
if (mService == null || mClientIf == 0) return false;
try {
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 5817d68..19900ec 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -143,14 +143,14 @@
* Callback indicating the MTU for a given device connection has changed.
*
* This callback is triggered in response to the
- * {@link BluetoothGatt#configureMTU} function, or in response to a connection
+ * {@link BluetoothGatt#requestMtu} function, or in response to a connection
* event.
*
- * @param gatt GATT client invoked {@link BluetoothGatt#configureMTU}
+ * @param gatt GATT client invoked {@link BluetoothGatt#requestMtu}
* @param mtu The new MTU size
* @param status {@link BluetoothGatt#GATT_SUCCESS} if the MTU has been changed successfully
*/
- public void onConfigureMTU(BluetoothGatt gatt, int mtu, int status) {
+ public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
}
/**
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
index 3a1b38ee..b0ddc26 100644
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java
@@ -141,7 +141,7 @@
* notifications.
*
* @param device The remote device the notification has been sent to
- * @param status 0 if the operation was successful
+ * @param status {@link BluetoothGatt#GATT_SUCCESS} if the operation was successful
*/
public void onNotificationSent(BluetoothDevice device, int status) {
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index a83bd4a..d19418b 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1470,6 +1470,12 @@
case 320:
parts.add("xhdpi");
break;
+ case 480:
+ parts.add("xxhdpi");
+ break;
+ case 640:
+ parts.add("xxxhdpi");
+ break;
default:
parts.add(config.densityDpi + "dpi");
break;
@@ -1542,7 +1548,7 @@
break;
}
- parts.add("v" + Build.VERSION.SDK_INT);
+ parts.add("v" + Build.VERSION.RESOURCES_SDK_INT);
return TextUtils.join("-", parts);
}
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4e7f9dd..c525348 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -313,18 +313,18 @@
/**
* <p>The set of aberration correction modes supported by this camera device.</p>
- * <p>This metadata lists the valid modes for {@link CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE android.colorCorrection.aberrationCorrectionMode}.
+ * <p>This metadata lists the valid modes for {@link CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE android.colorCorrection.aberrationMode}.
* If no aberration correction modes are available for a device, this list will solely include
* OFF mode.</p>
* <p>For FULL capability device ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} <code>==</code> FULL), OFF must be
* included.</p>
*
- * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE
+ * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
@PublicKey
- public static final Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES =
- new Key<int[]>("android.colorCorrection.availableAberrationCorrectionModes", int[].class);
+ public static final Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES =
+ new Key<int[]>("android.colorCorrection.availableAberrationModes", int[].class);
/**
* <p>The set of auto-exposure antibanding modes that are
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 9bdfe8b..3c9b7b3 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -386,8 +386,8 @@
* </ul>
* </li>
* <li>Manual aberration correction control (if aberration correction is supported)<ul>
- * <li>{@link CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE android.colorCorrection.aberrationCorrectionMode}</li>
- * <li>{@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES android.colorCorrection.availableAberrationCorrectionModes}</li>
+ * <li>{@link CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE android.colorCorrection.aberrationMode}</li>
+ * <li>{@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES android.colorCorrection.availableAberrationModes}</li>
* </ul>
* </li>
* </ul>
@@ -396,8 +396,8 @@
* <p>A given camera device may also support additional post-processing
* controls, but this capability only covers the above list of controls.</p>
*
- * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE
- * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES
+ * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
+ * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES
* @see CaptureRequest#COLOR_CORRECTION_GAINS
* @see CaptureRequest#COLOR_CORRECTION_TRANSFORM
* @see CaptureRequest#SHADING_MODE
@@ -739,28 +739,28 @@
public static final int COLOR_CORRECTION_MODE_HIGH_QUALITY = 2;
//
- // Enumeration values for CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE
+ // Enumeration values for CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
//
/**
* <p>No aberration correction is applied.</p>
- * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE
+ * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
*/
- public static final int COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_OFF = 0;
+ public static final int COLOR_CORRECTION_ABERRATION_MODE_OFF = 0;
/**
* <p>Aberration correction will not slow down capture rate
* relative to sensor raw output.</p>
- * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE
+ * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
*/
- public static final int COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_FAST = 1;
+ public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1;
/**
* <p>Aberration correction operates at improved quality but reduced
* capture rate (relative to sensor raw output).</p>
- * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_CORRECTION_MODE
+ * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
*/
- public static final int COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_HIGH_QUALITY = 2;
+ public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2;
//
// Enumeration values for CaptureRequest#CONTROL_AE_ANTIBANDING_MODE
@@ -1213,7 +1213,8 @@
* image while recording video) use case.</p>
* <p>The camera device should take the highest-quality image
* possible (given the other settings) without disrupting the
- * frame rate of video recording. </p>
+ * frame rate of video recording.<br />
+ * </p>
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
*/
public static final int CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT = 4;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 97077e6..bcdcd62 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -569,7 +569,7 @@
/**
* <p>Mode of operation for the chromatic aberration correction algorithm.</p>
* <p>This must be set to a valid mode from
- * {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES android.colorCorrection.availableAberrationCorrectionModes}.</p>
+ * {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES android.colorCorrection.availableAberrationModes}.</p>
* <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light
* can not focus on the same point after exiting from the lens. This metadata defines
* the high level control of chromatic aberration correction algorithm, which aims to
@@ -581,14 +581,14 @@
* capture rate. FAST means the camera device will not slow down capture rate when
* applying aberration correction.</p>
*
- * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES
- * @see #COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_OFF
- * @see #COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_FAST
- * @see #COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_HIGH_QUALITY
+ * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES
+ * @see #COLOR_CORRECTION_ABERRATION_MODE_OFF
+ * @see #COLOR_CORRECTION_ABERRATION_MODE_FAST
+ * @see #COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY
*/
@PublicKey
- public static final Key<Integer> COLOR_CORRECTION_ABERRATION_CORRECTION_MODE =
- new Key<Integer>("android.colorCorrection.aberrationCorrectionMode", int.class);
+ public static final Key<Integer> COLOR_CORRECTION_ABERRATION_MODE =
+ new Key<Integer>("android.colorCorrection.aberrationMode", int.class);
/**
* <p>The desired setting for the camera device's auto-exposure
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 63dff55..f9c4df4 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -420,7 +420,7 @@
/**
* <p>Mode of operation for the chromatic aberration correction algorithm.</p>
* <p>This must be set to a valid mode from
- * {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES android.colorCorrection.availableAberrationCorrectionModes}.</p>
+ * {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES android.colorCorrection.availableAberrationModes}.</p>
* <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light
* can not focus on the same point after exiting from the lens. This metadata defines
* the high level control of chromatic aberration correction algorithm, which aims to
@@ -432,14 +432,14 @@
* capture rate. FAST means the camera device will not slow down capture rate when
* applying aberration correction.</p>
*
- * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_CORRECTION_MODES
- * @see #COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_OFF
- * @see #COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_FAST
- * @see #COLOR_CORRECTION_ABERRATION_CORRECTION_MODE_HIGH_QUALITY
+ * @see CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES
+ * @see #COLOR_CORRECTION_ABERRATION_MODE_OFF
+ * @see #COLOR_CORRECTION_ABERRATION_MODE_FAST
+ * @see #COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY
*/
@PublicKey
- public static final Key<Integer> COLOR_CORRECTION_ABERRATION_CORRECTION_MODE =
- new Key<Integer>("android.colorCorrection.aberrationCorrectionMode", int.class);
+ public static final Key<Integer> COLOR_CORRECTION_ABERRATION_MODE =
+ new Key<Integer>("android.colorCorrection.aberrationMode", int.class);
/**
* <p>The desired setting for the camera device's auto-exposure
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index a15028c..621968b 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -68,6 +68,8 @@
/** This session is closed; all further calls will throw ISE */
private boolean mClosed = false;
+ /** This session failed to be configured successfully */
+ private final boolean mConfigureSuccess;
/** Do not unconfigure if this is set; another session will overwrite configuration */
private boolean mSkipUnconfigure = false;
@@ -119,10 +121,12 @@
if (configureSuccess) {
mStateListener.onConfigured(this);
if (VERBOSE) Log.v(TAG, "ctor - Created session successfully");
+ mConfigureSuccess = true;
} else {
mStateListener.onConfigureFailed(this);
mClosed = true; // do not fire any other callbacks, do not allow any other work
Log.e(TAG, "Failed to create capture session; configuration failed");
+ mConfigureSuccess = false;
}
}
@@ -285,9 +289,9 @@
// - This session is active, so close() below starts the shutdown drain
// - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener.
// - This session is already closed and has executed the idle drain listener, and
- // configureOutputs(null) has already been called.
+ // configureOutputsChecked(null) has already been called.
//
- // Do not call configureOutputs(null) going forward, since it would race with the
+ // Do not call configureOutputsChecked(null) going forward, since it would race with the
// configuration for the new session. If it was already called, then we don't care, since it
// won't get called again.
mSkipUnconfigure = true;
@@ -506,7 +510,7 @@
public void onUnconfigured(CameraDevice camera) {
synchronized (session) {
// Ignore #onUnconfigured before #close is called
- if (mClosed) {
+ if (mClosed && mConfigureSuccess) {
mUnconfigureDrainer.taskFinished();
}
}
@@ -619,7 +623,7 @@
try {
mUnconfigureDrainer.taskStarted();
- mDeviceImpl.configureOutputs(null); // begin transition to unconfigured state
+ mDeviceImpl.configureOutputsChecked(null); // begin transition to unconfigured
} catch (CameraAccessException e) {
// OK: do not throw checked exceptions.
Log.e(TAG, "Exception while configuring outputs: ", e);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 71eb0e9..79ce9df 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -312,10 +312,33 @@
}
public void configureOutputs(List<Surface> outputs) throws CameraAccessException {
+ // Leave this here for backwards compatibility with older code using this directly
+ configureOutputsChecked(outputs);
+ }
+
+ /**
+ * Attempt to configure the outputs; the device goes to idle and then configures the
+ * new outputs if possible.
+ *
+ * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
+ * are not supported, or if the sizes for that format is not supported. In this case this
+ * function will return {@code false} and the unconfigured callback will be fired.</p>
+ *
+ * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
+ * Unconfiguring the device always fires the idle callback.</p>
+ *
+ * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
+ * @return whether or not the configuration was successful
+ *
+ * @throws CameraAccessException if there were any unexpected problems during configuration
+ */
+ public boolean configureOutputsChecked(List<Surface> outputs) throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
outputs = new ArrayList<Surface>();
}
+ boolean success = false;
+
synchronized(mInterfaceLock) {
checkIfCameraClosedOrInError();
@@ -355,7 +378,17 @@
mConfiguredOutputs.put(streamId, s);
}
- mRemoteDevice.endConfigure();
+ try {
+ mRemoteDevice.endConfigure();
+ }
+ catch (IllegalArgumentException e) {
+ // OK. camera service can reject stream config if it's not supported by HAL
+ // This is only the result of a programmer misusing the camera2 api.
+ Log.e(TAG, "Stream configuration failed", e);
+ return false;
+ }
+
+ success = true;
} catch (CameraRuntimeException e) {
if (e.getReason() == CAMERA_IN_USE) {
throw new IllegalStateException("The camera is currently busy." +
@@ -365,15 +398,18 @@
throw e.asChecked();
} catch (RemoteException e) {
// impossible
- return;
- }
-
- if (outputs.size() > 0) {
- mDeviceHandler.post(mCallOnIdle);
- } else {
- mDeviceHandler.post(mCallOnUnconfigured);
+ return false;
+ } finally {
+ if (success && outputs.size() > 0) {
+ mDeviceHandler.post(mCallOnIdle);
+ } else {
+ // Always return to the 'unconfigured' state if we didn't hit a fatal error
+ mDeviceHandler.post(mCallOnUnconfigured);
+ }
}
}
+
+ return success;
}
@Override
@@ -397,7 +433,7 @@
boolean configureSuccess = true;
CameraAccessException pendingException = null;
try {
- configureOutputs(outputs); // and then block until IDLE
+ configureSuccess = configureOutputsChecked(outputs); // and then block until IDLE
} catch (CameraAccessException e) {
configureSuccess = false;
pendingException = e;
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 5815fa6..4039992 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -57,7 +57,6 @@
void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
void setP2pModes(int initatorModes, int targetModes);
- void registerLockscreenDispatch(INfcLockscreenDispatch lockscreenDispatch, in int[] techList);
void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 6bd5a32..7cc8ca4 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -384,16 +384,6 @@
public Uri[] createBeamUris(NfcEvent event);
}
-
- /**
- * A callback to be invoked when an application has registered for receiving
- * tags at the lockscreen.
- */
- public interface NfcLockscreenDispatch {
- public boolean onTagDetected(Tag tag);
- }
-
-
/**
* A callback to be invoked when an application has registered as a
* handler to unlock the device given an NFC tag at the lockscreen.
@@ -1468,26 +1458,6 @@
}
}
- public boolean registerLockscreenDispatch(final NfcLockscreenDispatch lockscreenDispatch,
- String[] techList) {
- try {
- sService.registerLockscreenDispatch(new INfcLockscreenDispatch.Stub() {
- @Override
- public boolean onTagDetected(Tag tag) throws RemoteException {
- return lockscreenDispatch.onTagDetected(tag);
- }
- }, Tag.getTechCodesFromStrings(techList));
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- return false;
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Unable to register LockscreenDispatch", e);
- return false;
- }
-
- return true;
- }
-
/**
* Registers a new NFC unlock handler with the NFC service.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 52f1dd9..2241716 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2674,6 +2674,9 @@
*/
public static final String[] CLONE_TO_MANAGED_PROFILE = {
DATE_FORMAT,
+ HAPTIC_FEEDBACK_ENABLED,
+ SOUND_EFFECTS_ENABLED,
+ TEXT_SHOW_PASSWORD,
TIME_12_24
};
@@ -4737,17 +4740,16 @@
/**
* List of TV inputs that are currently hidden. This is a string
- * containing the IDs of all hidden TV inputs. Each ID is separated by ':'.
- *
+ * containing the IDs of all hidden TV inputs. Each ID is encoded by
+ * {@link android.net.Uri#encode(String)} and separated by ':'.
* @hide
*/
public static final String TV_INPUT_HIDDEN_INPUTS = "tv_input_hidden_inputs";
/**
* List of custom TV input labels. This is a string containing <TV input id, custom name>
- * pairs. Each pair is separated by ':' and TV input id and custom name are separated by
- * ','.
- *
+ * pairs. TV input id and custom name are encoded by {@link android.net.Uri#encode(String)}
+ * and separated by ','. Each pair is separated by ':'.
* @hide
*/
public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels";
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index 6246cbe..ebb1a5c 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -107,6 +107,8 @@
*
* @param reparent true if the transition should track the parent
* container of target views and animate parent changes.
+ * @deprecated Use {@link android.transition.ChangeTransform} to handle
+ * transitions between different parents.
*/
public void setReparent(boolean reparent) {
mReparent = reparent;
diff --git a/core/java/android/transition/ChangeImageTransform.java b/core/java/android/transition/ChangeImageTransform.java
index 4b230eb..d7a9120 100644
--- a/core/java/android/transition/ChangeImageTransform.java
+++ b/core/java/android/transition/ChangeImageTransform.java
@@ -16,7 +16,6 @@
package android.transition;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.content.Context;
@@ -196,28 +195,6 @@
private ObjectAnimator createMatrixAnimator(final ImageView imageView, Matrix startMatrix,
final Matrix endMatrix) {
return ObjectAnimator.ofObject(imageView, ANIMATED_TRANSFORM_PROPERTY,
- new MatrixEvaluator(), startMatrix, endMatrix);
+ new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
}
-
- private static class MatrixEvaluator implements TypeEvaluator<Matrix> {
-
- float[] mTempStartValues = new float[9];
-
- float[] mTempEndValues = new float[9];
-
- Matrix mTempMatrix = new Matrix();
-
- @Override
- public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
- startValue.getValues(mTempStartValues);
- endValue.getValues(mTempEndValues);
- for (int i = 0; i < 9; i++) {
- float diff = mTempEndValues[i] - mTempStartValues[i];
- mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
- }
- mTempMatrix.setValues(mTempEndValues);
- return mTempMatrix;
- }
- }
-
}
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index e9be3b9..d579f54 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -16,72 +16,134 @@
package android.transition;
import android.animation.Animator;
-import android.animation.FloatArrayEvaluator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Matrix;
import android.util.AttributeSet;
-import android.util.FloatProperty;
import android.util.Property;
+import android.view.GhostView;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
/**
* This Transition captures scale and rotation for Views before and after the
* scene change and animates those changes during the transition.
*
- * <p>ChangeTransform does not work when the pivot changes between scenes, so either the
- * pivot must be set to prevent automatic pivot adjustment or the View's size must be unchanged.</p>
+ * A change in parent is handled as well by capturing the transforms from
+ * the parent before and after the scene change and animating those during the
+ * transition.
*/
public class ChangeTransform extends Transition {
private static final String TAG = "ChangeTransform";
- private static final String PROPNAME_SCALE_X = "android:changeTransform:scaleX";
- private static final String PROPNAME_SCALE_Y = "android:changeTransform:scaleY";
- private static final String PROPNAME_ROTATION_X = "android:changeTransform:rotationX";
- private static final String PROPNAME_ROTATION_Y = "android:changeTransform:rotationY";
- private static final String PROPNAME_ROTATION_Z = "android:changeTransform:rotationZ";
- private static final String PROPNAME_PIVOT_X = "android:changeTransform:pivotX";
- private static final String PROPNAME_PIVOT_Y = "android:changeTransform:pivotY";
+ private static final String PROPNAME_MATRIX = "android:changeTransform:matrix";
+ private static final String PROPNAME_TRANSFORMS = "android:changeTransform:transforms";
+ private static final String PROPNAME_PARENT = "android:changeTransform:parent";
+ private static final String PROPNAME_PARENT_MATRIX = "android:changeTransform:parentMatrix";
private static final String[] sTransitionProperties = {
- PROPNAME_SCALE_X,
- PROPNAME_SCALE_Y,
- PROPNAME_ROTATION_X,
- PROPNAME_ROTATION_Y,
- PROPNAME_ROTATION_Z,
+ PROPNAME_MATRIX,
+ PROPNAME_TRANSFORMS,
+ PROPNAME_PARENT_MATRIX,
};
- private static final FloatProperty<View>[] sChangedProperties = new FloatProperty[] {
- (FloatProperty) View.SCALE_X,
- (FloatProperty) View.SCALE_Y,
- (FloatProperty) View.ROTATION_X,
- (FloatProperty) View.ROTATION_Y,
- (FloatProperty) View.ROTATION,
- };
-
- private static Property<View, float[]> TRANSFORMS = new Property<View, float[]>(float[].class,
- "transforms") {
- @Override
- public float[] get(View object) {
- return null;
- }
-
- @Override
- public void set(View view, float[] values) {
- for (int i = 0; i < values.length; i++) {
- float value = values[i];
- if (!Float.isNaN(value)) {
- sChangedProperties[i].setValue(view, value);
+ private static final Property<View, Matrix> ANIMATION_MATRIX_PROPERTY =
+ new Property<View, Matrix>(Matrix.class, "animationMatrix") {
+ @Override
+ public Matrix get(View object) {
+ return null;
}
- }
- }
- };
+
+ @Override
+ public void set(View object, Matrix value) {
+ object.setAnimationMatrix(value);
+ }
+ };
+
+ private boolean mUseOverlay = true;
+ private boolean mReparent = true;
+ private Matrix mTempMatrix = new Matrix();
public ChangeTransform() {}
public ChangeTransform(Context context, AttributeSet attrs) {
super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeTransform);
+ mUseOverlay = a.getBoolean(R.styleable.ChangeTransform_reparentWithOverlay, true);
+ mReparent = a.getBoolean(R.styleable.ChangeTransform_reparent, true);
+ a.recycle();
+ }
+
+ /**
+ * Returns whether changes to parent should use an overlay or not. When the parent
+ * change doesn't use an overlay, it affects the transforms of the child. The
+ * default value is <code>true</code>.
+ *
+ * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
+ * it moves outside the bounds of its parent. Setting
+ * {@link android.view.ViewGroup#setClipChildren(boolean)} and
+ * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
+ * Overlays are not used and the parent is animating its location, the position of the
+ * child view will be relative to its parent's final position, so it may appear to "jump"
+ * at the beginning.</p>
+ *
+ * @return <code>true</code> when a changed parent should execute the transition
+ * inside the scene root's overlay or <code>false</code> if a parent change only
+ * affects the transform of the transitioning view.
+ */
+ public boolean getReparentWithOverlay() {
+ return mUseOverlay;
+ }
+
+ /**
+ * Sets whether changes to parent should use an overlay or not. When the parent
+ * change doesn't use an overlay, it affects the transforms of the child. The
+ * default value is <code>true</code>.
+ *
+ * <p>Note: when Overlays are not used when a parent changes, a view can be clipped when
+ * it moves outside the bounds of its parent. Setting
+ * {@link android.view.ViewGroup#setClipChildren(boolean)} and
+ * {@link android.view.ViewGroup#setClipToPadding(boolean)} can help. Also, when
+ * Overlays are not used and the parent is animating its location, the position of the
+ * child view will be relative to its parent's final position, so it may appear to "jump"
+ * at the beginning.</p>
+ *
+ * @return <code>true</code> when a changed parent should execute the transition
+ * inside the scene root's overlay or <code>false</code> if a parent change only
+ * affects the transform of the transitioning view.
+ */
+ public void setReparentWithOverlay(boolean reparentWithOverlay) {
+ mUseOverlay = reparentWithOverlay;
+ }
+
+ /**
+ * Returns whether parent changes will be tracked by the ChangeTransform. If parent
+ * changes are tracked, then the transform will adjust to the transforms of the
+ * different parents. If they aren't tracked, only the transforms of the transitioning
+ * view will be tracked. Default is true.
+ *
+ * @return whether parent changes will be tracked by the ChangeTransform.
+ */
+ public boolean getReparent() {
+ return mReparent;
+ }
+
+ /**
+ * Sets whether parent changes will be tracked by the ChangeTransform. If parent
+ * changes are tracked, then the transform will adjust to the transforms of the
+ * different parents. If they aren't tracked, only the transforms of the transitioning
+ * view will be tracked. Default is true.
+ *
+ * @param reparent Set to true to track parent changes or false to only track changes
+ * of the transitioning view without considering the parent change.
+ */
+ public void setReparent(boolean reparent) {
+ mReparent = reparent;
}
@Override
@@ -89,19 +151,29 @@
return sTransitionProperties;
}
- private void captureValues(TransitionValues values) {
- View view = values.view;
+ private void captureValues(TransitionValues transitionValues) {
+ View view = transitionValues.view;
if (view.getVisibility() == View.GONE) {
return;
}
-
- values.values.put(PROPNAME_SCALE_X, view.getScaleX());
- values.values.put(PROPNAME_SCALE_Y, view.getScaleY());
- values.values.put(PROPNAME_PIVOT_X, view.getPivotX());
- values.values.put(PROPNAME_PIVOT_Y, view.getPivotY());
- values.values.put(PROPNAME_ROTATION_X, view.getRotationX());
- values.values.put(PROPNAME_ROTATION_Y, view.getRotationY());
- values.values.put(PROPNAME_ROTATION_Z, view.getRotation());
+ transitionValues.values.put(PROPNAME_PARENT, view.getParent());
+ Transforms transforms = new Transforms(view);
+ transitionValues.values.put(PROPNAME_TRANSFORMS, transforms);
+ Matrix matrix = view.getMatrix();
+ if (matrix == null || matrix.isIdentity()) {
+ matrix = null;
+ } else {
+ matrix = new Matrix(matrix);
+ }
+ transitionValues.values.put(PROPNAME_MATRIX, matrix);
+ if (mReparent) {
+ Matrix parentMatrix = new Matrix();
+ ViewGroup parent = (ViewGroup) view.getParent();
+ parent.transformMatrixToGlobal(parentMatrix);
+ parentMatrix.preTranslate(-parent.getScrollX(), -parent.getScrollY());
+ transitionValues.values.put(PROPNAME_PARENT_MATRIX, parentMatrix);
+ }
+ return;
}
@Override
@@ -115,57 +187,252 @@
}
@Override
- public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
- if (startValues == null || endValues == null
- || !startValues.values.containsKey(PROPNAME_SCALE_X)
- || !endValues.values.containsKey(PROPNAME_SCALE_X)
- || !isPivotSame(startValues, endValues)
- || !isChanged(startValues, endValues)) {
+ if (startValues == null || endValues == null ||
+ !startValues.values.containsKey(PROPNAME_PARENT) ||
+ !endValues.values.containsKey(PROPNAME_PARENT)) {
return null;
}
- float[] start = createValues(startValues);
- float[] end = createValues(endValues);
- for (int i = 0; i < start.length; i++) {
- if (start[i] == end[i]) {
- start[i] = Float.NaN;
- end[i] = Float.NaN;
- } else {
- sChangedProperties[i].setValue(endValues.view, start[i]);
+ ViewGroup startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
+ ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
+ boolean handleParentChange = mReparent && !parentsMatch(startParent, endParent);
+
+ Matrix startMatrix = (Matrix) startValues.view.getTag(R.id.transitionTransform);
+ if (startMatrix != null) {
+ startValues.values.put(PROPNAME_MATRIX, startMatrix);
+ }
+
+ Matrix startParentMatrix = (Matrix) startValues.view.getTag(R.id.parentMatrix);
+ if (startParentMatrix != null) {
+ startValues.values.put(PROPNAME_PARENT_MATRIX, startParentMatrix);
+ }
+
+ // First handle the parent change:
+ if (handleParentChange) {
+ setMatricesForParent(startValues, endValues);
+ }
+
+ // Next handle the normal matrix transform:
+ ObjectAnimator transformAnimator = createTransformAnimator(startValues, endValues);
+
+ if (handleParentChange && transformAnimator != null && mUseOverlay) {
+ createGhostView(sceneRoot, startValues, endValues);
+ }
+
+ return transformAnimator;
+ }
+
+ private ObjectAnimator createTransformAnimator(TransitionValues startValues,
+ TransitionValues endValues) {
+ Matrix startMatrix = (Matrix) startValues.values.get(PROPNAME_MATRIX);
+ Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_MATRIX);
+
+ if (startMatrix == null) {
+ startMatrix = Matrix.IDENTITY_MATRIX;
+ }
+
+ if (endMatrix == null) {
+ endMatrix = Matrix.IDENTITY_MATRIX;
+ }
+
+ if (startMatrix.equals(endMatrix)) {
+ return null;
+ }
+
+ final Transforms transforms = (Transforms) endValues.values.get(PROPNAME_TRANSFORMS);
+
+ // clear the transform properties so that we can use the animation matrix instead
+ final View view = endValues.view;
+ setIdentityTransforms(view);
+
+ ObjectAnimator animator = ObjectAnimator.ofObject(view, ANIMATION_MATRIX_PROPERTY,
+ new TransitionUtils.MatrixEvaluator(), startMatrix, endMatrix);
+
+ AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+ private boolean mIsCanceled;
+ private Matrix mTempMatrix;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mIsCanceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mIsCanceled) {
+ view.setTagInternal(R.id.transitionTransform, null);
+ view.setTagInternal(R.id.parentMatrix, null);
+ }
+ ANIMATION_MATRIX_PROPERTY.set(view, null);
+ transforms.restore(view);
+ }
+
+ @Override
+ public void onAnimationPause(Animator animation) {
+ ValueAnimator animator = (ValueAnimator) animation;
+ Matrix currentMatrix = (Matrix) animator.getAnimatedValue();
+ if (mTempMatrix == null) {
+ mTempMatrix = new Matrix(currentMatrix);
+ } else {
+ mTempMatrix.set(currentMatrix);
+ }
+ view.setTagInternal(R.id.transitionTransform, mTempMatrix);
+ transforms.restore(view);
+ }
+
+ @Override
+ public void onAnimationResume(Animator animation) {
+ setIdentityTransforms(view);
+ }
+ };
+
+ animator.addListener(listener);
+ animator.addPauseListener(listener);
+ return animator;
+ }
+
+ private boolean parentsMatch(ViewGroup startParent, ViewGroup endParent) {
+ boolean parentsMatch = false;
+ if (!isValidTarget(startParent) || !isValidTarget(endParent)) {
+ parentsMatch = startParent == endParent;
+ } else {
+ TransitionValues endValues = getMatchedTransitionValues(startParent, true);
+ if (endValues != null) {
+ parentsMatch = endParent == endValues.view;
}
}
- FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[start.length]);
- return ObjectAnimator.ofObject(endValues.view, TRANSFORMS, evaluator, start, end);
+ return parentsMatch;
}
- private static float[] createValues(TransitionValues transitionValues) {
- float[] values = new float[sChangedProperties.length];
- for (int i = 0; i < values.length; i++) {
- values[i] = (Float) transitionValues.values.get(sTransitionProperties[i]);
+ private void createGhostView(final ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ View view = endValues.view;
+
+ Matrix endMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
+ Matrix localEndMatrix = new Matrix(endMatrix);
+ sceneRoot.transformMatrixToLocal(localEndMatrix);
+
+ GhostView ghostView = GhostView.addGhost(view, sceneRoot, localEndMatrix);
+
+ Transition outerTransition = this;
+ while (outerTransition.mParent != null) {
+ outerTransition = outerTransition.mParent;
}
- return values;
+ GhostListener listener = new GhostListener(view, ghostView, endMatrix);
+ outerTransition.addListener(listener);
+
+ if (startValues.view != endValues.view) {
+ startValues.view.setTransitionAlpha(0);
+ }
+ view.setTransitionAlpha(1);
}
- private static boolean isPivotSame(TransitionValues startValues, TransitionValues endValues) {
- float startPivotX = (Float) startValues.values.get(PROPNAME_PIVOT_X);
- float startPivotY = (Float) startValues.values.get(PROPNAME_PIVOT_Y);
- float endPivotX = (Float) endValues.values.get(PROPNAME_PIVOT_X);
- float endPivotY = (Float) endValues.values.get(PROPNAME_PIVOT_Y);
+ private void setMatricesForParent(TransitionValues startValues, TransitionValues endValues) {
+ Matrix endParentMatrix = (Matrix) endValues.values.get(PROPNAME_PARENT_MATRIX);
+ endValues.view.setTagInternal(R.id.parentMatrix, endParentMatrix);
- // We don't support pivot changes, because they could be automatically set
- // and we can't end the state in an automatic state.
- return startPivotX == endPivotX && startPivotY == endPivotY;
+ Matrix toLocal = mTempMatrix;
+ toLocal.reset();
+ endParentMatrix.invert(toLocal);
+
+ Matrix startLocal = (Matrix) startValues.values.get(PROPNAME_MATRIX);
+ if (startLocal == null) {
+ startLocal = new Matrix();
+ startValues.values.put(PROPNAME_MATRIX, startLocal);
+ }
+
+ Matrix startParentMatrix = (Matrix) startValues.values.get(PROPNAME_PARENT_MATRIX);
+ startLocal.postConcat(startParentMatrix);
+ startLocal.postConcat(toLocal);
}
- private static boolean isChanged(TransitionValues startValues, TransitionValues endValues) {
- for (int i = 0; i < sChangedProperties.length; i++) {
- Object start = startValues.values.get(sTransitionProperties[i]);
- Object end = endValues.values.get(sTransitionProperties[i]);
- if (!start.equals(end)) {
- return true;
+ private static void setIdentityTransforms(View view) {
+ setTransforms(view, 0, 0, 0, 1, 1, 0, 0, 0);
+ }
+
+ private static void setTransforms(View view, float translationX, float translationY,
+ float translationZ, float scaleX, float scaleY, float rotationX,
+ float rotationY, float rotationZ) {
+ view.setTranslationX(translationX);
+ view.setTranslationY(translationY);
+ view.setTranslationZ(translationZ);
+ view.setScaleX(scaleX);
+ view.setScaleY(scaleY);
+ view.setRotationX(rotationX);
+ view.setRotationY(rotationY);
+ view.setRotation(rotationZ);
+ }
+
+ private static class Transforms {
+ public final float translationX;
+ public final float translationY;
+ public final float translationZ;
+ public final float scaleX;
+ public final float scaleY;
+ public final float rotationX;
+ public final float rotationY;
+ public final float rotationZ;
+
+ public Transforms(View view) {
+ translationX = view.getTranslationX();
+ translationY = view.getTranslationY();
+ translationZ = view.getTranslationZ();
+ scaleX = view.getScaleX();
+ scaleY = view.getScaleY();
+ rotationX = view.getRotationX();
+ rotationY = view.getRotationY();
+ rotationZ = view.getRotation();
+ }
+
+ public void restore(View view) {
+ setTransforms(view, translationX, translationY, translationZ, scaleX, scaleY,
+ rotationX, rotationY, rotationZ);
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ if (!(that instanceof Transforms)) {
+ return false;
}
+ Transforms thatTransform = (Transforms) that;
+ return thatTransform.translationX == translationX &&
+ thatTransform.translationY == translationY &&
+ thatTransform.translationZ == translationZ &&
+ thatTransform.scaleX == scaleX &&
+ thatTransform.scaleY == scaleY &&
+ thatTransform.rotationX == rotationX &&
+ thatTransform.rotationY == rotationY &&
+ thatTransform.rotationZ == rotationZ;
}
- return false;
+ }
+
+ private static class GhostListener extends Transition.TransitionListenerAdapter {
+ private View mView;
+ private GhostView mGhostView;
+ private Matrix mEndMatrix;
+
+ public GhostListener(View view, GhostView ghostView, Matrix endMatrix) {
+ mView = view;
+ mGhostView = ghostView;
+ mEndMatrix = endMatrix;
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ transition.removeListener(this);
+ GhostView.removeGhost(mView);
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ mGhostView.setVisibility(View.INVISIBLE);
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ mGhostView.setVisibility(View.VISIBLE);
+ }
}
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 0d32d40..59ba71f 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -112,8 +112,8 @@
*
* Further information on XML resource descriptions for transitions can be found for
* {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
- * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade}, and
- * {@link android.R.styleable#Slide}.
+ * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
+ * {@link android.R.styleable#Slide}, and {@link android.R.styleable#ChangeTransform}.
*
*/
public abstract class Transition implements Cloneable {
@@ -1755,24 +1755,40 @@
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
if (oldValues != null && newValues != null) {
- for (String key : oldValues.values.keySet()) {
- Object oldValue = oldValues.values.get(key);
- Object newValue = newValues.values.get(key);
- if (oldValue != null && newValue != null &&
- !oldValue.equals(newValue)) {
- valuesChanged = true;
- if (DBG) {
- Log.d(LOG_TAG, "Transition.playTransition: " +
- "oldValue != newValue for " + key +
- ": old, new = " + oldValue + ", " + newValue);
+ String[] properties = getTransitionProperties();
+ if (properties != null) {
+ int count = properties.length;
+ for (int i = 0; i < count; i++) {
+ if (isValueChanged(oldValues, newValues, properties[i])) {
+ valuesChanged = true;
+ break;
}
- break;
+ }
+ } else {
+ for (String key : oldValues.values.keySet()) {
+ if (isValueChanged(oldValues, newValues, key)) {
+ valuesChanged = true;
+ break;
+ }
}
}
}
return valuesChanged;
}
+ private static boolean isValueChanged(TransitionValues oldValues, TransitionValues newValues,
+ String key) {
+ Object oldValue = oldValues.values.get(key);
+ Object newValue = newValues.values.get(key);
+ boolean changed = (oldValue != null && newValue != null && !oldValue.equals(newValue));
+ if (DBG && changed) {
+ Log.d(LOG_TAG, "Transition.playTransition: " +
+ "oldValue != newValue for " + key +
+ ": old, new = " + oldValue + ", " + newValue);
+ }
+ return changed;
+ }
+
/**
* This is a utility method used by subclasses to handle standard parts of
* setting up and running an Animator: it sets the {@link #getDuration()
diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java
index 931d46a..b0c9e9a 100644
--- a/core/java/android/transition/TransitionUtils.java
+++ b/core/java/android/transition/TransitionUtils.java
@@ -18,6 +18,8 @@
import android.animation.Animator;
import android.animation.AnimatorSet;
+import android.animation.TypeEvaluator;
+import android.graphics.Matrix;
/**
* Static utility methods for Transitions.
@@ -37,4 +39,25 @@
return animatorSet;
}
}
+
+ public static class MatrixEvaluator implements TypeEvaluator<Matrix> {
+
+ float[] mTempStartValues = new float[9];
+
+ float[] mTempEndValues = new float[9];
+
+ Matrix mTempMatrix = new Matrix();
+
+ @Override
+ public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
+ startValue.getValues(mTempStartValues);
+ endValue.getValues(mTempEndValues);
+ for (int i = 0; i < 9; i++) {
+ float diff = mTempEndValues[i] - mTempStartValues[i];
+ mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
+ }
+ mTempMatrix.setValues(mTempEndValues);
+ return mTempMatrix;
+ }
+ }
}
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 79dbb49..81c69d1 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -63,8 +63,6 @@
private static final String[] sTransitionProperties = {
PROPNAME_VISIBILITY,
- PROPNAME_PARENT,
- PROPNAME_SCREEN_LOCATION,
};
private static class VisibilityInfo {
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index a56d448..9433237 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
+import android.animation.Animator.AnimatorListener;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
@@ -202,7 +203,7 @@
mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
}
- final ArrayList<AnimatorListener> listeners = getListeners();
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationStart(this);
@@ -220,7 +221,7 @@
getHelper().removeDelayedAnimation(this);
nEnd(mNativePtr.get());
- final ArrayList<AnimatorListener> listeners = getListeners();
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationCancel(this);
@@ -329,13 +330,22 @@
protected void onFinished() {
mFinished = true;
- final ArrayList<AnimatorListener> listeners = getListeners();
+ final ArrayList<AnimatorListener> listeners = cloneListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
for (int i = 0; i < numListeners; i++) {
listeners.get(i).onAnimationEnd(this);
}
}
+ @SuppressWarnings("unchecked")
+ private ArrayList<AnimatorListener> cloneListeners() {
+ ArrayList<AnimatorListener> listeners = getListeners();
+ if (listeners != null) {
+ listeners = (ArrayList<AnimatorListener>) listeners.clone();
+ }
+ return listeners;
+ }
+
long getNativeAnimator() {
return mNativePtr.get();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 243d7d7..6f58582 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10793,6 +10793,15 @@
}
}
+ /** @hide */
+ public void setAnimationMatrix(Matrix matrix) {
+ invalidateViewProperty(true, false);
+ mRenderNode.setAnimationMatrix(matrix);
+ invalidateViewProperty(false, true);
+
+ invalidateParentIfNeededAndWasQuickRejected();
+ }
+
/**
* Returns the current StateListAnimator if exists.
*
@@ -13090,6 +13099,10 @@
removeSendViewScrolledAccessibilityEventCallback();
stopNestedScroll();
+ // Anything that started animating right before detach should already
+ // be in its final state when re-attached.
+ jumpDrawablesToCurrentState();
+
destroyDrawingCache();
cleanupDraw();
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e7b3152..2c7ea3e 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1662,6 +1662,27 @@
public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { }
/**
+ * Returns <code>true</code> when shared elements should use an Overlay during
+ * shared element transitions or <code>false</code> when they should animate as
+ * part of the normal View hierarchy. The default value is true.
+ *
+ * @return <code>true</code> when shared elements should use an Overlay during
+ * shared element transitions or <code>false</code> when they should animate as
+ * part of the normal View hierarchy.
+ */
+ public boolean getSharedElementsUseOverlay() { return true; }
+
+ /**
+ * Sets whether or not shared elements should use an Overlay during shared element transitions.
+ * The default value is true.
+ *
+ * @param sharedElementsUseOverlay <code>true</code> indicates that shared elements should
+ * be transitioned with an Overlay or <code>false</code>
+ * to transition within the normal View hierarchy.
+ */
+ public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) { }
+
+ /**
* @return the color of the status bar.
*/
public abstract int getStatusBarColor();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a82fa65..096fe88 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2867,8 +2867,15 @@
}
/**
- * Gives the text a shadow of the specified radius and color, the specified
- * distance from its normal position.
+ * Gives the text a shadow of the specified blur radius and color, the specified
+ * distance from its drawn position.
+ * <p>
+ * The text shadow produced does not interact with the properties on view
+ * that are responsible for real time shadows,
+ * {@link View#getElevation() elevation} and
+ * {@link View#getTranslationZ() translationZ}.
+ *
+ * @see Paint#setShadowLayer(float, float, float, int)
*
* @attr ref android.R.styleable#TextView_shadowColor
* @attr ref android.R.styleable#TextView_shadowDx
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ece3e9d..74b1fdd 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1093,6 +1093,25 @@
*/
public void setVisiblePatternEnabled(boolean enabled) {
setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled);
+
+ // Update for crypto if owner
+ int userId = getCurrentOrCallingUserId();
+ if (userId != UserHandle.USER_OWNER) {
+ return;
+ }
+
+ IBinder service = ServiceManager.getService("mount");
+ if (service == null) {
+ Log.e(TAG, "Could not find the mount service to update the user info");
+ return;
+ }
+
+ IMountService mountService = IMountService.Stub.asInterface(service);
+ try {
+ mountService.setField("PatternVisible", enabled ? "1" : "0");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error changing pattern visible state", e);
+ }
}
/**
diff --git a/core/res/res/color/switch_thumb_material_dark.xml b/core/res/res/color/switch_thumb_material_dark.xml
new file mode 100644
index 0000000..8fede70
--- /dev/null
+++ b/core/res/res/color/switch_thumb_material_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/switch_thumb_disabled_material_dark"/>
+ <item android:color="@color/switch_thumb_normal_material_dark"/>
+</selector>
diff --git a/core/res/res/color/switch_thumb_material_light.xml b/core/res/res/color/switch_thumb_material_light.xml
new file mode 100644
index 0000000..1a34b74
--- /dev/null
+++ b/core/res/res/color/switch_thumb_material_light.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@color/switch_thumb_disabled_material_light"/>
+ <item android:color="@color/switch_thumb_normal_material_light"/>
+</selector>
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 8af9ceb4..5e67395 100644
--- a/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
index 81c78c6..9c2ee13 100644
--- a/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
index 7bcebcd..ce577e5 100644
--- a/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
index eb1d945..7c305ab 100644
--- a/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-hdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 22992c0..cb8f78a 100644
--- a/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
index f44a2c2..64d4c81 100644
--- a/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
index ef4ebc0..d7faacf 100644
--- a/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
index 9ddbcf5..0a36039 100644
--- a/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-mdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 2d79d59..8e7862f 100644
--- a/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 36f9753..95cb83f 100644
--- a/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
index 1a2546f..33c1035 100644
--- a/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
index 500ec33..0226f84 100644
--- a/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 9c0b19e..eb495c6 100644
--- a/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 0edb4b8..c2268af 100644
--- a/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
index cd5b00f..b6efff3 100644
--- a/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_search_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
index 5ee867c..2b253fb 100644
--- a/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxhdpi/textfield_search_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
index 78c5ebd..fbcd7d4 100644
--- a/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_activated_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
index 36974b7..ebc9bf7 100644
--- a/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
+++ b/core/res/res/drawable-xxxhdpi/spinner_textfield_default_mtrl_alpha.9.png
Binary files differ
diff --git a/core/res/res/drawable/btn_borderless_material.xml b/core/res/res/drawable/btn_borderless_material.xml
index 47cc455..016f0ff 100644
--- a/core/res/res/drawable/btn_borderless_material.xml
+++ b/core/res/res/drawable/btn_borderless_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<ripple android:color="?attr/colorControlHighlight">
<item android:id="@id/mask"
android:drawable="@drawable/btn_default_mtrl_shape" />
diff --git a/core/res/res/drawable/btn_default_material.xml b/core/res/res/drawable/btn_default_material.xml
index b04d4fb..d00a348 100644
--- a/core/res/res/drawable/btn_default_material.xml
+++ b/core/res/res/drawable/btn_default_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<ripple android:color="?attr/colorControlHighlight">
<item android:drawable="@drawable/btn_default_mtrl_shape" />
</ripple>
diff --git a/core/res/res/drawable/btn_toggle_material.xml b/core/res/res/drawable/btn_toggle_material.xml
index a9951e7..9726782 100644
--- a/core/res/res/drawable/btn_toggle_material.xml
+++ b/core/res/res/drawable/btn_toggle_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<layer-list android:paddingMode="stack">
<item>
<ripple android:color="?attr/colorControlHighlight">
diff --git a/core/res/res/drawable/edit_text_material.xml b/core/res/res/drawable/edit_text_material.xml
index eaf5e45..bbc7301 100644
--- a/core/res/res/drawable/edit_text_material.xml
+++ b/core/res/res/drawable/edit_text_material.xml
@@ -15,10 +15,7 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetLeft="@dimen/control_inset_material"
- android:insetTop="@dimen/control_inset_material"
- android:insetBottom="@dimen/control_inset_material"
- android:insetRight="@dimen/control_inset_material">
+ android:inset="@dimen/control_inset_material">
<ripple android:color="?attr/colorControlActivated">
<item>
<selector>
diff --git a/core/res/res/drawable/spinner_textfield_background_material.xml b/core/res/res/drawable/spinner_textfield_background_material.xml
index f818baf..5bdff4a 100644
--- a/core/res/res/drawable/spinner_textfield_background_material.xml
+++ b/core/res/res/drawable/spinner_textfield_background_material.xml
@@ -14,18 +14,20 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true">
- <item android:state_checked="true">
- <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item android:state_pressed="true">
- <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
- android:tint="?attr/colorControlActivated" />
- </item>
- <item>
- <nine-patch android:src="@drawable/spinner_textfield_default_mtrl_alpha"
- android:tint="?attr/colorControlNormal" />
- </item>
-</selector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="@dimen/control_inset_material">
+ <selector android:autoMirrored="true">
+ <item android:state_checked="true">
+ <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item android:state_pressed="true">
+ <nine-patch android:src="@drawable/spinner_textfield_activated_mtrl_alpha"
+ android:tint="?attr/colorControlActivated" />
+ </item>
+ <item>
+ <nine-patch android:src="@drawable/spinner_textfield_default_mtrl_alpha"
+ android:tint="?attr/colorControlNormal" />
+ </item>
+ </selector>
+</inset>
diff --git a/core/res/res/drawable/switch_thumb_material_anim.xml b/core/res/res/drawable/switch_thumb_material_anim.xml
index 30bc8882..0d4d78e 100644
--- a/core/res/res/drawable/switch_thumb_material_anim.xml
+++ b/core/res/res/drawable/switch_thumb_material_anim.xml
@@ -16,22 +16,12 @@
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="true">
- <item
- android:state_enabled="false"
- android:state_checked="true">
- <nine-patch
- android:src="@drawable/btn_switch_to_on_mtrl_00012"
- android:gravity="center"
- android:tintMode="multiply"
- android:tint="?attr/colorControlActivated"
- android:alpha="?attr/disabledAlpha" />
- </item>
- <item android:state_enabled="false">
+ <item android:state_enabled="false" android:id="@+id/off">
<nine-patch
android:src="@drawable/btn_switch_to_on_mtrl_00001"
android:gravity="center"
android:tintMode="multiply"
- android:tint="?attr/colorButtonNormal" />
+ android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item
android:state_checked="true"
@@ -47,29 +37,29 @@
android:src="@drawable/btn_switch_to_on_mtrl_00001"
android:gravity="center"
android:tintMode="multiply"
- android:tint="?attr/colorButtonNormal" />
+ android:tint="?attr/colorSwitchThumbNormal" />
</item>
<transition
android:fromId="@+id/off"
android:toId="@+id/on">
<animation-list>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00001" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00002" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00003" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00004" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00005" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
<nine-patch android:src="@drawable/btn_switch_to_on_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" />
@@ -112,22 +102,22 @@
<nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00006" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorControlActivated" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00007" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00008" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00009" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00010" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00011" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
<item android:duration="15">
- <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorButtonNormal" />
+ <nine-patch android:src="@drawable/btn_switch_to_off_mtrl_00012" android:gravity="center" android:tintMode="multiply" android:tint="?attr/colorSwitchThumbNormal" />
</item>
</animation-list>
</transition>
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index 0728055..1ec2f88 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -15,10 +15,10 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:state_checked="true">
+ <item android:state_enabled="false">
<nine-patch android:src="@drawable/switch_track_mtrl_alpha"
- android:tint="?attr/colorControlActivated"
- android:alpha="0.2" />
+ android:tint="?attr/colorForeground"
+ android:alpha="0.1" />
</item>
<item android:state_checked="true">
<nine-patch android:src="@drawable/switch_track_mtrl_alpha"
@@ -27,7 +27,7 @@
</item>
<item>
<nine-patch android:src="@drawable/switch_track_mtrl_alpha"
- android:tint="?attr/colorButtonNormal"
+ android:tint="?attr/colorForeground"
android:alpha="0.3" />
</item>
</selector>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 327782d..f843d1f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -506,12 +506,24 @@
<!-- Used in LocalePicker -->
<string-array translatable="false" name="special_locale_codes">
+ <!-- http://b/17150708 - ensure that the list of languages says "Arabic"
+ rather than "Arabic (Egypt)". If you're an OEM supporting multiple
+ Arabic locales, you should remove this entry so that ar_EG is shown
+ as "Arabic (Egypt)" in Settings. -->
+ <item>ar_EG</item>
+
<item>zh_CN</item>
<item>zh_TW</item>
</string-array>
<!-- Used in LocalePicker -->
<string-array translatable="false" name="special_locale_names">
+ <!-- http://b/17150708 - ensure that the list of languages says "Arabic"
+ rather than "Arabic (Egypt)". If you're an OEM supporting multiple
+ Arabic locales, you should remove this entry so that ar_EG is shown
+ as "Arabic (Egypt)" in Settings. -->
+ <item>العربية</item>
+
<item>中文 (简体)</item>
<item>中文 (繁體)</item>
</string-array>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ed9e83f..3524636 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -517,6 +517,10 @@
{@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
<attr name="windowAllowExitTransitionOverlap" format="boolean"/>
+ <!-- Indicates whether or not shared elements should use an overlay
+ during transitions. The default value is true. -->
+ <attr name="windowSharedElementsUseOverlay" format="boolean"/>
+
<!-- Internal layout used internally for window decor -->
<attr name="windowActionBarFullscreenDecorLayout" format="reference" />
@@ -1005,6 +1009,9 @@
<!-- The color applied to framework buttons in their normal state. -->
<attr name="colorButtonNormal" format="color" />
+ <!-- The color applied to framework switch thumbs in their normal state. -->
+ <attr name="colorSwitchThumbNormal" format="color" />
+
<!-- ================== -->
<!-- Hardware rendering -->
<!-- ================== -->
@@ -1836,6 +1843,10 @@
{@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
<attr name="windowAllowExitTransitionOverlap"/>
+ <!-- Indicates whether or not shared elements should use an overlay
+ during transitions. The default value is true. -->
+ <attr name="windowSharedElementsUseOverlay"/>
+
<!-- Flag indicating whether this Window is responsible for drawing the background for the
system bars. If true and the window is not floating, the system bars are drawn with a
transparent background and the corresponding areas in this window are filled with the
@@ -3799,13 +3810,17 @@
<attr name="textColorLink" />
<!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
<attr name="textAllCaps" format="boolean" />
- <!-- Place a shadow of the specified color behind the text. -->
+ <!-- Place a blurred shadow of text underneath the text, drawn with the
+ specified color. The text shadow produced does not interact with
+ properties on View that are responsible for real time shadows,
+ {@link android.R.styleable#View_elevation elevation} and
+ {@link android.R.styleable#View_translationZ translationZ}. -->
<attr name="shadowColor" format="color" />
- <!-- Horizontal offset of the shadow. -->
+ <!-- Horizontal offset of the text shadow. -->
<attr name="shadowDx" format="float" />
- <!-- Vertical offset of the shadow. -->
+ <!-- Vertical offset of the text shadow. -->
<attr name="shadowDy" format="float" />
- <!-- Radius of the shadow. -->
+ <!-- Blur radius of the text shadow. -->
<attr name="shadowRadius" format="float" />
<!-- Elegant text height, especially for less compacted complex script text. -->
<attr name="elegantTextHeight" format="boolean" />
@@ -3946,13 +3961,17 @@
<!-- Set an input filter to constrain the text length to the
specified number. -->
<attr name="maxLength" format="integer" min="0" />
- <!-- Place a shadow of the specified color behind the text. -->
+ <!-- Place a blurred shadow of text underneath the text, drawn with the
+ specified color. The text shadow produced does not interact with
+ properties on View that are responsible for real time shadows,
+ {@link android.R.styleable#View_elevation elevation} and
+ {@link android.R.styleable#View_translationZ translationZ}. -->
<attr name="shadowColor" />
- <!-- Horizontal offset of the shadow. -->
+ <!-- Horizontal offset of the text shadow. -->
<attr name="shadowDx" />
- <!-- Vertical offset of the shadow. -->
+ <!-- Vertical offset of the text shadow. -->
<attr name="shadowDy" />
- <!-- Radius of the shadow. -->
+ <!-- Blur radius of the text shadow. -->
<attr name="shadowRadius" />
<attr name="autoLink" />
<!-- If set to false, keeps the movement method from being set
@@ -5589,6 +5608,19 @@
</attr>
</declare-styleable>
+ <!-- Use <code>changeTransform</code> as the root tag of the XML resource that
+ describes a {@link android.transition.ChangeTransform} transition. -->
+ <declare-styleable name="ChangeTransform">
+ <!-- A parent change should use an overlay or affect the transform of the
+ transitionining View. Default is true. Corresponds to
+ {@link android.transition.ChangeTransform#setReparentWithOverlay(boolean)}. -->
+ <attr name="reparentWithOverlay" format="boolean"/>
+
+ <!-- Tells ChangeTransform to track parent changes. Default is true. Corresponds to
+ {@link android.transition.ChangeTransform#setReparent(boolean)}. -->
+ <attr name="reparent" format="boolean"/>
+ </declare-styleable>
+
<!-- Use <code>transitionManager</code> as the root tag of the XML resource that
describes a {@link android.transition.TransitionManager
TransitionManager}. -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index ccbb8bc..2348951 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -25,6 +25,11 @@
<color name="button_material_dark">#ff5a595b</color>
<color name="button_material_light">#ffd6d7d7</color>
+ <color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
+ <color name="switch_thumb_normal_material_light">#fff1f1f1</color>
+ <color name="switch_thumb_disabled_material_dark">#ff616161</color>
+ <color name="switch_thumb_disabled_material_light">#ffbdbdbd</color>
+
<color name="bright_foreground_material_dark">@color/white</color>
<color name="bright_foreground_material_light">@color/black</color>
<!-- White 50% -->
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index c64e910..4c59f73 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -85,4 +85,6 @@
<item type="id" name="scene_layoutid_cache" />
<item type="id" name="mask" />
<item type="id" name="transitionPosition" />
+ <item type="id" name="transitionTransform" />
+ <item type="id" name="parentMatrix" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4f0c5eb..f2466f7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2275,6 +2275,9 @@
<public type="attr" name="outlineProvider" />
<public type="attr" name="ageHint" />
<public type="attr" name="country" />
+ <public type="attr" name="windowSharedElementsUseOverlay" />
+ <public type="attr" name="reparent" />
+ <public type="attr" name="reparentWithOverlay" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index af73c02..3c4e881 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1990,4 +1990,6 @@
<java-symbol type="color" name="battery_saver_mode_color" />
<java-symbol type="color" name="system_notification_accent_color" />
<java-symbol type="dimen" name="text_handle_min_size" />
+ <java-symbol type="id" name="transitionTransform" />
+ <java-symbol type="id" name="parentMatrix" />
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index b36cdb9..5445816 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -116,12 +116,12 @@
<!-- Button styles -->
<item name="buttonStyle">@style/Widget.Button</item>
-
<item name="buttonStyleSmall">@style/Widget.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.Button.Inset</item>
-
<item name="buttonStyleToggle">@style/Widget.Button.Toggle</item>
+ <item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
+
<item name="selectableItemBackground">@drawable/item_background</item>
<item name="selectableItemBackgroundBorderless">?attr/selectableItemBackground</item>
<item name="borderlessButtonStyle">?attr/buttonStyle</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 18170ac..bff5ce2 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -379,6 +379,7 @@
<item name="colorControlHighlight">@color/ripple_material_dark</item>
<item name="colorButtonNormal">@color/btn_default_material_dark</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
</style>
<!-- Material theme (light version). -->
@@ -721,6 +722,7 @@
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/btn_default_material_light</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
</style>
<!-- Variant of the material (light) theme that has a solid (opaque) action bar
@@ -774,6 +776,7 @@
<item name="colorControlNormal">?attr/textColorSecondary</item>
<item name="colorControlHighlight">@color/ripple_material_light</item>
<item name="colorButtonNormal">@color/btn_default_material_light</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_light</item>
</style>
<!-- Theme overlay that replaces colors with their dark versions but preserves
@@ -811,6 +814,7 @@
<item name="colorControlNormal">?attr/textColorSecondary</item>
<item name="colorControlHighlight">@color/ripple_material_dark</item>
<item name="colorButtonNormal">@color/btn_default_material_dark</item>
+ <item name="colorSwitchThumbNormal">@color/switch_thumb_material_dark</item>
</style>
<!-- Theme overlay that replaces the normal control color, which by default is the same as the
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 3b52b0a..af9456d 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -1678,7 +1678,7 @@
<p><b>Example intent:</b></p>
<pre>
public void composeMmsMessage(String message, Uri attachment) {
- Intent intent = new Intent(Intent.ACTION_SEND);
+ Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setType(HTTP.PLAIN_TEXT_TYPE);
intent.putExtra("sms_body", message);
intent.putExtra(Intent.EXTRA_STREAM, attachment);
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index cb952a4..ab105fd 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -31,7 +31,7 @@
<li>{@link android.view.ViewGroup}</li>
<li>{@link android.view.ViewGroup.LayoutParams}</li>
</ol>
-
+
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}training/basics/firstapp/building-ui.html">Building a Simple User
@@ -43,9 +43,9 @@
href="{@docRoot}guide/topics/appwidgets/index.html">app widget</a>.
You can declare a layout in two ways:</p>
<ul>
-<li><strong>Declare UI elements in XML</strong>. Android provides a straightforward XML
+<li><strong>Declare UI elements in XML</strong>. Android provides a straightforward XML
vocabulary that corresponds to the View classes and subclasses, such as those for widgets and layouts.</li>
-<li><strong>Instantiate layout elements at runtime</strong>. Your
+<li><strong>Instantiate layout elements at runtime</strong>. Your
application can create View and ViewGroup objects (and manipulate their properties) programmatically. </li>
</ul>
@@ -55,12 +55,12 @@
<div class="sidebox">
<ul>
<li>The <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
- Plugin for Eclipse</a> offers a layout preview of your XML —
+ Plugin for Eclipse</a> offers a layout preview of your XML —
with the XML file opened, select the <strong>Layout</strong> tab.</li>
- <li>You should also try the
- <a href="{@docRoot}tools/debugging/debugging-ui.html#hierarchyViewer">Hierarchy Viewer</a> tool,
- for debugging layouts — it reveals layout property values,
- draws wireframes with padding/margin indicators, and full rendered views while
+ <li>You should also try the
+ <a href="{@docRoot}tools/debugging/debugging-ui.html#hierarchyViewer">Hierarchy Viewer</a> tool,
+ for debugging layouts — it reveals layout property values,
+ draws wireframes with padding/margin indicators, and full rendered views while
you debug on the emulator or device.</li>
<li>The <a href="{@docRoot}tools/debugging/debugging-ui.html#layoutopt">layoutopt</a> tool lets
you quickly analyze your layouts and hierarchies for inefficiencies or other problems.</li>
@@ -68,7 +68,7 @@
</div>
<p>The advantage to declaring your UI in XML is that it enables you to better separate the presentation of your application from the code that controls its behavior. Your UI descriptions are external to your application code, which means that you can modify or adapt it without having to modify your source code and recompile. For example, you can create XML layouts for different screen orientations, different device screen sizes, and different languages. Additionally, declaring the layout in XML makes it easier to visualize the structure of your UI, so it's easier to debug problems. As such, this document focuses on teaching you how to declare your layout in XML. If you're
-interested in instantiating View objects at runtime, refer to the {@link android.view.ViewGroup} and
+interested in instantiating View objects at runtime, refer to the {@link android.view.ViewGroup} and
{@link android.view.View} class references.</p>
<p>In general, the XML vocabulary for declaring UI elements closely follows the structure and naming of the classes and methods, where element names correspond to class names and attribute names correspond to methods. In fact, the correspondence is often so direct that you can guess what XML attribute corresponds to a class method, or guess what class corresponds to a given XML element. However, note that not all vocabulary is identical. In some cases, there are slight naming differences. For
@@ -102,7 +102,7 @@
</LinearLayout>
</pre>
-<p>After you've declared your layout in XML, save the file with the <code>.xml</code> extension,
+<p>After you've declared your layout in XML, save the file with the <code>.xml</code> extension,
in your Android project's <code>res/layout/</code> directory, so it will properly compile. </p>
<p>More information about the syntax for a layout XML file is available in the <a
@@ -111,11 +111,11 @@
<h2 id="load">Load the XML Resource</h2>
<p>When you compile your application, each XML layout file is compiled into a
-{@link android.view.View} resource. You should load the layout resource from your application code, in your
+{@link android.view.View} resource. You should load the layout resource from your application code, in your
{@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate()} callback implementation.
-Do so by calling <code>{@link android.app.Activity#setContentView(int) setContentView()}</code>,
-passing it the reference to your layout resource in the form of:
-<code>R.layout.<em>layout_file_name</em></code>.
+Do so by calling <code>{@link android.app.Activity#setContentView(int) setContentView()}</code>,
+passing it the reference to your layout resource in the form of:
+<code>R.layout.<em>layout_file_name</em></code>.
For example, if your XML layout is saved as <code>main_layout.xml</code>, you would load it
for your Activity like so:</p>
<pre>
@@ -126,7 +126,7 @@
</pre>
<p>The <code>onCreate()</code> callback method in your Activity is called by the Android framework when
-your Activity is launched (see the discussion about lifecycles, in the
+your Activity is launched (see the discussion about lifecycles, in the
<a href="{@docRoot}guide/components/activities.html#Lifecycle">Activities</a>
document).</p>
@@ -136,18 +136,18 @@
<p>Every View and ViewGroup object supports their own variety of XML attributes.
Some attributes are specific to a View object (for example, TextView supports the <code>textSize</code>
attribute), but these attributes are also inherited by any View objects that may extend this class.
-Some are common to all View objects, because they are inherited from the root View class (like
-the <code>id</code> attribute). And, other attributes are considered "layout parameters," which are
+Some are common to all View objects, because they are inherited from the root View class (like
+the <code>id</code> attribute). And, other attributes are considered "layout parameters," which are
attributes that describe certain layout orientations of the View object, as defined by that object's
parent ViewGroup object.</p>
<h3 id="id">ID</h3>
<p>Any View object may have an integer ID associated with it, to uniquely identify the View within the tree.
-When the application is compiled, this ID is referenced as an integer, but the ID is typically
+When the application is compiled, this ID is referenced as an integer, but the ID is typically
assigned in the layout XML file as a string, in the <code>id</code> attribute.
This is an XML attribute common to all View objects
-(defined by the {@link android.view.View} class) and you will use it very often.
+(defined by the {@link android.view.View} class) and you will use it very often.
The syntax for an ID, inside an XML tag is:</p>
<pre>android:id="@+id/my_button"</pre>
@@ -170,7 +170,7 @@
android:text="@string/my_button_text"/>
</pre>
</li>
- <li>Then create an instance of the view object and capture it from the layout
+ <li>Then create an instance of the view object and capture it from the layout
(typically in the <code>{@link android.app.Activity#onCreate(Bundle) onCreate()}</code> method):
<pre>
Button myButton = (Button) findViewById(R.id.my_button);
@@ -178,16 +178,16 @@
</li>
</ol>
<p>Defining IDs for view objects is important when creating a {@link android.widget.RelativeLayout}.
-In a relative layout, sibling views can define their layout relative to another sibling view,
+In a relative layout, sibling views can define their layout relative to another sibling view,
which is referenced by the unique ID.</p>
<p>An ID need not be unique throughout the entire tree, but it should be
-unique within the part of the tree you are searching (which may often be the entire tree, so it's best
+unique within the part of the tree you are searching (which may often be the entire tree, so it's best
to be completely unique when possible).</p>
<h3 id="layout-params">Layout Parameters</h3>
-<p>XML layout attributes named <code>layout_<em>something</em></code> define
+<p>XML layout attributes named <code>layout_<em>something</em></code> define
layout parameters for the View that are appropriate for the ViewGroup in which it resides.</p>
<p>Every ViewGroup class implements a nested class that extends {@link
@@ -201,7 +201,7 @@
parameters associated with each view.</p>
<p>Note that every LayoutParams subclass has its own syntax for setting
-values. Each child element must define LayoutParams that are appropriate for its parent,
+values. Each child element must define LayoutParams that are appropriate for its parent,
though it may also define different LayoutParams for its own children. </p>
<p>All view groups include a width and height (<code>layout_width</code> and
@@ -236,7 +236,7 @@
two dimensions, expressed as a width and a height. The unit for location
and dimensions is the pixel.
</p>
-
+
<p>
It is possible to retrieve the location of a view by invoking the methods
{@link android.view.View#getLeft()} and {@link android.view.View#getTop()}. The former returns the left, or X,
@@ -246,7 +246,7 @@
when <code>getLeft()</code> returns 20, that means the view is located 20 pixels to the
right of the left edge of its direct parent.
</p>
-
+
<p>
In addition, several convenience methods are offered to avoid unnecessary
computations, namely {@link android.view.View#getRight()} and {@link android.view.View#getBottom()}.
@@ -254,14 +254,14 @@
rectangle representing the view. For instance, calling {@link android.view.View#getRight()}
is similar to the following computation: <code>getLeft() + getWidth()</code>.
</p>
-
+
<h2 id="SizePaddingMargins">Size, Padding and Margins</h2>
<p>
The size of a view is expressed with a width and a height. A view actually
possess two pairs of width and height values.
</p>
-
+
<p>
The first pair is known as <em>measured width</em> and
<em>measured height</em>. These dimensions define how big a view wants to be
@@ -269,16 +269,16 @@
measured dimensions can be obtained by calling {@link android.view.View#getMeasuredWidth()}
and {@link android.view.View#getMeasuredHeight()}.
</p>
-
+
<p>
The second pair is simply known as <em>width</em> and <em>height</em>, or
sometimes <em>drawing width</em> and <em>drawing height</em>. These
dimensions define the actual size of the view on screen, at drawing time and
after layout. These values may, but do not have to, be different from the
measured width and height. The width and height can be obtained by calling
- {@link android.view.View#getWidth()} and {@link android.view.View#getHeight()}.
+ {@link android.view.View#getWidth()} and {@link android.view.View#getHeight()}.
</p>
-
+
<p>
To measure its dimensions, a view takes into account its padding. The padding
is expressed in pixels for the left, top, right and bottom parts of the view.
@@ -287,9 +287,9 @@
2 pixels to the right of the left edge. Padding can be set using the
{@link android.view.View#setPadding(int, int, int, int)} method and queried by calling
{@link android.view.View#getPaddingLeft()}, {@link android.view.View#getPaddingTop()},
- {@link android.view.View#getPaddingRight()} and {@link android.view.View#getPaddingBottom()}.
+ {@link android.view.View#getPaddingRight()} and {@link android.view.View#getPaddingBottom()}.
</p>
-
+
<p>
Even though a view can define a padding, it does not provide any support for
margins. However, view groups provide such a support. Refer to
@@ -297,13 +297,13 @@
{@link android.view.ViewGroup.MarginLayoutParams} for further information.
</p>
- <p>For more information about dimensions, see
+ <p>For more information about dimensions, see
<a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">Dimension Values</a>.
</p>
-
-
-
+
+
+
<style type="text/css">
@@ -332,7 +332,7 @@
possible. Your layout draws faster if it has fewer nested layouts (a wide view hierarchy is
better than a deep view hierarchy).</p>
-<!--
+<!--
<h2 id="framelayout">FrameLayout</h2>
<p>{@link android.widget.FrameLayout FrameLayout} is the simplest type of layout
object. It's basically a blank space on your screen that you can
@@ -417,7 +417,7 @@
android.widget.ListView}, initialize a new {@link android.widget.ArrayAdapter} using a
constructor to specify the layout for each string and the string array:</p>
<pre>
-ArrayAdapter adapter = new ArrayAdapter<String>(this,
+ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, myStringArray);
</pre>
<p>The arguments for this constructor are:</p>
@@ -453,14 +453,14 @@
android.database.Cursor} you want in the layout for each result and an integer array specifying the
corresponding views that each column should be placed:</p>
<pre>
-String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
+String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};
</pre>
<p>When you instantiate the {@link android.widget.SimpleCursorAdapter}, pass the layout to use for
each result, the {@link android.database.Cursor} containing the results, and these two arrays:</p>
<pre>
-SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
+SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);
@@ -490,7 +490,7 @@
}
};
-listView.setOnItemClickListener(mMessageClickedHandler);
+listView.setOnItemClickListener(mMessageClickedHandler);
</pre>
diff --git a/docs/html/sdk/installing/create-project.jd b/docs/html/sdk/installing/create-project.jd
index c0d523a..a7c12d4 100644
--- a/docs/html/sdk/installing/create-project.jd
+++ b/docs/html/sdk/installing/create-project.jd
@@ -76,7 +76,7 @@
<img src="{@docRoot}images/tools/wizard7.png" alt="" width="750" height="509">
<p class="img-caption"><strong>Figure 7.</strong> The default project structure for a mobile app.</p>
-<p>Now you are ready to develop your app. Fore more information, see the following links:</p>
+<p>Now you are ready to develop your app. For more information, see the following links:</p>
<ul>
<li><a href="{@docRoot}training/">Training Lessons</a></li>
diff --git a/docs/html/training/wearables/data-layer/assets.jd b/docs/html/training/wearables/data-layer/assets.jd
index 52ccbb0..5dc11cb 100644
--- a/docs/html/training/wearables/data-layer/assets.jd
+++ b/docs/html/training/wearables/data-layer/assets.jd
@@ -91,7 +91,7 @@
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED &&
event.getDataItem().getUri().getPath().equals("/image")) {
- DataMapItem dataMapItem = DataMapItem.fromDataItem(dataItem);
+ DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
Asset profileAsset = dataMapItem.getDataMap().getAsset("profileImage");
Bitmap bitmap = loadBitmapFromAsset(profileAsset);
// Do something with the bitmap
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 06586ca..568d3f2 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -188,7 +188,7 @@
return createFromFamiliesWithDefault(families);
}
}
- return null;
+ throw new RuntimeException("Font asset not found " + path);
}
/**
@@ -215,7 +215,7 @@
return createFromFamiliesWithDefault(families);
}
}
- return null;
+ throw new RuntimeException("Font not found " + path);
}
/**
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 29b9141..2c8611e 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -811,6 +811,11 @@
}
@Override
+ public ColorFilter getColorFilter() {
+ return mColorFilter;
+ }
+
+ @Override
public void setColorFilter(ColorFilter cf) {
if (cf != mColorFilter) {
mColorFilter = cf;
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index be2241b..063ac09 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -211,7 +211,7 @@
final boolean canUseHardware = c.isHardwareAccelerated();
if (mCanUseHardware != canUseHardware && mCanUseHardware) {
// We've switched from hardware to non-hardware mode. Panic.
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
mCanUseHardware = canUseHardware;
@@ -231,7 +231,7 @@
final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
final int N = pendingAnimations.size();
if (N > 0) {
- cancelHardwareAnimations();
+ cancelHardwareAnimations(false);
for (int i = 0; i < N; i++) {
pendingAnimations.get(i).setTarget(c);
@@ -399,6 +399,45 @@
invalidateSelf();
}
+ public void jump() {
+ endSoftwareAnimations();
+ endHardwareAnimations();
+ }
+
+ private void endSoftwareAnimations() {
+ if (mAnimRadius != null) {
+ mAnimRadius.end();
+ }
+
+ if (mAnimOpacity != null) {
+ mAnimOpacity.end();
+ }
+
+ if (mAnimX != null) {
+ mAnimX.end();
+ }
+
+ if (mAnimY != null) {
+ mAnimY.end();
+ }
+ }
+
+ private void endHardwareAnimations() {
+ final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+ final int N = runningAnimations.size();
+ for (int i = 0; i < N; i++) {
+ runningAnimations.get(i).end();
+ }
+ runningAnimations.clear();
+
+ // Abort any pending animations. Since we always have a completion
+ // listener on a pending animation, we also need to remove ourselves.
+ if (!mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
+ }
+
private Paint getTempPaint() {
if (mTempPaint == null) {
mTempPaint = new Paint();
@@ -444,7 +483,7 @@
*/
public void cancel() {
cancelSoftwareAnimations();
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
private void cancelSoftwareAnimations() {
@@ -468,14 +507,18 @@
/**
* Cancels any running hardware animations.
*/
- private void cancelHardwareAnimations() {
+ private void cancelHardwareAnimations(boolean cancelPending) {
final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
final int N = runningAnimations.size();
for (int i = 0; i < N; i++) {
runningAnimations.get(i).cancel();
}
-
runningAnimations.clear();
+
+ if (cancelPending && !mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
}
private void removeSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 93df648..49862bc 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -203,7 +203,7 @@
final boolean canUseHardware = c.isHardwareAccelerated();
if (mCanUseHardware != canUseHardware && mCanUseHardware) {
// We've switched from hardware to non-hardware mode. Panic.
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
mCanUseHardware = canUseHardware;
@@ -223,7 +223,7 @@
final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
final int N = pendingAnimations.size();
if (N > 0) {
- cancelHardwareAnimations();
+ cancelHardwareAnimations(false);
for (int i = 0; i < N; i++) {
pendingAnimations.get(i).setTarget(c);
@@ -403,6 +403,41 @@
invalidateSelf();
}
+ public void jump() {
+ endSoftwareAnimations();
+ endHardwareAnimations();
+ }
+
+ private void endSoftwareAnimations() {
+ if (mAnimOuterOpacity != null) {
+ mAnimOuterOpacity.end();
+ }
+
+ if (mAnimX != null) {
+ mAnimX.end();
+ }
+
+ if (mAnimY != null) {
+ mAnimY.end();
+ }
+ }
+
+ private void endHardwareAnimations() {
+ final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+ final int N = runningAnimations.size();
+ for (int i = 0; i < N; i++) {
+ runningAnimations.get(i).end();
+ }
+ runningAnimations.clear();
+
+ // Abort any pending animations. Since we always have a completion
+ // listener on a pending animation, we also need to remove ourselves.
+ if (!mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
+ }
+
private Paint getTempPaint() {
if (mTempPaint == null) {
mTempPaint = new Paint();
@@ -477,7 +512,7 @@
*/
public void cancel() {
cancelSoftwareAnimations();
- cancelHardwareAnimations();
+ cancelHardwareAnimations(true);
}
private void cancelSoftwareAnimations() {
@@ -497,7 +532,7 @@
/**
* Cancels any running hardware animations.
*/
- private void cancelHardwareAnimations() {
+ private void cancelHardwareAnimations(boolean cancelPending) {
final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
final int N = runningAnimations.size();
for (int i = 0; i < N; i++) {
@@ -505,6 +540,11 @@
}
runningAnimations.clear();
+
+ if (cancelPending && !mPendingAnimations.isEmpty()) {
+ mPendingAnimations.clear();
+ removeSelf();
+ }
}
private void removeSelf() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 0447e17..ca32751f 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -199,6 +199,29 @@
}
@Override
+ public void jumpToCurrentState() {
+ super.jumpToCurrentState();
+
+ if (mRipple != null) {
+ mRipple.jump();
+ }
+
+ if (mBackground != null) {
+ mBackground.jump();
+ }
+
+ mClearingHotspots = true;
+ final int count = mAnimatingRipplesCount;
+ final Ripple[] ripples = mAnimatingRipples;
+ for (int i = 0; i < count; i++) {
+ ripples[i].jump();
+ ripples[i] = null;
+ }
+ mAnimatingRipplesCount = 0;
+ mClearingHotspots = false;
+ }
+
+ @Override
public void setAlpha(int alpha) {
super.setAlpha(alpha);
@@ -534,18 +557,6 @@
}
private void clearHotspots() {
- mClearingHotspots = true;
-
- final int count = mAnimatingRipplesCount;
- final Ripple[] ripples = mAnimatingRipples;
- for (int i = 0; i < count; i++) {
- // Calling cancel may remove the ripple from the animating ripple
- // array, so cache the reference before nulling it out.
- final Ripple ripple = ripples[i];
- ripples[i] = null;
- ripple.cancel();
- }
-
if (mRipple != null) {
mRipple.cancel();
mRipple = null;
@@ -556,8 +567,16 @@
mBackground = null;
}
- mClearingHotspots = false;
+ mClearingHotspots = true;
+ final int count = mAnimatingRipplesCount;
+ final Ripple[] ripples = mAnimatingRipples;
+ for (int i = 0; i < count; i++) {
+ ripples[i].cancel();
+ ripples[i] = null;
+ }
mAnimatingRipplesCount = 0;
+ mClearingHotspots = false;
+
invalidateSelf();
}
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index b56829d..1af497c 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1459,6 +1459,9 @@
// Loads an unmapped reference table from the package.
status_t load(const ResTable_lib_header* const header);
+ // Adds mappings from the other DynamicRefTable
+ status_t addMappings(const DynamicRefTable& other);
+
// Creates a mapping from build-time package ID to run-time package ID for
// the given package.
status_t addMapping(const String16& packageName, uint8_t packageId);
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 2a4dec0..239d682 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3346,6 +3346,7 @@
TypeList& typeList = pg->types.editItemAt(j);
typeList.appendVector(srcPg->types[j]);
}
+ pg->dynamicRefTable.addMappings(srcPg->dynamicRefTable);
pg->largestTypeId = max(pg->largestTypeId, srcPg->largestTypeId);
mPackageGroups.add(pg);
}
@@ -5604,7 +5605,6 @@
return (mError=NO_MEMORY);
}
- //printf("Adding new package id %d at index %d\n", id, idx);
err = mPackageGroups.add(group);
if (err < NO_ERROR) {
return (mError=err);
@@ -5844,6 +5844,37 @@
return NO_ERROR;
}
+status_t DynamicRefTable::addMappings(const DynamicRefTable& other) {
+ if (mAssignedPackageId != other.mAssignedPackageId) {
+ return UNKNOWN_ERROR;
+ }
+
+ const size_t entryCount = other.mEntries.size();
+ for (size_t i = 0; i < entryCount; i++) {
+ ssize_t index = mEntries.indexOfKey(other.mEntries.keyAt(i));
+ if (index < 0) {
+ mEntries.add(other.mEntries.keyAt(i), other.mEntries[i]);
+ } else {
+ if (other.mEntries[i] != mEntries[index]) {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+
+ // Merge the lookup table. No entry can conflict
+ // (value of 0 means not set).
+ for (size_t i = 0; i < 256; i++) {
+ if (mLookupTable[i] != other.mLookupTable[i]) {
+ if (mLookupTable[i] == 0) {
+ mLookupTable[i] = other.mLookupTable[i];
+ } else if (other.mLookupTable[i] != 0) {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
status_t DynamicRefTable::addMapping(const String16& packageName, uint8_t packageId)
{
ssize_t index = mEntries.indexOfKey(packageName);
@@ -6216,21 +6247,36 @@
printf("Package Groups (%d)\n", (int)pgCount);
for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
const PackageGroup* pg = mPackageGroups[pgIndex];
- printf("Package Group %d id=%d packageCount=%d name=%s\n",
+ printf("Package Group %d id=0x%02x packageCount=%d name=%s\n",
(int)pgIndex, pg->id, (int)pg->packages.size(),
String8(pg->name).string());
+ const KeyedVector<String16, uint8_t>& refEntries = pg->dynamicRefTable.entries();
+ const size_t refEntryCount = refEntries.size();
+ if (refEntryCount > 0) {
+ printf(" DynamicRefTable entryCount=%d:\n", (int) refEntryCount);
+ for (size_t refIndex = 0; refIndex < refEntryCount; refIndex++) {
+ printf(" 0x%02x -> %s\n",
+ refEntries.valueAt(refIndex),
+ String8(refEntries.keyAt(refIndex)).string());
+ }
+ printf("\n");
+ }
+
+ int packageId = pg->id;
size_t pkgCount = pg->packages.size();
for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
const Package* pkg = pg->packages[pkgIndex];
- printf(" Package %d id=%d name=%s\n", (int)pkgIndex,
+ // Use a package's real ID, since the ID may have been assigned
+ // if this package is a shared library.
+ packageId = pkg->package->id;
+ printf(" Package %d id=0x%02x name=%s\n", (int)pkgIndex,
pkg->package->id, String8(String16(pkg->package->name)).string());
}
for (size_t typeIndex=0; typeIndex < pg->types.size(); typeIndex++) {
const TypeList& typeList = pg->types[typeIndex];
if (typeList.isEmpty()) {
- //printf(" type %d NULL\n", (int)typeIndex);
continue;
}
const Type* typeConfigs = typeList[0];
@@ -6239,13 +6285,15 @@
(int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
if (typeConfigs->typeSpecFlags != NULL) {
for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
- uint32_t resID = (0xff000000 & ((pg->id)<<24))
+ uint32_t resID = (0xff000000 & ((packageId)<<24))
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
// Since we are creating resID without actually
// iterating over them, we have no idea which is a
// dynamic reference. We must check.
- pg->dynamicRefTable.lookupResourceId(&resID);
+ if (packageId == 0) {
+ pg->dynamicRefTable.lookupResourceId(&resID);
+ }
resource_name resName;
if (this->getResourceName(resID, true, &resName)) {
@@ -6303,10 +6351,12 @@
continue;
}
- uint32_t resID = (0xff000000 & ((pg->id)<<24))
+ uint32_t resID = (0xff000000 & ((packageId)<<24))
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
- pg->dynamicRefTable.lookupResourceId(&resID);
+ if (packageId == 0) {
+ pg->dynamicRefTable.lookupResourceId(&resID);
+ }
resource_name resName;
if (this->getResourceName(resID, true, &resName)) {
String8 type8;
@@ -6387,9 +6437,11 @@
const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
const uint32_t parent = dtohl(bagPtr->parent.ident);
uint32_t resolvedParent = parent;
- status_t err = pg->dynamicRefTable.lookupResourceId(&resolvedParent);
- if (err != NO_ERROR) {
- resolvedParent = 0;
+ if (Res_GETPACKAGE(resolvedParent) + 1 == 0) {
+ status_t err = pg->dynamicRefTable.lookupResourceId(&resolvedParent);
+ if (err != NO_ERROR) {
+ resolvedParent = 0;
+ }
}
printf(" Parent=0x%08x(Resolved=0x%08x), Count=%d\n",
parent, resolvedParent, N);
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 054a164..420e331 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -214,7 +214,7 @@
mHead->pendingDirty.join(left, top, right, bottom);
}
-void DamageAccumulator::peekAtDirty(SkRect* dest) {
+void DamageAccumulator::peekAtDirty(SkRect* dest) const {
*dest = mHead->pendingDirty;
}
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index 6f0bd8c..dd3365a 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -50,7 +50,7 @@
void dirty(float left, float top, float right, float bottom);
// Returns the current dirty area, *NOT* transformed by pushed transforms
- void peekAtDirty(SkRect* dest);
+ void peekAtDirty(SkRect* dest) const;
void computeCurrentTransform(Matrix4* outMatrix) const;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 0db6198..977744f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -179,13 +179,6 @@
transformUpdateNeeded = true;
}
- if (transformUpdateNeeded) {
- // update the transform in window of the layer to reset its origin wrt light source position
- Matrix4 windowTransform;
- info.damageAccumulator->computeCurrentTransform(&windowTransform);
- mLayer->setWindowTransform(windowTransform);
- }
-
SkRect dirty;
info.damageAccumulator->peekAtDirty(&dirty);
@@ -198,6 +191,12 @@
return;
}
+ if (transformUpdateNeeded) {
+ // update the transform in window of the layer to reset its origin wrt light source position
+ Matrix4 windowTransform;
+ info.damageAccumulator->computeCurrentTransform(&windowTransform);
+ mLayer->setWindowTransform(windowTransform);
+ }
if (dirty.intersect(0, 0, getWidth(), getHeight())) {
dirty.roundOut();
@@ -216,7 +215,10 @@
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingPropertiesChanges(info);
}
- uint32_t animatorDirtyMask = mAnimatorManager.animate(info);
+ uint32_t animatorDirtyMask = 0;
+ if (CC_LIKELY(info.runAnimations)) {
+ animatorDirtyMask = mAnimatorManager.animate(info);
+ }
prepareLayer(info, animatorDirtyMask);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingDisplayListChanges(info);
@@ -231,7 +233,9 @@
// Push the animators first so that setupStartValueIfNecessary() is called
// before properties() is trampled by stagingProperties(), as they are
// required by some animators.
- mAnimatorManager.pushStaging(info);
+ if (CC_LIKELY(info.runAnimations)) {
+ mAnimatorManager.pushStaging(info);
+ }
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
damageSelf(info);
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index 06c5ab4..bdac47b 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -196,12 +196,14 @@
float radius;
if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
- if (!MathUtils::isPositive(radius)) {
+ bool outlineIsRounded = MathUtils::isPositive(radius);
+ if (!outlineIsRounded || currentTransform()->isSimple()) {
// TODO: consider storing this rect separately, so that this can't be replaced with clip ops
clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op);
- return;
}
- setClippingRoundRect(allocator, bounds, radius);
+ if (outlineIsRounded) {
+ setClippingRoundRect(allocator, bounds, radius);
+ }
}
void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 331f157..74d52a3 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -65,6 +65,7 @@
, frameTimeMs(0)
, animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
+ , runAnimations(true)
, damageAccumulator(NULL)
, renderState(renderState)
, renderer(NULL)
@@ -76,6 +77,7 @@
, frameTimeMs(clone.frameTimeMs)
, animationHook(clone.animationHook)
, prepareTextures(mode == MODE_FULL)
+ , runAnimations(clone.runAnimations)
, damageAccumulator(clone.damageAccumulator)
, renderState(clone.renderState)
, renderer(clone.renderer)
@@ -88,6 +90,12 @@
// TODO: Remove this? Currently this is used to signal to stop preparing
// textures if we run out of cache space.
bool prepareTextures;
+ // TODO: buildLayer uses this to suppress running any animations, but this
+ // should probably be refactored somehow. The reason this is done is
+ // because buildLayer is not setup for injecting the animationHook, as well
+ // as this being otherwise wasted work as all the animators will be
+ // re-evaluated when the frame is actually drawn
+ bool runAnimations;
// Must not be null during actual usage
DamageAccumulator* damageAccumulator;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5922135..4bf5a8a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -257,6 +257,7 @@
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
info.renderer = mCanvas;
+ info.runAnimations = false;
node->prepareTree(info);
SkRect ignore;
mDamageAccumulator.finish(&ignore);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 7bf9e98..96e6ab9 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -94,9 +94,17 @@
* and {@link #dequeueOutputBuffer} then transfer ownership from the codec
* to the client.<p>
* The client is not required to resubmit/release buffers immediately
- * to the codec, the sample code above simply does this for simplicity's sake.<p>
+ * to the codec, the sample code above simply does this for simplicity's sake.
+ * Nonetheless, it is possible that a codec may hold off on generating
+ * output buffers until all outstanding buffers have been
+ * released/resubmitted.
+ * <p>
* Once the client has an input buffer available it can fill it with data
- * and submit it it to the codec via a call to {@link #queueInputBuffer}.<p>
+ * and submit it it to the codec via a call to {@link #queueInputBuffer}.
+ * Do not submit multiple input buffers with the same timestamp (unless
+ * it is codec-specific data marked as such using the flag
+ * {@link #BUFFER_FLAG_CODEC_CONFIG}).
+ * <p>
* The codec in turn will return an output buffer to the client in response
* to {@link #dequeueOutputBuffer}. After the output buffer has been processed
* a call to {@link #releaseOutputBuffer} will return it to the codec.
@@ -128,18 +136,64 @@
* {@link #queueInputBuffer}. The codec will continue to return output buffers
* until it eventually signals the end of the output stream by specifying
* the same flag ({@link #BUFFER_FLAG_END_OF_STREAM}) on the BufferInfo returned in
- * {@link #dequeueOutputBuffer}.
+ * {@link #dequeueOutputBuffer}. Do not submit additional input buffers after
+ * signaling the end of the input stream, unless the codec has been flushed,
+ * or stopped and restarted.
* <p>
+ * <h3>Seeking & Adaptive Playback Support</h3>
+ *
+ * You can check if a decoder supports adaptive playback via {@link
+ * MediaCodecInfo.CodecCapabilities#isFeatureSupported}. Adaptive playback
+ * is only supported if you configure the codec to decode onto a {@link
+ * android.view.Surface}.
+ *
+ * <h4>For decoders that do not support adaptive playback (including
+ * when not decoding onto a Surface)</h4>
+ *
* In order to start decoding data that's not adjacent to previously submitted
- * data (i.e. after a seek) it is necessary to {@link #flush} the decoder.
+ * data (i.e. after a seek) <em>one must</em> {@link #flush} the decoder.
* Any input or output buffers the client may own at the point of the flush are
* immediately revoked, i.e. after a call to {@link #flush} the client does not
* own any buffers anymore.
+ * <p>
+ * It is important that the input data after a flush starts at a suitable
+ * stream boundary. The first frame must be able to be decoded completely on
+ * its own (for most codecs this means an I-frame), and that no frames should
+ * refer to frames before that first new frame.
* Note that the format of the data submitted after a flush must not change,
* flush does not support format discontinuities,
- * for this a full {@link #stop}, {@link #configure}, {@link #start}
+ * for this a full {@link #stop}, {@link #configure configure()}, {@link #start}
* cycle is necessary.
*
+ * <h4>For decoders that support adaptive playback</h4>
+ *
+ * In order to start decoding data that's not adjacent to previously submitted
+ * data (i.e. after a seek) it is <em>not necessary</em> to {@link #flush} the
+ * decoder.
+ * <p>
+ * It is still important that the input data after the discontinuity starts
+ * at a suitable stream boundary (e.g. I-frame), and that no new frames refer
+ * to frames before the first frame of the new input data segment.
+ * <p>
+ * For some video formats it is also possible to change the picture size
+ * mid-stream. To do this for H.264, the new Sequence Parameter Set (SPS) and
+ * Picture Parameter Set (PPS) values must be packaged together with an
+ * Instantaneous Decoder Refresh (IDR) frame in a single buffer, which then
+ * can be enqueued as a regular input buffer.
+ * The client will receive an {@link #INFO_OUTPUT_FORMAT_CHANGED} return
+ * value from {@link #dequeueOutputBuffer dequeueOutputBuffer()} or
+ * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable()}
+ * just after the picture-size change takes place and before any
+ * frames with the new size have been returned.
+ * <p>
+ * Be careful when calling {@link #flush} shortly after you have changed
+ * the picture size. If you have not received confirmation of the picture
+ * size change, you will need to repeat the request for the new picture size.
+ * E.g. for H.264 you will need to prepend the PPS/SPS to the new IDR
+ * frame to ensure that the codec receives the picture size change request.
+ *
+ * <h3>States and error handling</h3>
+ *
* <p> During its life, a codec conceptually exists in one of the following states:
* Initialized, Configured, Executing, Error, Uninitialized, (omitting transitory states
* between them). When created by one of the factory methods,
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index d3b1520..05acf90 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -47,6 +47,7 @@
private InputStream mInputStream = null;
private boolean mAllowCrossDomainRedirect = true;
+ private boolean mAllowCrossProtocolRedirect = true;
// from com.squareup.okhttp.internal.http
private final static int HTTP_TEMP_REDIRECT = 307;
@@ -91,6 +92,8 @@
private boolean filterOutInternalHeaders(String key, String val) {
if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
mAllowCrossDomainRedirect = parseBoolean(val);
+ // cross-protocol redirects are also controlled by this flag
+ mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
} else {
return false;
}
@@ -190,8 +193,12 @@
!url.getProtocol().equals("http")) {
throw new NoRouteToHostException("Unsupported protocol redirect");
}
+ boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
+ if (!mAllowCrossProtocolRedirect && !sameProtocol) {
+ throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
+ }
boolean sameHost = mURL.getHost().equals(url.getHost());
- if (!sameHost) {
+ if (!mAllowCrossDomainRedirect && !sameHost) {
throw new NoRouteToHostException("Cross-domain redirects are disallowed");
}
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 2a0fd83..3c2ad0e 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -389,6 +389,7 @@
public void registerWithSession(MediaSessionLegacyHelper helper) {
helper.addRccListener(mRcMediaIntent, mTransportListener);
mSession = helper.getSession(mRcMediaIntent);
+ setTransportControlFlags(mTransportControlFlags);
}
/**
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 3f5697f..106e1dc 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -46,7 +46,6 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -616,11 +615,15 @@
public static Set<String> getHiddenTvInputIds(Context context, int userId) {
String hiddenIdsString = Settings.Secure.getStringForUser(
context.getContentResolver(), Settings.Secure.TV_INPUT_HIDDEN_INPUTS, userId);
+ Set<String> set = new HashSet<String>();
if (TextUtils.isEmpty(hiddenIdsString)) {
- return new HashSet<String>();
+ return set;
}
String[] ids = hiddenIdsString.split(TV_INPUT_SEPARATOR);
- return new HashSet<>(Arrays.asList(ids));
+ for (String id : ids) {
+ set.add(Uri.decode(id));
+ }
+ return set;
}
/**
@@ -641,7 +644,7 @@
String[] pairs = labelsString.split(TV_INPUT_SEPARATOR);
for (String pairString : pairs) {
String[] pair = pairString.split(CUSTOM_NAME_SEPARATOR);
- map.put(pair[0], pair[1]);
+ map.put(Uri.decode(pair[0]), Uri.decode(pair[1]));
}
return map;
}
@@ -667,7 +670,7 @@
} else {
builder.append(TV_INPUT_SEPARATOR);
}
- builder.append(inputId);
+ builder.append(Uri.encode(inputId));
}
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.TV_INPUT_HIDDEN_INPUTS, builder.toString(), userId);
@@ -695,9 +698,9 @@
} else {
builder.append(TV_INPUT_SEPARATOR);
}
- builder.append(entry.getKey());
+ builder.append(Uri.encode(entry.getKey()));
builder.append(CUSTOM_NAME_SEPARATOR);
- builder.append(entry.getValue());
+ builder.append(Uri.encode(entry.getValue()));
}
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.TV_INPUT_CUSTOM_LABELS, builder.toString(), userId);
@@ -707,14 +710,6 @@
if (TextUtils.isEmpty(value)) {
throw new IllegalArgumentException(value + " should not empty ");
}
- if (value.contains(TV_INPUT_SEPARATOR)) {
- throw new IllegalArgumentException(value + " should not include "
- + TV_INPUT_SEPARATOR);
- }
- if (value.contains(CUSTOM_NAME_SEPARATOR)) {
- throw new IllegalArgumentException(value + " should not include "
- + CUSTOM_NAME_SEPARATOR);
- }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index fb77751..5390daf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -71,6 +71,8 @@
public class SystemServicesProxy {
final static String TAG = "SystemServicesProxy";
+ final static BitmapFactory.Options sBitmapOptions;
+
ActivityManager mAm;
IActivityManager mIam;
AppWidgetManager mAwm;
@@ -89,6 +91,11 @@
Paint mBgProtectionPaint;
Canvas mBgProtectionCanvas;
+ static {
+ sBitmapOptions = new BitmapFactory.Options();
+ sBitmapOptions.inMutable = true;
+ }
+
/** Private constructor */
public SystemServicesProxy(Context context) {
mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -258,7 +265,8 @@
Bitmap thumbnail = taskThumbnail.mainThumbnail;
ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
if (thumbnail == null && descriptor != null) {
- thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor());
+ thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(),
+ null, sBitmapOptions);
}
if (descriptor != null) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index d53aa47..735fbfc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -158,8 +158,9 @@
picture = BitmapHelper.createCircularClip(
picture, avatarSize, avatarSize);
}
- records.add(new UserRecord(info, picture, false /* isGuest */, isCurrent,
- false /* isAddUser */, false /* isRestricted */));
+ int index = isCurrent ? 0 : records.size();
+ records.add(index, new UserRecord(info, picture, false /* isGuest */,
+ isCurrent, false /* isAddUser */, false /* isRestricted */));
}
}
@@ -182,7 +183,8 @@
false /* isAddUser */, createIsRestricted));
}
} else {
- records.add(guestRecord);
+ int index = guestRecord.isCurrent ? 0 : records.size();
+ records.add(index, guestRecord);
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 73358c8..9652ebd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -267,6 +267,7 @@
private Boolean mAllowExitTransitionOverlap;
private Boolean mAllowEnterTransitionOverlap;
private long mBackgroundFadeDurationMillis = -1;
+ private Boolean mSharedElementsUseOverlay;
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -3546,6 +3547,10 @@
R.styleable.Window_windowTransitionBackgroundFadeDuration,
DEFAULT_BACKGROUND_FADE_DURATION_MS);
}
+ if (mSharedElementsUseOverlay == null) {
+ mSharedElementsUseOverlay = getWindowStyle().getBoolean(
+ R.styleable.Window_windowSharedElementsUseOverlay, true);
+ }
}
}
}
@@ -4024,6 +4029,16 @@
mBackgroundFadeDurationMillis = fadeDurationMillis;
}
+ @Override
+ public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
+ mSharedElementsUseOverlay = sharedElementsUseOverlay;
+ }
+
+ @Override
+ public boolean getSharedElementsUseOverlay() {
+ return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
+ }
+
private static final class DrawableFeatureState {
DrawableFeatureState(int _featureId) {
featureId = _featureId;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index c6aa30b..f1e99fd 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1539,7 +1539,7 @@
widget.views = views;
}
- scheduleNotifyUpdateAppWidgetLocked(widget);
+ scheduleNotifyUpdateAppWidgetLocked(widget, views);
}
}
@@ -1611,7 +1611,7 @@
}
}
- private void scheduleNotifyUpdateAppWidgetLocked(Widget widget) {
+ private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
if (widget == null || widget.provider == null || widget.provider.zombie
|| widget.host.callbacks == null || widget.host.zombie) {
return;
@@ -1620,7 +1620,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = widget.host;
args.arg2 = widget.host.callbacks;
- args.arg3 = widget.views;
+ args.arg3 = updateViews;
args.argi1 = widget.appWidgetId;
mCallbackHandler.obtainMessage(
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 96f8324..1005bd7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2850,11 +2850,13 @@
enforceConnectivityInternalPermission();
if (TextUtils.isEmpty(iface)) return ConnectivityManager.TYPE_NONE;
- for (NetworkStateTracker tracker : mNetTrackers) {
- if (tracker != null) {
- LinkProperties lp = tracker.getLinkProperties();
- if (lp != null && iface.equals(lp.getInterfaceName())) {
- return tracker.getNetworkInfo().getType();
+
+ synchronized(mNetworkForNetId) {
+ for (int i = 0; i < mNetworkForNetId.size(); i++) {
+ NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
+ LinkProperties lp = nai.linkProperties;
+ if (lp != null && iface.equals(lp.getInterfaceName()) && nai.networkInfo != null) {
+ return nai.networkInfo.getType();
}
}
}
@@ -4759,7 +4761,9 @@
result.setType(networkType);
return result;
} else {
- return new NetworkInfo(networkType, 0, "Unknown", "");
+ NetworkInfo result = new NetworkInfo(networkType);
+ result.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
+ return result;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b1d84f58..f36f25f 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -40,6 +40,9 @@
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.BatteryStats;
import android.os.PersistableBundle;
@@ -261,6 +264,7 @@
static final boolean DEBUG_VISBILITY = localLOGV || false;
static final boolean DEBUG_PSS = localLOGV || false;
static final boolean DEBUG_LOCKSCREEN = localLOGV || false;
+ static final boolean DEBUG_RECENTS = localLOGV || false;
static final boolean VALIDATE_TOKENS = false;
static final boolean SHOW_ACTIVITY_START_TIME = true;
@@ -410,6 +414,21 @@
ArrayList<TaskRecord> mRecentTasks;
ArraySet<TaskRecord> mTmpRecents = new ArraySet<TaskRecord>();
+ /**
+ * For addAppTask: cached of the last activity component that was added.
+ */
+ ComponentName mLastAddedTaskComponent;
+
+ /**
+ * For addAppTask: cached of the last activity uid that was added.
+ */
+ int mLastAddedTaskUid;
+
+ /**
+ * For addAppTask: cached of the last ActivityInfo that was added.
+ */
+ ActivityInfo mLastAddedTaskActivity;
+
public class PendingAssistExtras extends Binder implements Runnable {
public final ActivityRecord activity;
public boolean haveResult = false;
@@ -1181,6 +1200,9 @@
/** Flag whether the device has a recents UI */
final boolean mHasRecents;
+ final int mThumbnailWidth;
+ final int mThumbnailHeight;
+
final ServiceThread mHandlerThread;
final MainHandler mHandler;
@@ -1819,6 +1841,7 @@
BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
Integer.toString(msg.arg1), msg.arg1);
mSystemServiceManager.switchUser(msg.arg1);
+ mLockToAppRequest.clearPrompt();
break;
}
case ENTER_ANIMATION_COMPLETE_MSG: {
@@ -2229,8 +2252,10 @@
mConfigurationSeq = mConfiguration.seq = 1;
mProcessCpuTracker.init();
- mHasRecents = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_hasRecents);
+ final Resources res = mContext.getResources();
+ mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
+ mThumbnailWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+ mThumbnailHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
@@ -3481,7 +3506,8 @@
try {
int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, null, null, options, UserHandle.getUserId(targetUid), null);
+ null, null, null, null, options, UserHandle.getUserId(sourceRecord.app.uid),
+ null);
return ret;
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
@@ -3781,7 +3807,7 @@
}
final void addRecentTaskLocked(TaskRecord task) {
- int N = mRecentTasks.size();
+ final int N = mRecentTasks.size();
// Quick case: check if the top-most recent task is the same.
if (N > 0 && mRecentTasks.get(0) == task) {
return;
@@ -3790,10 +3816,25 @@
if (task.voiceSession != null) {
return;
}
- // Remove any existing entries that are the same kind of task.
+
+ trimRecentsForTask(task, true);
+
+ if (N >= MAX_RECENT_TASKS) {
+ final TaskRecord tr = mRecentTasks.remove(N - 1);
+ tr.disposeThumbnail();
+ tr.closeRecentsChain();
+ }
+ mRecentTasks.add(0, task);
+ }
+
+ /**
+ * If needed, remove oldest existing entries in recents that are for the same kind
+ * of task as the given one.
+ */
+ int trimRecentsForTask(TaskRecord task, boolean doTrim) {
+ int N = mRecentTasks.size();
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
- final ComponentName comp = intent.getComponent();
int maxRecents = task.maxRecents - 1;
for (int i=0; i<N; i++) {
@@ -3825,6 +3866,12 @@
}
}
+ if (!doTrim) {
+ // If the caller is not actually asking for a trim, just tell them we reached
+ // a point where the trim would happen.
+ return i;
+ }
+
// Either task and tr are the same or, their affinities match or their intents match
// and neither of them is a document, or they are documents using the same activity
// and their maxRecents has been reached.
@@ -3842,12 +3889,8 @@
}
notifyTaskPersisterLocked(tr, false);
}
- if (N >= MAX_RECENT_TASKS) {
- final TaskRecord tr = mRecentTasks.remove(N - 1);
- tr.disposeThumbnail();
- tr.closeRecentsChain();
- }
- mRecentTasks.add(0, task);
+
+ return -1;
}
@Override
@@ -7639,7 +7682,10 @@
for (int i=0; i<N && maxNum > 0; i++) {
TaskRecord tr = mRecentTasks.get(i);
// Only add calling user or related users recent tasks
- if (!includedUsers.contains(Integer.valueOf(tr.userId))) continue;
+ if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
+ if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not user: " + tr);
+ continue;
+ }
// Return the entry if desired by the caller. We always return
// the first entry, because callers always expect this to be the
@@ -7656,11 +7702,14 @@
// If the caller doesn't have the GET_TASKS permission, then only
// allow them to see a small subset of tasks -- their own and home.
if (!tr.isHomeTask() && tr.creatorUid != callingUid) {
+ if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not allowed: " + tr);
continue;
}
}
if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
// Don't include auto remove tasks that are finished or finishing.
+ if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, auto-remove without activity: "
+ + tr);
continue;
}
@@ -7675,11 +7724,15 @@
if (rti.origActivity != null) {
if (pm.getActivityInfo(rti.origActivity, 0, userId)
== null) {
+ if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail orig act: "
+ + tr);
continue;
}
} else if (rti.baseIntent != null) {
if (pm.queryIntentActivities(rti.baseIntent,
null, 0, userId) == null) {
+ if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail intent: "
+ + tr);
continue;
}
}
@@ -7721,6 +7774,97 @@
}
@Override
+ public int addAppTask(IBinder activityToken, Intent intent,
+ ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException {
+ final int callingUid = Binder.getCallingUid();
+ final long callingIdent = Binder.clearCallingIdentity();
+
+ try {
+ synchronized (this) {
+ ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+ if (r == null) {
+ throw new IllegalArgumentException("Activity does not exist; token="
+ + activityToken);
+ }
+ ComponentName comp = intent.getComponent();
+ if (comp == null) {
+ throw new IllegalArgumentException("Intent " + intent
+ + " must specify explicit component");
+ }
+ if (thumbnail.getWidth() != mThumbnailWidth
+ || thumbnail.getHeight() != mThumbnailHeight) {
+ throw new IllegalArgumentException("Bad thumbnail size: got "
+ + thumbnail.getWidth() + "x" + thumbnail.getHeight() + ", require "
+ + mThumbnailWidth + "x" + mThumbnailHeight);
+ }
+ if (intent.getSelector() != null) {
+ intent.setSelector(null);
+ }
+ if (intent.getSourceBounds() != null) {
+ intent.setSourceBounds(null);
+ }
+ if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) {
+ if ((intent.getFlags()&Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) == 0) {
+ // The caller has added this as an auto-remove task... that makes no
+ // sense, so turn off auto-remove.
+ intent.addFlags(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
+ }
+ } else if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ // Must be a new task.
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+ if (!comp.equals(mLastAddedTaskComponent) || callingUid != mLastAddedTaskUid) {
+ mLastAddedTaskActivity = null;
+ }
+ ActivityInfo ainfo = mLastAddedTaskActivity;
+ if (ainfo == null) {
+ ainfo = mLastAddedTaskActivity = AppGlobals.getPackageManager().getActivityInfo(
+ comp, 0, UserHandle.getUserId(callingUid));
+ if (ainfo.applicationInfo.uid != callingUid) {
+ throw new SecurityException(
+ "Can't add task for another application: target uid="
+ + ainfo.applicationInfo.uid + ", calling uid=" + callingUid);
+ }
+ }
+
+ TaskRecord task = new TaskRecord(this, mStackSupervisor.getNextTaskId(), ainfo,
+ intent, description);
+
+ int trimIdx = trimRecentsForTask(task, false);
+ if (trimIdx >= 0) {
+ // If this would have caused a trim, then we'll abort because that
+ // means it would be added at the end of the list but then just removed.
+ return -1;
+ }
+
+ final int N = mRecentTasks.size();
+ if (N >= (MAX_RECENT_TASKS-1)) {
+ final TaskRecord tr = mRecentTasks.remove(N - 1);
+ tr.disposeThumbnail();
+ tr.closeRecentsChain();
+ }
+
+ mRecentTasks.add(task);
+ r.task.stack.addTask(task, false, false);
+
+ task.setLastThumbnail(thumbnail);
+ task.freeLastThumbnail();
+
+ return task.taskId;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdent);
+ }
+ }
+
+ @Override
+ public Point getAppTaskThumbnailSize() {
+ synchronized (this) {
+ return new Point(mThumbnailWidth, mThumbnailHeight);
+ }
+ }
+
+ @Override
public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) {
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
@@ -18056,14 +18200,16 @@
mCallingUid = callingUid;
}
+ private void checkCaller() {
+ if (mCallingUid != Binder.getCallingUid()) {
+ throw new SecurityException("Caller " + mCallingUid
+ + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
+ }
+ }
+
@Override
public void finishAndRemoveTask() {
- // Ensure that we are called from the same process that created this AppTask
- if (mCallingUid != Binder.getCallingUid()) {
- Slog.w(TAG, "finishAndRemoveTask: caller " + mCallingUid
- + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
- return;
- }
+ checkCaller();
synchronized (ActivityManagerService.this) {
long origId = Binder.clearCallingIdentity();
@@ -18085,12 +18231,7 @@
@Override
public ActivityManager.RecentTaskInfo getTaskInfo() {
- // Ensure that we are called from the same process that created this AppTask
- if (mCallingUid != Binder.getCallingUid()) {
- Slog.w(TAG, "finishAndRemoveTask: caller " + mCallingUid
- + " does not match caller of getAppTasks(): " + Binder.getCallingUid());
- return null;
- }
+ checkCaller();
synchronized (ActivityManagerService.this) {
long origId = Binder.clearCallingIdentity();
@@ -18105,5 +18246,28 @@
return null;
}
}
+
+ @Override
+ public void setExcludeFromRecents(boolean exclude) {
+ checkCaller();
+
+ synchronized (ActivityManagerService.this) {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ TaskRecord tr = recentTaskForIdLocked(mTaskId);
+ if (tr != null) {
+ Intent intent = tr.getBaseIntent();
+ if (exclude) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ } else {
+ intent.setFlags(intent.getFlags()
+ & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index abacb2d..24b7cb3 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1054,8 +1054,8 @@
return null;
}
- private static String createImageFilename(ActivityRecord r, int taskId) {
- return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + r.createTime +
+ private static String createImageFilename(long createTime, int taskId) {
+ return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + createTime +
TaskPersister.IMAGE_EXTENSION;
}
@@ -1072,7 +1072,7 @@
out.attribute(null, ATTR_USERID, String.valueOf(userId));
if (taskDescription != null) {
- task.saveTaskDescription(taskDescription, createImageFilename(this, task.taskId),
+ task.saveTaskDescription(taskDescription, createImageFilename(createTime, task.taskId),
out);
}
@@ -1165,7 +1165,8 @@
r.persistentState = persistentState;
if (createTime >= 0) {
- taskDescription.setIcon(TaskPersister.restoreImage(createImageFilename(r, taskId)));
+ taskDescription.setIcon(TaskPersister.restoreImage(createImageFilename(createTime,
+ taskId)));
}
r.taskDescription = taskDescription;
r.createTime = createTime;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e309a03..5ad84d4 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -355,8 +355,8 @@
mCurrentUser = mService.mCurrentUserId;
// Get the activity screenshot thumbnail dimensions
Resources res = mService.mContext.getResources();
- mThumbnailWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
- mThumbnailHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
+ mThumbnailWidth = mService.mThumbnailWidth;
+ mThumbnailHeight = mService.mThumbnailHeight;
}
/**
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 0ba62c5..098b0b6 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -94,6 +94,9 @@
}
mResult.set(msg.what);
+ // Make sure we don't have time timeout still hanging around.
+ removeMessages(FORCE_QUIT);
+
// If this is a timeout we won't be automatically closed, so go
// ahead and explicitly dismiss ourselves just in case.
dismiss();
diff --git a/services/core/java/com/android/server/am/LockToAppRequestDialog.java b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
index 5abf699..a1eb31e 100644
--- a/services/core/java/com/android/server/am/LockToAppRequestDialog.java
+++ b/services/core/java/com/android/server/am/LockToAppRequestDialog.java
@@ -74,11 +74,15 @@
return 0;
}
- public void showLockTaskPrompt(TaskRecord task) {
+ public void clearPrompt() {
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
}
+ }
+
+ public void showLockTaskPrompt(TaskRecord task) {
+ clearPrompt();
mRequestedTask = task;
final int unlockStringId = getLockString(task.userId);
@@ -97,6 +101,8 @@
mDialog = builder.create();
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ mDialog.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mDialog.show();
if (unlockStringId != 0) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index ccca657..2a8c6fb 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -167,6 +167,34 @@
setIntent(_intent, info);
}
+ TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
+ ActivityManager.TaskDescription _taskDescription) {
+ mService = service;
+ mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
+ TaskPersister.IMAGE_EXTENSION;
+ mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename);
+ taskId = _taskId;
+ mAffiliatedTaskId = _taskId;
+ voiceSession = null;
+ voiceInteractor = null;
+ mActivities = new ArrayList<ActivityRecord>();
+ setIntent(_intent, info);
+
+ taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+ isPersistable = true;
+ mCallingUid = info.applicationInfo.uid;
+ mCallingPackage = info.packageName;
+ // Clamp to [1, 100].
+ maxRecents = Math.min(Math.max(info.maxRecents, 1), 100);
+
+ taskType = APPLICATION_ACTIVITY_TYPE;
+ mTaskToReturnTo = HOME_ACTIVITY_TYPE;
+ userId = UserHandle.getUserId(info.applicationInfo.uid);
+ lastTaskDescription = _taskDescription;
+ mCallingUid = info.applicationInfo.uid;
+ mCallingPackage = info.packageName;
+ }
+
TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
String _affinity, ComponentName _realActivity, ComponentName _origActivity,
boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode,
@@ -764,8 +792,13 @@
return true;
}
+ private static String createLastTaskDescriptionIconFilename(int taskId, long lastActiveTime) {
+ return String.valueOf(taskId) + LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime +
+ TaskPersister.IMAGE_EXTENSION;
+ }
+
void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
- Slog.i(TAG, "Saving task=" + this);
+ if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this);
out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
if (realActivity != null) {
@@ -790,8 +823,8 @@
out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
}
if (lastTaskDescription != null) {
- saveTaskDescription(lastTaskDescription, String.valueOf(taskId) +
- LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime, out);
+ saveTaskDescription(lastTaskDescription, createLastTaskDescriptionIconFilename(taskId,
+ lastActiveTime), out);
}
out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
@@ -933,8 +966,8 @@
}
if (lastActiveTime >= 0) {
- taskDescription.setIcon(TaskPersister.restoreImage(String.valueOf(taskId) +
- LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime + TaskPersister.IMAGE_EXTENSION));
+ taskDescription.setIcon(TaskPersister.restoreImage(
+ createLastTaskDescriptionIconFilename(taskId, lastActiveTime)));
}
final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
@@ -948,18 +981,15 @@
activities.get(activityNdx).task = task;
}
- Slog.i(TAG, "Restored task=" + task);
+ if (ActivityManagerService.DEBUG_RECENTS) Slog.d(TAG, "Restored task=" + task);
return task;
}
void dump(PrintWriter pw, String prefix) {
- if (rootWasReset || userId != 0 || numFullscreen != 0) {
- pw.print(prefix); pw.print(" rootWasReset="); pw.print(rootWasReset);
- pw.print(" userId="); pw.print(userId);
- pw.print(" taskType="); pw.print(taskType);
- pw.print(" numFullscreen="); pw.print(numFullscreen);
- pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
- }
+ pw.print(prefix); pw.print("userId="); pw.print(userId);
+ pw.print(" creatorUid="); pw.print(creatorUid);
+ pw.print(" mCallingUid="); pw.print(mCallingUid);
+ pw.print(" mCallingPackage="); pw.println(mCallingPackage);
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);
}
@@ -991,6 +1021,17 @@
pw.print(prefix); pw.print("realActivity=");
pw.println(realActivity.flattenToShortString());
}
+ if (autoRemoveRecents || taskType != 0 || mTaskToReturnTo != 0 || numFullscreen != 0) {
+ pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
+ pw.print(" numFullscreen="); pw.print(numFullscreen);
+ pw.print(" taskType="); pw.print(taskType);
+ pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
+ }
+ if (rootWasReset || mNeverRelinquishIdentity || mReuseTask) {
+ pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
+ pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
+ pw.print(" mReuseTask="); pw.println(mReuseTask);
+ }
pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
if (!askedCompatMode) {
pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index b09298c..ddd0865 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -769,6 +769,7 @@
latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
}
- mContext.sendBroadcast(latencyBroadcast, PERMISSION_ACCESS_NETWORK_CONDITIONS);
+ mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
+ PERMISSION_ACCESS_NETWORK_CONDITIONS);
}
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 14457ec..6771cce 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -162,6 +162,7 @@
JobStatus jobStatus = new JobStatus(job, uId);
cancelJob(uId, job.getId());
startTrackingJob(jobStatus);
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
return JobScheduler.RESULT_SUCCESS;
}
@@ -507,7 +508,9 @@
case MSG_JOB_EXPIRED:
synchronized (mJobs) {
JobStatus runNow = (JobStatus) message.obj;
- if (!mPendingJobs.contains(runNow)) {
+ // runNow can be null, which is a controller's way of indicating that its
+ // state is such that all ready jobs should be run immediately.
+ if (runNow != null && !mPendingJobs.contains(runNow)) {
mPendingJobs.add(runNow);
}
}
diff --git a/services/core/java/com/android/server/job/StateChangedListener.java b/services/core/java/com/android/server/job/StateChangedListener.java
index 90c203a..97dfad3 100644
--- a/services/core/java/com/android/server/job/StateChangedListener.java
+++ b/services/core/java/com/android/server/job/StateChangedListener.java
@@ -33,7 +33,8 @@
/**
* Called by the controller to notify the JobManager that regardless of the state of the task,
* it must be run immediately.
- * @param jobStatus The state of the task which is to be run immediately.
+ * @param jobStatus The state of the task which is to be run immediately. <strong>null
+ * indicates to the scheduler that any ready jobs should be flushed.</strong>
*/
public void onRunJobNow(JobStatus jobStatus);
}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 538a252..309e034 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -84,15 +84,15 @@
@Override
public void maybeStartTrackingJob(JobStatus taskStatus) {
+ final boolean isOnStablePower = mChargeTracker.isOnStablePower();
if (taskStatus.hasChargingConstraint()) {
- final boolean isOnStablePower = mChargeTracker.isOnStablePower();
synchronized (mTrackedTasks) {
mTrackedTasks.add(taskStatus);
taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
}
- if (isOnStablePower) {
- mStateChangedListener.onControllerStateChanged();
- }
+ }
+ if (isOnStablePower) {
+ mChargeTracker.setStableChargingAlarm();
}
}
@@ -119,9 +119,15 @@
}
}
}
+ // Let the scheduler know that state has changed. This may or may not result in an
+ // execution.
if (reportChange) {
mStateChangedListener.onControllerStateChanged();
}
+ // Also tell the scheduler that any ready jobs should be flushed.
+ if (stablePower) {
+ mStateChangedListener.onRunJobNow(null);
+ }
}
public class ChargingTracker extends BroadcastReceiver {
@@ -196,9 +202,7 @@
}
// Set up an alarm for ACTION_CHARGING_STABLE - we don't want to kick off tasks
// here if the user unplugs the phone immediately.
- mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + STABLE_CHARGING_THRESHOLD_MILLIS,
- mStableChargingTriggerIntent);
+ setStableChargingAlarm();
mCharging = true;
} else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
if (DEBUG) {
@@ -211,7 +215,7 @@
}else if (ACTION_CHARGING_STABLE.equals(action)) {
// Here's where we actually do the notify for a task being ready.
if (DEBUG) {
- Slog.d(TAG, "Battery connected fired @ " + SystemClock.elapsedRealtime()
+ Slog.d(TAG, "Stable charging fired @ " + SystemClock.elapsedRealtime()
+ " charging: " + mCharging);
}
if (mCharging) { // Should never receive this intent if mCharging is false.
@@ -219,6 +223,17 @@
}
}
}
+
+ void setStableChargingAlarm() {
+ final long alarmTriggerElapsed =
+ SystemClock.elapsedRealtime() + STABLE_CHARGING_THRESHOLD_MILLIS;
+ if (DEBUG) {
+ Slog.d(TAG, "Setting stable alarm to go off in " +
+ (STABLE_CHARGING_THRESHOLD_MILLIS / 1000) + "s");
+ }
+ mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTriggerElapsed,
+ mStableChargingTriggerIntent);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 03cb2e9..5e802de 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -485,17 +485,22 @@
if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Brand new install, use best resolved location. This also verifies
// that target has enough free space for the install.
- final int resolved = PackageHelper.resolveInstallLocation(mContext,
- params.appPackageName, params.installLocation, params.sizeBytes,
- params.installFlags);
- if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
- stageInternal = true;
- } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
- stageInternal = false;
- } else {
- throw new IOException("No storage with enough free space; res=" + resolved);
- }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final int resolved = PackageHelper.resolveInstallLocation(mContext,
+ params.appPackageName, params.installLocation, params.sizeBytes,
+ params.installFlags);
+ if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
+ stageInternal = true;
+ } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
+ stageInternal = false;
+ } else {
+ throw new IOException("No storage with enough free space; res=" + resolved);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
} else if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
// We always stage inheriting sessions on internal storage first,
// since we don't want to grow containers until we're sure that
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b57a090..32f3707 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5801,6 +5801,29 @@
SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
}
+ private static void convertCropForSurfaceFlinger(Rect crop, int rot, int dw, int dh) {
+ if (rot == Surface.ROTATION_90) {
+ final int tmp = crop.top;
+ crop.top = dw - crop.right;
+ crop.right = crop.bottom;
+ crop.bottom = dw - crop.left;
+ crop.left = tmp;
+ } else if (rot == Surface.ROTATION_180) {
+ int tmp = crop.top;
+ crop.top = dh - crop.bottom;
+ crop.bottom = dh - tmp;
+ tmp = crop.right;
+ crop.right = dw - crop.left;
+ crop.left = dw - tmp;
+ } else if (rot == Surface.ROTATION_270) {
+ final int tmp = crop.top;
+ crop.top = crop.left;
+ crop.left = dh - crop.bottom;
+ crop.bottom = crop.right;
+ crop.right = dh - tmp;
+ }
+ }
+
/**
* Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
* In portrait mode, it grabs the upper region of the screen based on the vertical dimension
@@ -5962,21 +5985,31 @@
// Constrain frame to the screen size.
frame.intersect(0, 0, dw, dh);
- // Constrain thumbnail to smaller of screen width or height. Assumes aspect
- // of thumbnail is the same as the screen (in landscape) or square.
- scale = Math.max(width / (float) frame.width(), height / (float) frame.height());
- dw = (int)(dw * scale);
- dh = (int)(dh * scale);
+
+ // Tell surface flinger what part of the image to crop. Take the top
+ // right part of the application, and crop the larger dimension to fit.
+ Rect crop = new Rect(frame);
+ if (width / (float) frame.width() < height / (float) frame.height()) {
+ int cropWidth = (int)((float)width / (float)height * frame.height());
+ crop.right = crop.left + cropWidth;
+ } else {
+ int cropHeight = (int)((float)height / (float)width * frame.width());
+ crop.bottom = crop.top + cropHeight;
+ }
// The screenshot API does not apply the current screen rotation.
rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
- final int tmp = dw;
- dw = dh;
- dh = tmp;
+ final int tmp = width;
+ width = height;
+ height = tmp;
rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
}
+ // Surfaceflinger is not aware of orientation, so convert our logical
+ // crop to surfaceflinger's portrait orientation.
+ convertCropForSurfaceFlinger(crop, rot, dw, dh);
+
if (DEBUG_SCREENSHOT) {
Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
+ maxLayer + " appToken=" + appToken);
@@ -5995,7 +6028,7 @@
if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG,
"Taking screenshot while rotating");
- rawss = SurfaceControl.screenshot(new Rect(), dw, dh, minLayer, maxLayer,
+ rawss = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
inRotation);
if (rawss == null) {
Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
@@ -6012,11 +6045,8 @@
if (DEBUG_SCREENSHOT) {
bm.eraseColor(0xFF000000);
}
- frame.scale(scale);
Matrix matrix = new Matrix();
- ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
- // TODO: Test for RTL vs. LTR and use frame.right-width instead of -frame.left
- matrix.postTranslate(-FloatMath.ceil(frame.left), -FloatMath.ceil(frame.top));
+ ScreenRotationAnimation.createRotationMatrix(rot, width, height, matrix);
Canvas canvas = new Canvas(bm);
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
@@ -6042,6 +6072,7 @@
}
rawss.recycle();
+
return bm;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 4b60c9f..5938819 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -267,6 +267,9 @@
if (mDeviceOwner != null) {
out.startTag(null, TAG_DEVICE_OWNER);
out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
+ if (mDeviceOwner.name != null) {
+ out.attribute(null, ATTR_NAME, mDeviceOwner.name);
+ }
out.endTag(null, TAG_DEVICE_OWNER);
}
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
index 34b9dae..44accb7 100644
--- a/telecomm/java/android/telecomm/Conference.java
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -163,6 +163,7 @@
* @return True if the connection was successfully removed.
*/
public void removeConnection(Connection connection) {
+ Log.d(this, "removing %s from %s", connection, mChildConnections);
if (connection != null && mChildConnections.remove(connection)) {
connection.resetConference();
for (Listener l : mListeners) {
@@ -177,7 +178,7 @@
public void destroy() {
Log.d(this, "destroying conference : %s", this);
// Tear down the children.
- for (Connection connection : new ArrayList<>(mChildConnections)) {
+ for (Connection connection : mChildConnections) {
Log.d(this, "removing connection %s", connection);
removeConnection(connection);
}
diff --git a/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
index c307a25..3aa4baf 100644
--- a/telecomm/java/android/telecomm/Connection.java
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -914,10 +914,11 @@
*/
public final boolean setConference(Conference conference) {
// We check to see if it is already part of another conference.
- if (mConference == null && mConnectionService != null &&
- mConnectionService.containsConference(conference)) {
+ if (mConference == null) {
mConference = conference;
- fireConferenceChanged();
+ if (mConnectionService != null && mConnectionService.containsConference(conference)) {
+ fireConferenceChanged();
+ }
return true;
}
return false;
@@ -929,6 +930,7 @@
*/
public final void resetConference() {
if (mConference != null) {
+ Log.d(this, "Conference reset");
mConference = null;
fireConferenceChanged();
}
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index c805978..b77bb18 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -84,6 +84,7 @@
private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter();
private boolean mAreAccountsInitialized = false;
+ private Conference sNullConference;
private final IBinder mBinder = new IConnectionService.Stub() {
@Override
@@ -561,17 +562,29 @@
private void disconnect(String callId) {
Log.d(this, "disconnect %s", callId);
- findConnectionForAction(callId, "disconnect").onDisconnect();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "disconnect").onDisconnect();
+ } else {
+ findConferenceForAction(callId, "disconnect").onDisconnect();
+ }
}
private void hold(String callId) {
Log.d(this, "hold %s", callId);
- findConnectionForAction(callId, "hold").onHold();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "hold").onHold();
+ } else {
+ findConferenceForAction(callId, "hold").onHold();
+ }
}
private void unhold(String callId) {
Log.d(this, "unhold %s", callId);
- findConnectionForAction(callId, "unhold").onUnhold();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "unhold").onUnhold();
+ } else {
+ findConferenceForAction(callId, "unhold").onUnhold();
+ }
}
private void onAudioStateChanged(String callId, AudioState audioState) {
@@ -616,7 +629,10 @@
return;
}
- // TODO: Find existing conference call and invoke split(connection).
+ Conference conference = connection.getConference();
+ if (conference != null) {
+ conference.onSeparate(connection);
+ }
}
private void onPostDialContinue(String callId, boolean proceed) {
@@ -885,4 +901,19 @@
}
return sNullConnection;
}
+
+ private Conference findConferenceForAction(String conferenceId, String action) {
+ if (mConferenceById.containsKey(conferenceId)) {
+ return mConferenceById.get(conferenceId);
+ }
+ Log.w(this, "%s - Cannot find conference %s", action, conferenceId);
+ return getNullConference();
+ }
+
+ private Conference getNullConference() {
+ if (sNullConference == null) {
+ sNullConference = new Conference(null) {};
+ }
+ return sNullConference;
+ }
}
diff --git a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
index 41c6360..cb63646 100644
--- a/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecomm/ConnectionServiceAdapter.java
@@ -197,6 +197,7 @@
void setIsConferenced(String callId, String conferenceCallId) {
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
+ Log.d(this, "sending connection %s with conference %s", callId, conferenceCallId);
adapter.setIsConferenced(callId, conferenceCallId);
} catch (RemoteException ignored) {
}
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index dcd0b79..767ecf9 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -21,6 +21,8 @@
import android.os.Parcelable;
import android.telecomm.VideoProfile;
+import com.android.internal.telephony.PhoneConstants;
+
/**
* Parcelable object to handle IMS call profile.
* It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111.
@@ -337,6 +339,38 @@
}
/**
+ * Translate presentation value to OIR value
+ * @param presentation
+ * @return OIR valuse
+ */
+ public static int presentationToOIR(int presentation) {
+ switch (presentation) {
+ case PhoneConstants.PRESENTATION_RESTRICTED:
+ return ImsCallProfile.OIR_PRESENTATION_RESTRICTED;
+ case PhoneConstants.PRESENTATION_ALLOWED:
+ return ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED;
+ default:
+ return ImsCallProfile.OIR_DEFAULT;
+ }
+ }
+
+ /**
+ * Translate OIR value to presentation value
+ * @param oir value
+ * @return presentation value
+ */
+ public static int OIRToPresentation(int oir) {
+ switch(oir) {
+ case ImsCallProfile.OIR_PRESENTATION_RESTRICTED:
+ return PhoneConstants.PRESENTATION_RESTRICTED;
+ case ImsCallProfile.OIR_PRESENTATION_NOT_RESTRICTED:
+ return PhoneConstants.PRESENTATION_ALLOWED;
+ default:
+ return PhoneConstants.PRESENTATION_UNKNOWN;
+ }
+ }
+
+ /**
* Determines if a video state is set in a video state bit-mask.
*
* @param videoState The video state bit mask.
diff --git a/tests/ActivityTests/res/drawable-hdpi/icon.png b/tests/ActivityTests/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..2eab6f2
--- /dev/null
+++ b/tests/ActivityTests/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/tests/ActivityTests/res/drawable-mdpi/icon.png b/tests/ActivityTests/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..63aec6f
--- /dev/null
+++ b/tests/ActivityTests/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/tests/ActivityTests/res/drawable-xhdpi/icon.png b/tests/ActivityTests/res/drawable-xhdpi/icon.png
new file mode 100644
index 0000000..8ea9c48
--- /dev/null
+++ b/tests/ActivityTests/res/drawable-xhdpi/icon.png
Binary files differ
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 9002125..7f3aa77 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -28,6 +28,7 @@
import android.content.ContentProviderClient;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -219,7 +220,7 @@
@Override public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(ActivityTestMain.this, UserTarget.class);
sendOrderedBroadcastAsUser(intent, new UserHandle(mSecondUser), null,
- new BroadcastResultReceiver(),
+ new BroadcastResultReceiver(),
null, Activity.RESULT_OK, null, null);
return true;
}
@@ -291,6 +292,30 @@
return true;
}
});
+ menu.add("Add App Recent").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ addAppRecents(1);
+ return true;
+ }
+ });
+ menu.add("Add App 10x Recent").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ addAppRecents(10);
+ return true;
+ }
+ });
+ menu.add("Exclude!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ setExclude(true);
+ return true;
+ }
+ });
+ menu.add("Include!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ setExclude(false);
+ return true;
+ }
+ });
return true;
}
@@ -317,7 +342,36 @@
mConnections.clear();
}
- private View scrollWrap(View view) {
+ void addAppRecents(int count) {
+ ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ intent.setComponent(new ComponentName(this, ActivityTestMain.class));
+ for (int i=0; i<count; i++) {
+ ActivityManager.TaskDescription desc = new ActivityManager.TaskDescription();
+ desc.setLabel("Added #" + i);
+ Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
+ if ((i&1) == 0) {
+ desc.setIcon(bitmap);
+ }
+ int taskId = am.addAppTask(this, intent, desc, bitmap);
+ Log.i(TAG, "Added new task id #" + taskId);
+ }
+ }
+
+ void setExclude(boolean exclude) {
+ ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
+ List<ActivityManager.AppTask> tasks = am.getAppTasks();
+ int taskId = getTaskId();
+ for (int i=0; i<tasks.size(); i++) {
+ ActivityManager.AppTask task = tasks.get(i);
+ if (task.getTaskInfo().id == taskId) {
+ task.setExcludeFromRecents(exclude);
+ }
+ }
+ }
+ private View scrollWrap(View view) {
ScrollView scroller = new ScrollView(this);
scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
ScrollView.LayoutParams.MATCH_PARENT));
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
index 08d7667..d402699 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
@@ -54,7 +54,7 @@
for (int i = 0; i < rowIndices.length; i++)
rowIndices[i] = i * REGION_SIZE;
- mScript = new ScriptC_errorCalculator(mRS, resources, R.raw.errorcalculator);
+ mScript = new ScriptC_errorCalculator(mRS);
mScript.set_HEIGHT(height);
mScript.set_WIDTH(width);
mScript.set_REGION_SIZE(REGION_SIZE);
diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk
index 4535eb1..c0f3323 100644
--- a/tests/RenderScriptTests/FountainFbo/Android.mk
+++ b/tests/RenderScriptTests/FountainFbo/Android.mk
@@ -25,5 +25,6 @@
# LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := RsFountainFbo
+LOCAL_SDK_VERSION := 14
include $(BUILD_PACKAGE)
diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk
index 7884d4d..b068bef 100644
--- a/tests/Split/Android.mk
+++ b/tests/Split/Android.mk
@@ -20,8 +20,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := Split
-LOCAL_AAPT_FLAGS := --split fr,de
-LOCAL_AAPT_FLAGS += -v
+LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4
LOCAL_MODULE_TAGS := tests
diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml
index a4956a7..0de8344 100644
--- a/tests/Split/AndroidManifest.xml
+++ b/tests/Split/AndroidManifest.xml
@@ -16,7 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.example.split">
- <application android:label="@string/app_title">
+ <application android:label="@string/app_title"
+ android:icon="@mipmap/ic_app">
<activity android:name="ActivityMain">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/tests/Split/res/drawable-hdpi/image.png b/tests/Split/res/drawable-hdpi/image.png
new file mode 100644
index 0000000..dcf4242
--- /dev/null
+++ b/tests/Split/res/drawable-hdpi/image.png
Binary files differ
diff --git a/tests/Split/res/drawable-mdpi/image.png b/tests/Split/res/drawable-mdpi/image.png
new file mode 100644
index 0000000..3437952
--- /dev/null
+++ b/tests/Split/res/drawable-mdpi/image.png
Binary files differ
diff --git a/tests/Split/res/drawable-xhdpi/image.png b/tests/Split/res/drawable-xhdpi/image.png
new file mode 100644
index 0000000..68b2f8e
--- /dev/null
+++ b/tests/Split/res/drawable-xhdpi/image.png
Binary files differ
diff --git a/tests/Split/res/drawable-xxhdpi/image.png b/tests/Split/res/drawable-xxhdpi/image.png
new file mode 100644
index 0000000..4bff9b9
--- /dev/null
+++ b/tests/Split/res/drawable-xxhdpi/image.png
Binary files differ
diff --git a/tests/Split/res/layout/main.xml b/tests/Split/res/layout/main.xml
index 36992a2..607cdb0 100644
--- a/tests/Split/res/layout/main.xml
+++ b/tests/Split/res/layout/main.xml
@@ -14,6 +14,12 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent">
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:src="@drawable/image"/>
+</RelativeLayout>
diff --git a/tests/Split/res/mipmap-hdpi/ic_app.png b/tests/Split/res/mipmap-hdpi/ic_app.png
new file mode 100644
index 0000000..ffcb9e5
--- /dev/null
+++ b/tests/Split/res/mipmap-hdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-mdpi/ic_app.png b/tests/Split/res/mipmap-mdpi/ic_app.png
new file mode 100644
index 0000000..35f5b45
--- /dev/null
+++ b/tests/Split/res/mipmap-mdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-xhdpi/ic_app.png b/tests/Split/res/mipmap-xhdpi/ic_app.png
new file mode 100644
index 0000000..bfe71fe
--- /dev/null
+++ b/tests/Split/res/mipmap-xhdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-xxhdpi/ic_app.png b/tests/Split/res/mipmap-xxhdpi/ic_app.png
new file mode 100644
index 0000000..b65532c
--- /dev/null
+++ b/tests/Split/res/mipmap-xxhdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/res/mipmap-xxxhdpi/ic_app.png b/tests/Split/res/mipmap-xxxhdpi/ic_app.png
new file mode 100644
index 0000000..2679b49
--- /dev/null
+++ b/tests/Split/res/mipmap-xxxhdpi/ic_app.png
Binary files differ
diff --git a/tests/Split/src/java/com/android/example/split/ActivityMain.java b/tests/Split/src/java/com/android/example/split/ActivityMain.java
index a15fb3c..63963a2 100644
--- a/tests/Split/src/java/com/android/example/split/ActivityMain.java
+++ b/tests/Split/src/java/com/android/example/split/ActivityMain.java
@@ -24,8 +24,6 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- TextView text = new TextView(this);
- text.setText(R.string.test);
- setContentView(text);
+ setContentView(R.layout.main);
}
}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index eead68c..b44e2d1 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -561,15 +561,17 @@
return NO_ERROR;
}
-#if 0
- printf("Error adding file %s: group %s already exists in leaf=%s path=%s\n",
- file->getSourceFile().string(),
- file->getGroupEntry().toDirName(String8()).string(),
- mLeaf.string(), mPath.string());
-#endif
+ // Check if the version is automatically applied. This is a common source of
+ // error.
+ ConfigDescription withoutVersion = file->getGroupEntry().toParams();
+ withoutVersion.version = 0;
+ AaptConfig::applyVersionForCompatibility(&withoutVersion);
- SourcePos(file->getSourceFile(), -1).error("Duplicate file.\n%s: Original is here.",
- getPrintableSource().string());
+ const sp<AaptFile>& originalFile = mFiles.valueAt(index);
+ SourcePos(file->getSourceFile(), -1)
+ .error("Duplicate file.\n%s: Original is here. %s",
+ originalFile->getPrintableSource().string(),
+ (withoutVersion.version != 0) ? "The version qualifier may be implied." : "");
return UNKNOWN_ERROR;
}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 0a80805..1d93b89 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -770,7 +770,14 @@
if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionCode",
bundle->getVersionCode(), errorOnFailedInsert, replaceVersion)) {
return UNKNOWN_ERROR;
+ } else {
+ const XMLNode::attribute_entry* attr = root->getAttribute(
+ String16(RESOURCES_ANDROID_NAMESPACE), String16("versionCode"));
+ if (attr != NULL) {
+ bundle->setVersionCode(strdup(String8(attr->string).string()));
+ }
}
+
if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "versionName",
bundle->getVersionName(), errorOnFailedInsert, replaceVersion)) {
return UNKNOWN_ERROR;
@@ -1392,7 +1399,8 @@
sp<ApkSplit>& split = splits.editItemAt(i);
sp<AaptFile> flattenedTable = new AaptFile(String8("resources.arsc"),
AaptGroupEntry(), String8());
- err = table.flatten(bundle, split->getResourceFilter(), flattenedTable);
+ err = table.flatten(bundle, split->getResourceFilter(),
+ flattenedTable, split->isBase());
if (err != NO_ERROR) {
fprintf(stderr, "Failed to generate resource table for split '%s'\n",
split->getPrintableName().string());
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index c98808f..b3c364b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2074,10 +2074,11 @@
return mNumLocal > 0;
}
-sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter)
+sp<AaptFile> ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const bool isBase)
{
sp<AaptFile> data = new AaptFile(String8(), AaptGroupEntry(), String8());
- status_t err = flatten(bundle, filter, data);
+ status_t err = flatten(bundle, filter, data, isBase);
return err == NO_ERROR ? data : NULL;
}
@@ -2699,7 +2700,9 @@
return err;
}
-status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest)
+status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const sp<AaptFile>& dest,
+ const bool isBase)
{
const ConfigDescription nullConfig;
@@ -2712,6 +2715,16 @@
// The libraries this table references.
Vector<sp<Package> > libraryPackages;
+ const ResTable& table = mAssets->getIncludedResources();
+ const size_t basePackageCount = table.getBasePackageCount();
+ for (size_t i = 0; i < basePackageCount; i++) {
+ size_t packageId = table.getBasePackageId(i);
+ String16 packageName(table.getBasePackageName(i));
+ if (packageId > 0x01 && packageId != 0x7f &&
+ packageName != String16("android")) {
+ libraryPackages.add(sp<Package>(new Package(packageName, packageId)));
+ }
+ }
// Iterate through all data, collecting all values (strings,
// references, etc).
@@ -2720,22 +2733,7 @@
for (pi=0; pi<N; pi++) {
sp<Package> p = mOrderedPackages.itemAt(pi);
if (p->getTypes().size() == 0) {
- // Empty, this is an imported package being used as
- // a shared library. We do not flatten this package.
- if (p->getAssignedId() != 0x01 && p->getName() != String16("android")) {
- // This is not the base Android package, and it is a library
- // so we must add a reference to the library when flattening.
- libraryPackages.add(p);
- }
continue;
- } else if (p->getAssignedId() == 0x00) {
- if (mPackageType != SharedLibrary) {
- fprintf(stderr, "ERROR: Package %s can not have ID=0x00 unless building a shared library.",
- String8(p->getName()).string());
- return UNKNOWN_ERROR;
- }
- // If this is a shared library, we also include ourselves as an entry.
- libraryPackages.add(p);
}
StringPool typeStrings(useUTF8);
@@ -2773,6 +2771,13 @@
configTypeName = "2value";
}
+ // mipmaps don't get filtered, so they will
+ // allways end up in the base. Make sure they
+ // don't end up in a split.
+ if (typeName == mipmap16 && !isBase) {
+ continue;
+ }
+
const bool filterable = (typeName != mipmap16);
const size_t N = t->getOrderedConfigs().size();
@@ -2876,10 +2881,12 @@
return amt;
}
- status_t err = flattenLibraryTable(data, libraryPackages);
- if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: failed to write library table\n");
- return err;
+ if (isBase) {
+ status_t err = flattenLibraryTable(data, libraryPackages);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: failed to write library table\n");
+ return err;
+ }
}
// Build the type chunks inside of this package.
@@ -2895,6 +2902,7 @@
continue;
}
const bool filterable = (typeName != mipmap16);
+ const bool skipEntireType = (typeName == mipmap16 && !isBase);
const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
@@ -2932,6 +2940,11 @@
if (cl->getPublic()) {
typeSpecFlags[ei] |= htodl(ResTable_typeSpec::SPEC_PUBLIC);
}
+
+ if (skipEntireType) {
+ continue;
+ }
+
const size_t CN = cl->getEntries().size();
for (size_t ci=0; ci<CN; ci++) {
if (filterable && !filter->match(cl->getEntries().keyAt(ci))) {
@@ -2948,6 +2961,10 @@
}
}
+ if (skipEntireType) {
+ continue;
+ }
+
// We need to write one type chunk for each configuration for
// which we have entries in this type.
const size_t NC = t->getUniqueConfigs().size();
@@ -3147,7 +3164,8 @@
const size_t libStart = dest->getSize();
const size_t count = libs.size();
- ResTable_lib_header* libHeader = (ResTable_lib_header*) dest->editDataInRange(libStart, sizeof(ResTable_lib_header));
+ ResTable_lib_header* libHeader = (ResTable_lib_header*) dest->editDataInRange(
+ libStart, sizeof(ResTable_lib_header));
memset(libHeader, 0, sizeof(*libHeader));
libHeader->header.type = htods(RES_TABLE_LIBRARY_TYPE);
@@ -3163,7 +3181,8 @@
String8(libPackage->getName()).string(),
(uint8_t)libPackage->getAssignedId()));
- ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(entryStart, sizeof(ResTable_lib_entry));
+ ResTable_lib_entry* entry = (ResTable_lib_entry*) dest->editDataInRange(
+ entryStart, sizeof(ResTable_lib_entry));
memset(entry, 0, sizeof(*entry));
entry->packageId = htodl(libPackage->getAssignedId());
strcpy16_htod(entry->packageName, libPackage->getName().string());
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index d4f47ef..3721de4 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -165,7 +165,8 @@
size_t numLocalResources() const;
bool hasResources() const;
- sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter);
+ sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const bool isBase);
static inline uint32_t makeResId(uint32_t packageId,
uint32_t typeId,
@@ -206,7 +207,8 @@
void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
status_t validateLocalizations(void);
- status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter, const sp<AaptFile>& dest);
+ status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
+ const sp<AaptFile>& dest, const bool isBase);
status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
void writePublicDefinitions(const String16& package, FILE* fp);
diff --git a/tools/aapt/tests/ResourceFilter_test.cpp b/tools/aapt/tests/ResourceFilter_test.cpp
index 30697bb..b55379e 100644
--- a/tools/aapt/tests/ResourceFilter_test.cpp
+++ b/tools/aapt/tests/ResourceFilter_test.cpp
@@ -126,3 +126,38 @@
EXPECT_TRUE(filter.match(config));
}
+TEST(StrongResourceFilterTest, MatchesDensities) {
+ ConfigDescription config;
+ config.density = 160;
+ config.version = 4;
+ std::set<ConfigDescription> configs;
+ configs.insert(config);
+
+ StrongResourceFilter filter(configs);
+
+ ConfigDescription expectedConfig;
+ expectedConfig.density = 160;
+ expectedConfig.version = 4;
+ ASSERT_TRUE(filter.match(expectedConfig));
+}
+
+TEST(StrongResourceFilterTest, MatchOnlyMdpiAndExcludeAllOthers) {
+ std::set<ConfigDescription> configsToMatch;
+ ConfigDescription config;
+ config.density = 160;
+ config.version = 4;
+ configsToMatch.insert(config);
+
+ std::set<ConfigDescription> configsToNotMatch;
+ config.density = 480;
+ configsToNotMatch.insert(config);
+
+ AndResourceFilter filter;
+ filter.addFilter(new InverseResourceFilter(new StrongResourceFilter(configsToNotMatch)));
+ filter.addFilter(new StrongResourceFilter(configsToMatch));
+
+ ConfigDescription expectedConfig;
+ expectedConfig.density = 160;
+ expectedConfig.version = 4;
+ ASSERT_TRUE(filter.match(expectedConfig));
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 3d976e7..e27bd7e 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1696,7 +1696,6 @@
*
* @hide
*/
- @SystemApi
public void connect(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
validateChannel();
@@ -1719,7 +1718,6 @@
* initialized again
* @hide
*/
- @SystemApi
public void connect(int networkId, ActionListener listener) {
if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
@@ -1744,7 +1742,6 @@
* initialized again
* @hide
*/
- @SystemApi
public void save(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
validateChannel();
@@ -1764,7 +1761,6 @@
* initialized again
* @hide
*/
- @SystemApi
public void forget(int netId, ActionListener listener) {
if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();
@@ -1780,7 +1776,6 @@
* initialized again
* @hide
*/
- @SystemApi
public void disable(int netId, ActionListener listener) {
if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
validateChannel();