Merge "Abort accessibility node prefetch if parent node is null" into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 6851bbf..979f2cf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4798,7 +4798,9 @@
method public int getCustomSizePreset();
method public android.app.PendingIntent getDisplayIntent();
method public int getGravity();
+ method public boolean getHintAvoidBackgroundClipping();
method public boolean getHintHideIcon();
+ method public int getHintScreenTimeout();
method public boolean getHintShowBackgroundOnly();
method public java.util.List<android.app.Notification> getPages();
method public boolean getStartScrollBottom();
@@ -4811,9 +4813,13 @@
method public android.app.Notification.WearableExtender setCustomSizePreset(int);
method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
method public android.app.Notification.WearableExtender setGravity(int);
+ method public android.app.Notification.WearableExtender setHintAvoidBackgroundClipping(boolean);
method public android.app.Notification.WearableExtender setHintHideIcon(boolean);
+ method public android.app.Notification.WearableExtender setHintScreenTimeout(int);
method public android.app.Notification.WearableExtender setHintShowBackgroundOnly(boolean);
method public android.app.Notification.WearableExtender setStartScrollBottom(boolean);
+ field public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+ field public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
field public static final int SIZE_DEFAULT = 0; // 0x0
field public static final int SIZE_FULL_SCREEN = 5; // 0x5
field public static final int SIZE_LARGE = 4; // 0x4
@@ -28391,6 +28397,7 @@
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
method public void clearAccounts();
+ method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method public android.telecom.PhoneAccountHandle getConnectionManager();
method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
@@ -28849,26 +28856,20 @@
}
public class SubInfoRecord implements android.os.Parcelable {
- ctor public SubInfoRecord();
- ctor public SubInfoRecord(int, java.lang.String, int, java.lang.String, int, int, java.lang.String, int, int, int[], int, int);
method public int describeContents();
method public int getColor();
- method public android.graphics.drawable.BitmapDrawable getIconDrawable();
- method public java.lang.String getLabel();
+ method public int getDataRoaming();
+ method public java.lang.CharSequence getDisplayName();
+ method public java.lang.String getIccId();
+ method public android.graphics.drawable.BitmapDrawable getIcon();
+ method public int getMcc();
+ method public int getMnc();
+ method public int getNameSource();
+ method public java.lang.String getNumber();
+ method public int getSimSlotIndex();
+ method public int getSubscriptionId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.SubInfoRecord> CREATOR;
- field public int color;
- field public int dataRoaming;
- field public java.lang.String displayName;
- field public int displayNumberFormat;
- field public java.lang.String iccId;
- field public int mcc;
- field public int mnc;
- field public int nameSource;
- field public java.lang.String number;
- field public int[] simIconRes;
- field public int slotId;
- field public int subId;
}
public class SubscriptionManager implements android.provider.BaseColumns {
@@ -30278,19 +30279,6 @@
method public static java.text.DateFormat getMediumDateFormat(android.content.Context);
method public static java.text.DateFormat getTimeFormat(android.content.Context);
method public static boolean is24HourFormat(android.content.Context);
- field public static final deprecated char AM_PM = 97; // 0x0061 'a'
- field public static final deprecated char CAPITAL_AM_PM = 65; // 0x0041 'A'
- field public static final deprecated char DATE = 100; // 0x0064 'd'
- field public static final deprecated char DAY = 69; // 0x0045 'E'
- field public static final deprecated char HOUR = 104; // 0x0068 'h'
- field public static final deprecated char HOUR_OF_DAY = 107; // 0x006b 'k'
- field public static final deprecated char MINUTE = 109; // 0x006d 'm'
- field public static final deprecated char MONTH = 77; // 0x004d 'M'
- field public static final deprecated char QUOTE = 39; // 0x0027 '\''
- field public static final deprecated char SECONDS = 115; // 0x0073 's'
- field public static final deprecated char STANDALONE_MONTH = 76; // 0x004c 'L'
- field public static final deprecated char TIME_ZONE = 122; // 0x007a 'z'
- field public static final deprecated char YEAR = 121; // 0x0079 'y'
}
public class DateUtils {
diff --git a/api/removed.txt b/api/removed.txt
index 8972679..1b69ee8 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -22,6 +22,26 @@
}
+package android.text.format {
+
+ public class DateFormat {
+ field public static final deprecated char AM_PM = 97; // 0x0061 'a'
+ field public static final deprecated char CAPITAL_AM_PM = 65; // 0x0041 'A'
+ field public static final deprecated char DATE = 100; // 0x0064 'd'
+ field public static final deprecated char DAY = 69; // 0x0045 'E'
+ field public static final deprecated char HOUR = 104; // 0x0068 'h'
+ field public static final deprecated char HOUR_OF_DAY = 107; // 0x006b 'k'
+ field public static final deprecated char MINUTE = 109; // 0x006d 'm'
+ field public static final deprecated char MONTH = 77; // 0x004d 'M'
+ field public static final deprecated char QUOTE = 39; // 0x0027 '\''
+ field public static final deprecated char SECONDS = 115; // 0x0073 's'
+ field public static final deprecated char STANDALONE_MONTH = 76; // 0x004c 'L'
+ field public static final deprecated char TIME_ZONE = 122; // 0x007a 'z'
+ field public static final deprecated char YEAR = 121; // 0x0079 'y'
+ }
+
+}
+
package android.view {
public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 37e8aa4..a285932 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1243,26 +1243,16 @@
}
/**
- * If set, the process of the root activity of the task will be killed
- * as part of removing the task.
- * @hide
- */
- public static final int REMOVE_TASK_KILL_PROCESS = 0x0001;
-
- /**
* Completely remove the given task.
*
* @param taskId Identifier of the task to be removed.
- * @param flags Additional operational flags. May be 0 or
- * {@link #REMOVE_TASK_KILL_PROCESS}.
* @return Returns true if the given task was found and removed.
*
* @hide
*/
- public boolean removeTask(int taskId, int flags)
- throws SecurityException {
+ public boolean removeTask(int taskId) throws SecurityException {
try {
- return ActivityManagerNative.getDefault().removeTask(taskId, flags);
+ return ActivityManagerNative.getDefault().removeTask(taskId);
} catch (RemoteException e) {
// System dead, we will be dead too soon!
return false;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4e2ff0b..bc7114b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1884,8 +1884,7 @@
{
data.enforceInterface(IActivityManager.descriptor);
int taskId = data.readInt();
- int fl = data.readInt();
- boolean result = removeTask(taskId, fl);
+ boolean result = removeTask(taskId);
reply.writeNoException();
reply.writeInt(result ? 1 : 0);
return true;
@@ -4778,12 +4777,11 @@
return result;
}
- public boolean removeTask(int taskId, int flags) throws RemoteException {
+ public boolean removeTask(int taskId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
- data.writeInt(flags);
mRemote.transact(REMOVE_TASK_TRANSACTION, data, reply, 0);
reply.readException();
boolean result = reply.readInt() != 0;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index be26f30..efcb197 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -373,7 +373,7 @@
public boolean isUserRunning(int userid, boolean orStopping) throws RemoteException;
public int[] getRunningUserIds() throws RemoteException;
- public boolean removeTask(int taskId, int flags) throws RemoteException;
+ public boolean removeTask(int taskId) throws RemoteException;
public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9849c51..c65f017 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4340,6 +4340,19 @@
*/
public static final int SIZE_FULL_SCREEN = 5;
+ /**
+ * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on for a
+ * short amount of time when this notification is displayed on the screen. This
+ * is the default value.
+ */
+ public static final int SCREEN_TIMEOUT_SHORT = 0;
+
+ /**
+ * Sentinel value for use with {@link #setHintScreenTimeout} to keep the screen on
+ * for a longer amount of time when this notification is displayed on the screen.
+ */
+ public static final int SCREEN_TIMEOUT_LONG = -1;
+
/** Notification extra which contains wearable extensions */
private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
@@ -4355,12 +4368,14 @@
private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset";
private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight";
private static final String KEY_GRAVITY = "gravity";
+ private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout";
// Flags bitwise-ored to mFlags
private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1;
private static final int FLAG_HINT_HIDE_ICON = 1 << 1;
private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2;
private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3;
+ private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4;
// Default value for flags integer
private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE;
@@ -4379,6 +4394,7 @@
private int mCustomSizePreset = SIZE_DEFAULT;
private int mCustomContentHeight;
private int mGravity = DEFAULT_GRAVITY;
+ private int mHintScreenTimeout;
/**
* Create a {@link android.app.Notification.WearableExtender} with default
@@ -4414,6 +4430,7 @@
SIZE_DEFAULT);
mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT);
mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY);
+ mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT);
}
}
@@ -4461,6 +4478,9 @@
if (mGravity != DEFAULT_GRAVITY) {
wearableBundle.putInt(KEY_GRAVITY, mGravity);
}
+ if (mHintScreenTimeout != 0) {
+ wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout);
+ }
builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
return builder;
@@ -4480,6 +4500,7 @@
that.mCustomSizePreset = this.mCustomSizePreset;
that.mCustomContentHeight = this.mCustomContentHeight;
that.mGravity = this.mGravity;
+ that.mHintScreenTimeout = this.mHintScreenTimeout;
return that;
}
@@ -4875,6 +4896,48 @@
return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0;
}
+ /**
+ * Set a hint that this notification's background should not be clipped if possible.
+ * @param hintAvoidBackgroundClipping {@code true} to avoid clipping if possible.
+ * @return this object for method chaining
+ */
+ public WearableExtender setHintAvoidBackgroundClipping(
+ boolean hintAvoidBackgroundClipping) {
+ setFlag(FLAG_HINT_AVOID_BACKGROUND_CLIPPING, hintAvoidBackgroundClipping);
+ return this;
+ }
+
+ /**
+ * Get a hint that this notification's background should not be clipped if possible.
+ * @return {@code true} if it's ok if the background is clipped on the screen, false
+ * otherwise. The default value is {@code false} if this was never set.
+ */
+ public boolean getHintAvoidBackgroundClipping() {
+ return (mFlags & FLAG_HINT_AVOID_BACKGROUND_CLIPPING) != 0;
+ }
+
+ /**
+ * Set a hint that the screen should remain on for at least this duration when
+ * this notification is displayed on the screen.
+ * @param timeout The requested screen timeout in milliseconds. Can also be either
+ * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
+ * @return this object for method chaining
+ */
+ public WearableExtender setHintScreenTimeout(int timeout) {
+ mHintScreenTimeout = timeout;
+ return this;
+ }
+
+ /**
+ * Get the duration, in milliseconds, that the screen should remain on for
+ * when this notification is displayed.
+ * @return the duration in milliseconds if > 0, or either one of the sentinel values
+ * {@link #SCREEN_TIMEOUT_SHORT} or {@link #SCREEN_TIMEOUT_LONG}.
+ */
+ public int getHintScreenTimeout() {
+ return mHintScreenTimeout;
+ }
+
private void setFlag(int mask, boolean value) {
if (value) {
mFlags |= mask;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7676e4b..e06f034 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -41,6 +41,7 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.os.StrictMode;
import android.os.UserHandle;
import android.provider.DocumentsContract;
@@ -7498,8 +7499,10 @@
*/
public void prepareToEnterProcess() {
if (mContentUserHint != UserHandle.USER_CURRENT) {
- fixUris(mContentUserHint);
- mContentUserHint = UserHandle.USER_CURRENT;
+ if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
+ fixUris(mContentUserHint);
+ mContentUserHint = UserHandle.USER_CURRENT;
+ }
}
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 084ca30..3f42d25 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -165,7 +165,7 @@
public int otherSwappedOut;
/** @hide */
- public static final int NUM_OTHER_STATS = 16;
+ public static final int NUM_OTHER_STATS = 17;
/** @hide */
public static final int NUM_DVK_STATS = 5;
@@ -296,23 +296,24 @@
case 1: return "Stack";
case 2: return "Cursor";
case 3: return "Ashmem";
- case 4: return "Other dev";
- case 5: return ".so mmap";
- case 6: return ".jar mmap";
- case 7: return ".apk mmap";
- case 8: return ".ttf mmap";
- case 9: return ".dex mmap";
- case 10: return "code mmap";
- case 11: return "image mmap";
- case 12: return "Other mmap";
- case 13: return "Graphics";
- case 14: return "GL";
- case 15: return "Memtrack";
- case 16: return ".Heap";
- case 17: return ".LOS";
- case 18: return ".LinearAlloc";
- case 19: return ".GC";
- case 20: return ".JITCache";
+ case 4: return "Gfx driver";
+ case 5: return "Other dev";
+ case 6: return ".so mmap";
+ case 7: return ".jar mmap";
+ case 8: return ".apk mmap";
+ case 9: return ".ttf mmap";
+ case 10: return ".dex mmap";
+ case 11: return ".oat mmap";
+ case 12: return ".art mmap";
+ case 13: return "Other mmap";
+ case 14: return "Graphics";
+ case 15: return "GL";
+ case 16: return "Memtrack";
+ case 17: return ".Heap";
+ case 18: return ".LOS";
+ case 19: return ".LinearAlloc";
+ case 20: return ".GC";
+ case 21: return ".JITCache";
default: return "????";
}
}
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 9fec9a1..933bcee 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -60,27 +60,45 @@
* {@code SimpleDateFormat}.
*/
public class DateFormat {
- /** @deprecated Use a literal {@code '} instead. */
+ /**
+ * @deprecated Use a literal {@code '} instead.
+ * @removed
+ */
@Deprecated
public static final char QUOTE = '\'';
- /** @deprecated Use a literal {@code 'a'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'a'} instead.
+ * @removed
+ */
@Deprecated
public static final char AM_PM = 'a';
- /** @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'. */
+ /**
+ * @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'.
+ * @removed
+ */
@Deprecated
public static final char CAPITAL_AM_PM = 'A';
- /** @deprecated Use a literal {@code 'd'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'd'} instead.
+ * @removed
+ */
@Deprecated
public static final char DATE = 'd';
- /** @deprecated Use a literal {@code 'E'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'E'} instead.
+ * @removed
+ */
@Deprecated
public static final char DAY = 'E';
- /** @deprecated Use a literal {@code 'h'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'h'} instead.
+ * @removed
+ */
@Deprecated
public static final char HOUR = 'h';
@@ -88,31 +106,51 @@
* @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat}
* and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including
* Jelly Bean MR-1) instead. Note that the two are incompatible.
+ *
+ * @removed
*/
@Deprecated
public static final char HOUR_OF_DAY = 'k';
- /** @deprecated Use a literal {@code 'm'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'm'} instead.
+ * @removed
+ */
@Deprecated
public static final char MINUTE = 'm';
- /** @deprecated Use a literal {@code 'M'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'M'} instead.
+ * @removed
+ */
@Deprecated
public static final char MONTH = 'M';
- /** @deprecated Use a literal {@code 'L'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'L'} instead.
+ * @removed
+ */
@Deprecated
public static final char STANDALONE_MONTH = 'L';
- /** @deprecated Use a literal {@code 's'} instead. */
+ /**
+ * @deprecated Use a literal {@code 's'} instead.
+ * @removed
+ */
@Deprecated
public static final char SECONDS = 's';
- /** @deprecated Use a literal {@code 'z'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'z'} instead.
+ * @removed
+ */
@Deprecated
public static final char TIME_ZONE = 'z';
- /** @deprecated Use a literal {@code 'y'} instead. */
+ /**
+ * @deprecated Use a literal {@code 'y'} instead.
+ * @removed
+ */
@Deprecated
public static final char YEAR = 'y';
@@ -306,9 +344,9 @@
}
/**
- * Gets the current date format stored as a char array. The array will contain
- * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order
- * specified by the user's format preference. Note that this order is
+ * Gets the current date format stored as a char array. Returns a 3 element
+ * array containing the day ({@code 'd'}), month ({@code 'M'}), and year ({@code 'y'}))
+ * in the order specified by the user's format preference. Note that this order is
* <i>only</i> appropriate for all-numeric dates; spelled-out (MEDIUM and LONG)
* dates will generally contain other punctuation, spaces, or words,
* not just the day, month, and year, and not necessarily in the same
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6450146..e464e77 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1746,8 +1746,8 @@
if (hwInitialized ||
mWidth != mAttachInfo.mHardwareRenderer.getWidth() ||
mHeight != mAttachInfo.mHardwareRenderer.getHeight()) {
- final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
- mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight, surfaceInsets);
+ mAttachInfo.mHardwareRenderer.setup(
+ mWidth, mHeight, mWindowAttributes.surfaceInsets);
if (!hwInitialized) {
mAttachInfo.mHardwareRenderer.invalidate(mSurface);
mFullRedrawNeeded = true;
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index fcf66f6..f9544d0 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -107,9 +107,9 @@
mAdapter.setRange(mMinDate, mMaxDate);
- if (constrainCalendar(mSelectedDay, mMinDate, mMaxDate)) {
- goTo(mSelectedDay, false, true, true);
- }
+ // Changing the min/max date changes the selection position since we
+ // don't really have stable IDs.
+ goTo(mSelectedDay, false, true, true);
}
/**
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index d4d186c..f90d64a 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -1752,6 +1752,17 @@
}
/**
+ * Accessor to enable LayoutLib to get ActionMenuPresenter directly.
+ */
+ ActionMenuPresenter getOuterActionMenuPresenter() {
+ return mOuterActionMenuPresenter;
+ }
+
+ Context getPopupContext() {
+ return mPopupContext;
+ }
+
+ /**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
*/
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 0bc1a8d..64bd6b6 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
@@ -75,16 +76,21 @@
}
@Override
- public Intent getReplacementIntent(String packageName, Intent defIntent) {
+ public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
+ Intent result = defIntent;
if (mReplacementExtras != null) {
- final Bundle replExtras = mReplacementExtras.getBundle(packageName);
+ final Bundle replExtras = mReplacementExtras.getBundle(aInfo.packageName);
if (replExtras != null) {
- final Intent result = new Intent(defIntent);
+ result = new Intent(defIntent);
result.putExtras(replExtras);
- return result;
}
}
- return defIntent;
+ if (aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER)
+ || aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+ result = Intent.createChooser(result,
+ getIntent().getCharSequenceExtra(Intent.EXTRA_TITLE));
+ }
+ return result;
}
@Override
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 6e2f84a..9656a21 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -58,21 +58,22 @@
Intent intentReceived = getIntent();
String className = intentReceived.getComponent().getClassName();
- final UserHandle userDest;
+ final int targetUserId;
final int userMessageId;
if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
userMessageId = com.android.internal.R.string.forward_intent_to_owner;
- userDest = UserHandle.OWNER;
+ targetUserId = UserHandle.USER_OWNER;
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
userMessageId = com.android.internal.R.string.forward_intent_to_work;
- userDest = getManagedProfile();
+ targetUserId = getManagedProfile();
} else {
Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
userMessageId = -1;
- userDest = null;
+ targetUserId = UserHandle.USER_NULL;
}
- if (userDest == null) { // This covers the case where there is no managed profile.
+ if (targetUserId == UserHandle.USER_NULL) {
+ // This covers the case where there is no managed profile.
finish();
return;
}
@@ -83,31 +84,24 @@
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
|Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
int callingUserId = getUserId();
- IPackageManager ipm = AppGlobals.getPackageManager();
- String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
- boolean canForward = false;
- Intent selector = newIntent.getSelector();
- if (selector == null) {
- selector = newIntent;
- }
- try {
- canForward = ipm.canForwardTo(selector, resolvedType, callingUserId,
- userDest.getIdentifier());
- } catch (RemoteException e) {
- Slog.e(TAG, "PackageManagerService is dead?");
- }
- if (canForward) {
- newIntent.setContentUserHint(callingUserId);
+
+ if (canForward(newIntent, targetUserId)) {
+ if (newIntent.getAction().equals(Intent.ACTION_CHOOSER)) {
+ Intent innerIntent = (Intent) newIntent.getParcelableExtra(Intent.EXTRA_INTENT);
+ innerIntent.setContentUserHint(callingUserId);
+ } else {
+ newIntent.setContentUserHint(callingUserId);
+ }
final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser(
- newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier());
+ newIntent, MATCH_DEFAULT_ONLY, targetUserId);
// Only show a disclosure if this is a normal (non-OS) app
final boolean shouldShowDisclosure =
!UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID);
try {
- startActivityAsCaller(newIntent, null, userDest.getIdentifier());
+ startActivityAsCaller(newIntent, null, targetUserId);
} catch (RuntimeException e) {
int launchedFromUid = -1;
String launchedFromPackage = "?";
@@ -129,26 +123,55 @@
}
} else {
Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
- + callingUserId + " to user " + userDest.getIdentifier());
+ + callingUserId + " to user " + targetUserId);
}
finish();
}
+ boolean canForward(Intent intent, int targetUserId) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ if (intent.getAction().equals(Intent.ACTION_CHOOSER)) {
+ // The EXTRA_INITIAL_INTENTS may not be allowed to be forwarded.
+ if (intent.hasExtra(Intent.EXTRA_INITIAL_INTENTS)) {
+ Slog.wtf(TAG, "An chooser intent with extra initial intents cannot be forwarded to"
+ + " a different user");
+ return false;
+ }
+ if (intent.hasExtra(Intent.EXTRA_REPLACEMENT_EXTRAS)) {
+ Slog.wtf(TAG, "A chooser intent with replacement extras cannot be forwarded to a"
+ + " different user");
+ return false;
+ }
+ intent = (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ }
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ if (intent.getSelector() != null) {
+ intent = intent.getSelector();
+ }
+ try {
+ return ipm.canForwardTo(intent, resolvedType, getUserId(),
+ targetUserId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "PackageManagerService is dead?");
+ return false;
+ }
+ }
+
/**
- * Returns the managed profile for this device or null if there is no managed
- * profile.
+ * Returns the userId of the managed profile for this device or UserHandle.USER_NULL if there is
+ * no managed profile.
*
* TODO: Remove the assumption that there is only one managed profile
* on the device.
*/
- private UserHandle getManagedProfile() {
+ private int getManagedProfile() {
UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
for (UserInfo userInfo : relatedUsers) {
- if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id);
+ if (userInfo.isManagedProfile()) return userInfo.id;
}
Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
+ " has been called, but there is no managed profile");
- return null;
+ return UserHandle.USER_NULL;
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 7df76e5..376db6e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -100,6 +100,7 @@
private int mMaxColumns;
private int mLastSelected = ListView.INVALID_POSITION;
private boolean mResolvingHome = false;
+ private int mProfileSwitchMessageId = -1;
private UsageStatsManager mUsm;
private Map<String, UsageStats> mStats;
@@ -200,6 +201,11 @@
List<ResolveInfo> rList, boolean alwaysUseOption) {
setTheme(R.style.Theme_DeviceDefault_Resolver);
super.onCreate(savedInstanceState);
+
+ // Determine whether we should show that intent is forwarded
+ // from managed profile to owner or other way around.
+ setProfileSwitchMessageId(intent.getContentUserHint());
+
try {
mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
getActivityToken());
@@ -320,6 +326,22 @@
}
}
+ private void setProfileSwitchMessageId(int contentUserHint) {
+ if (contentUserHint != UserHandle.USER_CURRENT &&
+ contentUserHint != UserHandle.myUserId()) {
+ UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+ UserInfo originUserInfo = userManager.getUserInfo(contentUserHint);
+ boolean originIsManaged = originUserInfo != null ? originUserInfo.isManagedProfile()
+ : false;
+ boolean targetIsManaged = userManager.isManagedProfile();
+ if (originIsManaged && !targetIsManaged) {
+ mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_owner;
+ } else if (!originIsManaged && targetIsManaged) {
+ mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_work;
+ }
+ }
+ }
+
/**
* Turn on launch mode that is safe to use when forwarding intents received from
* applications and running in system processes. This mode uses Activity.startActivityAsCaller
@@ -529,7 +551,7 @@
/**
* Replace me in subclasses!
*/
- public Intent getReplacementIntent(String packageName, Intent defIntent) {
+ public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
return defIntent;
}
@@ -642,6 +664,11 @@
}
public void safelyStartActivity(Intent intent) {
+ // If needed, show that intent is forwarded
+ // from managed profile to owner or other way around.
+ if (mProfileSwitchMessageId != -1) {
+ Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
+ }
if (!mSafeForwardingMode) {
startActivity(intent);
onActivityStarted(intent);
@@ -943,7 +970,7 @@
DisplayResolveInfo dri = filtered ? getItem(position) : mList.get(position);
Intent intent = new Intent(dri.origIntent != null ? dri.origIntent :
- getReplacementIntent(dri.ri.activityInfo.packageName, mIntent));
+ getReplacementIntent(dri.ri.activityInfo, mIntent));
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
|Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
ActivityInfo ai = dri.ri.activityInfo;
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 9ec9993..178bab6 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -46,10 +46,12 @@
HEAP_UNKNOWN,
HEAP_DALVIK,
HEAP_NATIVE,
+
HEAP_DALVIK_OTHER,
HEAP_STACK,
HEAP_CURSOR,
HEAP_ASHMEM,
+ HEAP_GL_DEV,
HEAP_UNKNOWN_DEV,
HEAP_SO,
HEAP_JAR,
@@ -297,7 +299,11 @@
} else if (strncmp(name, "[stack", 6) == 0) {
whichHeap = HEAP_STACK;
} else if (strncmp(name, "/dev/", 5) == 0) {
- whichHeap = HEAP_UNKNOWN_DEV;
+ if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
+ whichHeap = HEAP_GL_DEV;
+ } else {
+ whichHeap = HEAP_UNKNOWN_DEV;
+ }
} else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
whichHeap = HEAP_SO;
is_swappable = true;
diff --git a/docs/html/design/tv/index.jd b/docs/html/design/tv/index.jd
index 483c24f..d79e279 100644
--- a/docs/html/design/tv/index.jd
+++ b/docs/html/design/tv/index.jd
@@ -1,4 +1,7 @@
-page.title=Android TV
+page.title=Designing for Android TV
+page.tags="tv", "leanback","designguidelines"
+page.metaDescription=Guidelines to help you create a great leanback experience on Android TV.
+page.image=design/tv/images/apps-games-rows.jpg
@jd:body
@@ -6,12 +9,15 @@
experience. It's important to understand how your app is presented in the main user interface and
how your app can help users get to the content they want quickly.</p>
-<p class="note">
+<p class="caution">
<strong>Important:</strong> There are specific design requirements your app must meet to qualify
as an Android TV app on Google Play. For more information, see the requirements listed in
<a href="{@docRoot}distribute/essentials/quality/tv.html">TV App Quality</a>.
</p>
+<p class="note"><strong>Note:</strong> For information about how to publish your TV apps in Google Play,
+see <a href="/distribute/googleplay/tv.html">Distributing to Android TV</a>.</p>
+
<h2>Home Screen</h2>
<p>The Home Screen is the start of the user experience, providing search, content
diff --git a/docs/html/distribute/essentials/quality/tv.jd b/docs/html/distribute/essentials/quality/tv.jd
index b13307e..20018c3 100644
--- a/docs/html/distribute/essentials/quality/tv.jd
+++ b/docs/html/distribute/essentials/quality/tv.jd
@@ -47,11 +47,9 @@
qualify as an Android TV app on Google Play.
</p>
-<p class="note">
- <strong>Note:</strong> You will be able to submit TV apps to Google Play with the public release
- of Android 5.0 on November 3. Stay tuned for more information about how to submit your TV apps
- through the Google Play Developer Console.
-</p>
+<p class="note"><strong>Note:</strong> For information about how to publish your TV apps in Google Play,
+see <a href="{@docRoot}distribute/googleplay/tv.html">Distributing to Android TV</a>.</p>
+
<div class="headerLine">
diff --git a/docs/html/distribute/googleplay/edu/start.jd b/docs/html/distribute/googleplay/edu/start.jd
index 3c3a175..f4c9717 100644
--- a/docs/html/distribute/googleplay/edu/start.jd
+++ b/docs/html/distribute/googleplay/edu/start.jd
@@ -1,4 +1,4 @@
-page.title=Publish Apps
+page.title=Publish Education Apps
page.image=/distribute/images/play-education.jpg
meta.tags="education", "guidelines", "quality"
page.tags="education", "addendum"
diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs
index 45464c7..fc7cd11 100644
--- a/docs/html/distribute/googleplay/googleplay_toc.cs
+++ b/docs/html/distribute/googleplay/googleplay_toc.cs
@@ -18,6 +18,12 @@
</div>
</li>
<li class="nav-section">
+ <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/tv.html">
+ <span class="en">Distributing to <span style="white-space:nowrap">Android TV</span></span>
+ </a>
+ </div>
+ </li>
+ <li class="nav-section">
<div class="nav-section-header" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/about.html">
<span class="en">Google Play for Education</span>
</a>
diff --git a/docs/html/distribute/googleplay/index.jd b/docs/html/distribute/googleplay/index.jd
index a215930..20f07fa 100644
--- a/docs/html/distribute/googleplay/index.jd
+++ b/docs/html/distribute/googleplay/index.jd
@@ -21,7 +21,7 @@
data-maxResults="3">
</div>
- <h3>Google Play for Education</h3>
+ <h3>Distribute Your Apps</h3>
<div class="resource-widget resource-flow-layout landing col-16"
data-query="collection:distribute/gp/gpfelanding"
diff --git a/docs/html/distribute/googleplay/tv.jd b/docs/html/distribute/googleplay/tv.jd
new file mode 100644
index 0000000..37cbe26
--- /dev/null
+++ b/docs/html/distribute/googleplay/tv.jd
@@ -0,0 +1,320 @@
+page.title=Distributing to Android TV
+page.image=/design/tv/images/atv-home.jpg
+meta.tags="tv", "publish", "quality"
+page.tags="tv", "publish", "googleplay"
+page.metaDescription=Distribute your apps, games, and content to Android TV.
+
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>How to Participate</h2>
+<ol>
+<li><a href="#understand_guidelines">Understand the guidelines</a></li>
+<li><a href="#develop_app">Develop a great app for TV</a></li>
+<li><a href="#test_app">Test for TV App Quality</a></li>
+<li><a href="#opt_in">Opt-in</a></li>
+<li><a href="#track_review">Track your review</a></li>
+</ol>
+
+<h2>You Should Also Read</h2>
+<ol>
+<li><a href="{@docRoot}distribute/essentials/quality/tv.html">TV App Quality</a></li>
+<li><a href="{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a></li>
+</ol>
+
+</div></div>
+
+<p>
+ If you've got a great app or game, Android TV and Google Play can help you
+ bring it to users right in their living rooms. You'll be able to offer your
+ apps and games in a storefront experience that’s optimized for TV. You can
+ extend your new or existing apps for TV and then publish them using familiar
+ tools and processes in Google Play.
+</p>
+
+<p>
+ To get started, review the sections in this document to learn how to
+ distribute your TV apps to users through Google Play. Be sure to read
+ <a href="{@docRoot}distribute/essentials/quality/tv.html">TV App Quality</a>
+ for information on the usability and quality standards that your apps should
+ meet. When your app is ready, you can opt-in to publishing in the Android TV
+ storefront from the Developer Console.
+</p>
+
+<h2 id="how_to_participate">
+ How to Participate
+</h2>
+
+<p>
+ Google Play lets you put your TV apps in front of a new audience of users in
+ their living rooms. You can develop and publish using your existing Developer
+ Console account and your current distribution and pricing settings. It's easy
+ to participate — the sections below outline the process.
+</p>
+
+<div style="float:right;margin:1em 0 1.5em 2em;">
+ <img src="{@docRoot}images/gp-tv-process.png">
+</div>
+
+<h3 id="understand_guidelines">
+ 1. Understand guidelines and requirements
+</h3>
+
+<p>
+ To prepare for a successful launch on Android TV, start by reviewing the
+ guidelines for creating great app experiences on TV. See the <a href=
+ "{@docRoot}design/tv/index.html">Android TV design guidelines</a> for ideas
+ on extending your app for TV and details on design and usability.
+</p>
+
+<p>
+ As you get started designing your TV experience, make sure to read and
+ understand the quality criteria for TV apps. The Google Play experience for
+ Android TV <strong>showcases only apps that are usable on the TV</strong>
+ — your apps can participate if they meet a set of basic quality
+ criteria. See <a href="{@docRoot}distribute/essentials/quality/tv.html">TV
+ App Quality</a> for details.
+</p>
+
+<h3 id="develop_app">2. Develop a great app for TV</h3>
+
+<p>
+ A great app for TV is designed for living room use and takes advantage of the
+ capabilities of Android TV and related input accessories such as game
+ controllers, D-pads, and remotes. The app is refined to offer a polished,
+ high-quality experience on large screens and delivers a compelling feature
+ set for users.
+</p>
+
+<p>
+ As you consider your TV app, review the <a href=
+ "{@docRoot}training/tv/start/index.html">developer documentation</a> and
+ usability guidelines and plan on supporting them to the greatest extent
+ possible. Make sure to design a great leanback experience for users and build
+ it with the leanback library included in the SDK. You’ll want to optimize
+ other parts of your app for the TV use case and it's a good idea to identify
+ those early in your development process.
+</p>
+
+<p>
+ In most cases, we recommend delivering your TV experience as part of your
+ existing app for phones, tablets, and other devices, using the same package
+ name and store listing. This approach lets users upgrade to your TV experience
+ seamlessly and also lets you take advantage of the reviews and ratings you’ve
+ earned in your app for phones and tablets.
+</p>
+
+<p>
+ You can bundle your TV intents, leanback library, and TV-specific code and
+ resources as part of a single APK solution for all supported devices. If
+ necessary, you can use <a href=
+ "{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK
+ Support</a> to deliver a custom binary to Android TV devices under the same
+ package name and store listing that you use for phones and tablets.
+</p>
+
+<p>
+ Throughout design and development, it's important to have a suitable device
+ on which to prototype and test your user experience. You should acquire one
+ or more Android TV devices or emulators and set up your testing environment
+ as early as possible. The recommended hardware device for testing in the
+ Android TV environment is Nexus Player, which is <a href=
+ "http://www.google.com/intl/all/nexus/player/">available from Google Play</a>
+ and other stores, and you should also acquire a game controller and other TV
+ input devices.
+</p>
+
+<h3 id="test_app">3. Test for TV App Quality</h3>
+
+<p>
+ Your TV apps should be designed to perform well, look great on Android TV,
+ and offer the best user experience possible. Google Play showcases
+ high-quality apps for easy discovery by users in Google Play. Here’s how you
+ can participate and deliver an Android TV app that users will enjoy.
+</p>
+
+<ul>
+ <li>Meet Core App Quality guidelines
+ <ul>
+ <li>Follow <a href="{@docRoot}design/index.html">Android Design
+ guidelines</a>. Pay special attention to using <a href=
+ "http://www.google.com/design/spec/material-design/introduction.html">material
+ design</a> in your app.
+ </li>
+
+ <li>Test your apps against the <a href=
+ "{@docRoot}distribute/essentials/quality/core.html">Core App Quality
+ guidelines</a>.
+ </li>
+ </ul>
+ </li>
+ <li>Meet <a href="{@docRoot}distribute/essentials/quality/tv.html">TV App
+ Quality</a> guidelines
+ <ul>
+ <li>Follow our best practices for <a href="{@docRoot}training/tv/index.html">
+ TV app development</a></li>
+ <li>Make sure your app meets all of the <a href=
+ "{@docRoot}distribute/essentials/quality/tv.html">TV App Quality</a> criteria</li>
+ </ul>
+ </li>
+ <li>Strive for simplicity and highest usability</li>
+</ul>
+
+<h3 id="opt_in">4. Opt-in to Android TV and publish</h3>
+
+<p>
+ When you've built your release-ready APK and tested to ensure that it meets
+ all of the <a href="{@docRoot}distribute/essentials/quality/tv.html">TV App
+ Quality</a> guidelines, upload it to the Developer Console. Update your store
+ listing with TV screenshots and TV banner, and set distribution options as
+ needed. If you aren't familiar with how to prepare for launch on Google Play,
+ see the <a href=
+ "{@docRoot}distribute/googleplay/publish/preparing.html">Launch
+ Checklist.</a>
+</p>
+
+<p>
+ Before you can publish to Android TV users, you need to opt-in to Android
+ TV from the <strong>Pricing and Distribution</strong> section of the
+ Developer Console. Opt-in means that you want your app to be made available
+ to Android TV users through Google Play, and that
+ your app meets <a href="{@docRoot}distribute/essentials/quality/tv.html">TV
+ App Quality</a> guidelines.
+</p>
+
+<p>
+ You can opt-in only if your app meets two preliminary quality
+ criteria that are automatically checked on APK upload:
+</p>
+
+<ul>
+ <li>Your app manifest must include an intent type of <a href=
+ "{@docRoot}reference/android/content/Intent.html#ACTION_MAIN"><code>ACTION_MAIN</code></a>
+ with category <a href=
+ "{@docRoot}reference/android/content/Intent.html#CATEGORY_LEANBACK_LAUNCHER">
+ <code>CATEGORY_LEANBACK_LAUNCHER</code></a>. Learn more <a href=
+ "{@docRoot}training/tv/start/start.html#tv-activity">here</a>.
+ </li>
+
+ <li>Your app must declare that it does not require a touchscreen. The
+ manifest must declare the <code>android.hardware.touchscreen</code> hardware
+ with <code>android:required="false”</code>. Learn more <a href=
+ "{@docRoot}training/tv/start/hardware.html#declare-hardware-requirements">here</a>.
+ </li>
+</ul>
+
+<p>
+ If your app meets the preliminary criteria, you’ll see an opt-in checkbox for
+ Android TV, as shown below. If the opt-in checkbox is not enabled, review
+ your APK to ensure it meets the preliminary criteria.
+</p>
+
+<p>
+ After you opt-in and save the changes, you can publish your app as usual.
+ Before making the app available to Android TV users, Google Play submits
+ your app for review against the <a href=
+ "{@docRoot}distribute/essentials/quality/tv.html">TV App Quality</a> criteria
+ and notifies you of the result. See the next section for details on how to
+ track the approval status of your app.
+</p>
+
+<p>
+ If your app meet <a href="{@docRoot}distribute/essentials/quality/tv.html">TV
+ App Quality</a> criteria, Google Play makes that app available to Android TV
+ users. Your app is alsoeligible for higher-visibility featuring in app
+ collections and promotions. To let users everywhere know that your app is
+ designed for Android TV, Google Play decorates the app’s store listing with a
+ TV badge.
+</p>
+
+<p>
+ Note that opt-in and review do not affect the availability of your app to
+ other devices in Google Play Store — on phones and tablets, for
+ example, your app is available as soon as you publish.
+</p>
+
+<p>
+ Here are the steps to opt-in to Android TV in the Developer Console:
+</p>
+
+<ol>
+ <li>Make sure your app meets all <a href=
+ "{@docRoot}distribute/essentials/quality/tv.html">TV App Quality</a> criteria
+ </li>
+
+ <li>Add TV screenshots and banner graphic to the app’s store listing
+ </li>
+
+ <li>In the <strong>All Applications</strong> page, click the app you want to opt-in.
+ </li>
+
+ <li>Under <strong>Pricing and Distribution</strong>, scroll down to find <em>Android TV</em> and the
+ opt-in checkbox.
+ </li>
+
+ <li>Click the checkbox next to <em>Distribute your app to Android TV</em>.
+ </li>
+
+ <li>Click <strong>Save</strong> to save your changes.
+ </li>
+</ol>
+
+<div style="padding-top:1em">
+ <img style="border:2px solid #ddd;" src="{@docRoot}images/gp-tv-opt-in.png">
+ <p class="caption">
+ <strong>Opt-in for TV:</strong> Include your app in Android TV by opting-in from the
+ Developer Console.
+ </p>
+</div>
+
+<h3 id="track_review">5. Track your review and approval</h3>
+
+<p>
+ If your app meets the technical and quality criteria for Android TV, as described above,
+ your app will be available for users to enjoy on Android TV. If your app doesn’t meet
+ the criteria, you’ll receive a <strong>notification email sent to your developer account
+ address</strong>, with a summary of the areas that you need to address. When you’ve made
+ the necessary adjustments, you can upload a new version of your app to the Developer
+ Console.
+</p>
+
+<p>
+ At any time, you can check the review and approval status of your app in the
+ Developer Console, under <em>Android TV</em> in the app's <strong>Pricing and Distribution</strong>
+ page.
+</p>
+
+<p>
+ There are three approval states:
+</p>
+
+<ul>
+ <li>
+ <em>Pending</em> — Your app was sent for review and the review is not yet
+ complete.
+ </li>
+
+ <li>
+ <em>Approved</em> — Your app was reviewed and approved. The app will be
+ made available directly to Android TV users.
+ </li>
+
+ <li>
+ <em>Not approved</em> — Your app was reviewed and not approved. Check the
+ notification email for information about why the app was not approved. You
+ can address any issues and opt-in and publish again to initiate another
+ review.
+ </li>
+</ul>
+
+<p>To understand how your apps are evaluated, please see the <a href=
+"{@docRoot}distribute/essentials/quality/tv.html">TV App Quality</a> document. </p>
+
+
+ <h3>Related resources</h3>
+
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="collection:tvlanding"
+ data-cardSizes="9x6, 6x3x2"
+ data-maxResults="6">
+ </div>
diff --git a/docs/html/images/emulator-wvga800l.png b/docs/html/images/emulator-wvga800l.png
deleted file mode 100644
index c92c1b9..0000000
--- a/docs/html/images/emulator-wvga800l.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/emulator.png b/docs/html/images/emulator.png
new file mode 100644
index 0000000..96a2507
--- /dev/null
+++ b/docs/html/images/emulator.png
Binary files differ
diff --git a/docs/html/images/emulator@2x.png b/docs/html/images/emulator@2x.png
new file mode 100644
index 0000000..9b825a7
--- /dev/null
+++ b/docs/html/images/emulator@2x.png
Binary files differ
diff --git a/docs/html/images/games/game-controller-buttons_2x_crop.png b/docs/html/images/games/game-controller-buttons_2x_crop.png
new file mode 100644
index 0000000..54dc2fa
--- /dev/null
+++ b/docs/html/images/games/game-controller-buttons_2x_crop.png
Binary files differ
diff --git a/docs/html/images/gp-tv-opt-in.png b/docs/html/images/gp-tv-opt-in.png
new file mode 100644
index 0000000..a815818
--- /dev/null
+++ b/docs/html/images/gp-tv-opt-in.png
Binary files differ
diff --git a/docs/html/images/gp-tv-process.png b/docs/html/images/gp-tv-process.png
new file mode 100644
index 0000000..a530777
--- /dev/null
+++ b/docs/html/images/gp-tv-process.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 08c0090..d63580e 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -57,8 +57,8 @@
},
"distribute/gp/gpfelanding": {
"resources": [
+ "distribute/googleplay/tv.html",
"distribute/googleplay/edu/about.html",
- "distribute/googleplay/edu/start.html",
"distribute/googleplay/edu/videos.html"
]
},
@@ -773,6 +773,14 @@
"https://support.google.com/googleplay/answer/2651410"
]
},
+ "tvlanding": {
+ "title": "",
+ "resources": [
+ "tv/index.html",
+ "design/tv/index.html",
+ "training/tv/index.html"
+ ]
+ },
"distribute/stories/games": {
"title": "",
"resources": [
diff --git a/docs/html/tools/devices/emulator.jd b/docs/html/tools/devices/emulator.jd
index ea1549d..d7bb8c7 100644
--- a/docs/html/tools/devices/emulator.jd
+++ b/docs/html/tools/devices/emulator.jd
@@ -80,7 +80,9 @@
provides a screen in which your application is displayed, together with any other
active Android applications. </p>
-<img src="{@docRoot}images/emulator-wvga800l.png" width="367" height="349" />
+<img src="{@docRoot}images/emulator@2x.png"
+srcset="{@docRoot}images/emulator.png 1x, {@docRoot}images/emulator@2x.png 2x" alt=""
+ width="367" height="330"/>
<p>To let you model and test your application more easily, the emulator utilizes
Android Virtual Device (AVD) configurations. AVDs let you define certain hardware
diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd
index e8291b8..efc0ee3 100644
--- a/docs/html/training/material/animations.jd
+++ b/docs/html/training/material/animations.jd
@@ -84,12 +84,14 @@
int cy = (myView.getTop() + myView.getBottom()) / 2;
// get the final radius for the clipping circle
-int finalRadius = myView.getWidth();
+int finalRadius = Math.max(myView.getWidth(), myView.getHeight());
-// create and start the animator for this view
-// (the start radius is zero)
+// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
+
+// make the view visible and start the animation
+myView.setVisibility(View.VISIBLE);
anim.start();
</pre>
diff --git a/docs/html/training/tv/discovery/index.jd b/docs/html/training/tv/discovery/index.jd
index fbc8c9f..5849149 100644
--- a/docs/html/training/tv/discovery/index.jd
+++ b/docs/html/training/tv/discovery/index.jd
@@ -1,4 +1,5 @@
-page.title=Helping Users Find Content on TV
+page.title=Helping Users Find Your Content on TV
+page.tags="tv", "leanback"
startpage=true
diff --git a/docs/html/training/tv/games/index.jd b/docs/html/training/tv/games/index.jd
index 8a998e0..5276d7f 100644
--- a/docs/html/training/tv/games/index.jd
+++ b/docs/html/training/tv/games/index.jd
@@ -1,5 +1,7 @@
page.title=Building TV Games
-page.tags="controller"
+page.tags="tv", "games", "controller"
+page.image=images/games/game-controller-buttons_2x_crop.png
+page.metaDescription=How to bring your games to Android TV, including recommendations and examples.
page.article=true
@jd:body
@@ -180,7 +182,7 @@
It includes a white controller on black background and a black controller on white background
(shown in figure 1), as a PNG file and an Adobe® Illustrator® file.</p>
-<img src="{@docRoot}images/games/game-controller-buttons_2x.png" width="700"
+<img itemprop="image" src="{@docRoot}images/games/game-controller-buttons_2x.png" width="700"
srcset="{@docRoot}images/games/game-controller-buttons_2x.png 2x,
{@docRoot}images/games/game-controller-buttons.png 1x" />
<p class="img-caption"><b>Figure 1.</b> Example controller instructions using the
diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd
index 56667a9..d52e1e8 100644
--- a/docs/html/training/tv/index.jd
+++ b/docs/html/training/tv/index.jd
@@ -1,8 +1,11 @@
page.title=Building Apps for TV
page.trainingcourse=true
-
+page.metaDescription=Starting point for building apps and games for Android TV, with guidelines, information, and examples.
+page.image=design/tv/images/focus.png
@jd:body
-<p>These classes teach you how to build apps for TV devices.</p>
\ No newline at end of file
+<p>These classes teach you how to build apps for TV devices.</p>
+
+<p class="note"><strong>Note:</strong> For details on how to publish your TV apps in Google Play, see <a href="{docRoot}distribute/googleplay/tv.html">Distributing to Android TV</a>.</p>
\ No newline at end of file
diff --git a/docs/html/training/tv/playback/index.jd b/docs/html/training/tv/playback/index.jd
index 118fc6c..09c3f24 100644
--- a/docs/html/training/tv/playback/index.jd
+++ b/docs/html/training/tv/playback/index.jd
@@ -1,5 +1,5 @@
page.title=Building TV Playback Apps
-page.tags="leanback"
+page.tags="tv","leanback"
startpage=true
diff --git a/docs/html/training/tv/start/index.jd b/docs/html/training/tv/start/index.jd
index ceefea1..fb478a8 100644
--- a/docs/html/training/tv/start/index.jd
+++ b/docs/html/training/tv/start/index.jd
@@ -1,4 +1,5 @@
page.title=Building TV Apps
+page.tags="tv", "leanback"
startpage=true
@jd:body
diff --git a/docs/html/training/tv/tif/index.jd b/docs/html/training/tv/tif/index.jd
index 4746e42..cde8ba7 100644
--- a/docs/html/training/tv/tif/index.jd
+++ b/docs/html/training/tv/tif/index.jd
@@ -1,5 +1,5 @@
page.title=Building Live TV Apps
-page.tags=tif
+page.tags="tv", "tif"
page.article=true
@jd:body
diff --git a/docs/html/training/wearables/apps/bt-debugging.jd b/docs/html/training/wearables/apps/bt-debugging.jd
index 8d09c43..98cf804 100644
--- a/docs/html/training/wearables/apps/bt-debugging.jd
+++ b/docs/html/training/wearables/apps/bt-debugging.jd
@@ -58,7 +58,8 @@
</li>
<li>Connect the handheld to your machine over USB and run:
<pre>
-adb forward tcp:4444 localabstract:/adb-hub; adb connect localhost:4444
+adb forward tcp:4444 localabstract:/adb-hub
+adb connect localhost:4444
</pre>
<p class="note"><b>Note</b>: You can use any available port that you have access to.</p>
diff --git a/docs/html/training/wearables/data-layer/accessing.jd b/docs/html/training/wearables/data-layer/accessing.jd
index 896a698..36e3daa 100644
--- a/docs/html/training/wearables/data-layer/accessing.jd
+++ b/docs/html/training/wearables/data-layer/accessing.jd
@@ -37,7 +37,7 @@
implementing its callbacks, and handling error cases.</p>
<pre style="clear:right">
-GoogleApiClient mGoogleAppiClient = new GoogleApiClient.Builder(this)
+GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(new ConnectionCallbacks() {
@Override
public void onConnected(Bundle connectionHint) {
@@ -64,4 +64,4 @@
method, as described in
<a href="{@docRoot}google/auth/api-client.html#Starting">Accessing Google Play services APIs</a>.
When the system invokes the <code>onConnected()</code> callback for your client, you're ready
-to use the data layer API.</p>
\ No newline at end of file
+to use the data layer API.</p>
diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd
index 71e177b..e4d7f7a 100644
--- a/docs/html/tv/index.jd
+++ b/docs/html/tv/index.jd
@@ -1,5 +1,9 @@
-page.title=Android TV
+page.title=About Android TV
+page.type=about
+page.image=tv/images/hero.jpg
page.viewport_width=970
+page.tags="tv", "leanback"
+page.metaDescription=Bring your apps, games, and content to the biggest screen in the house.
fullpage=true
no_footer_links=true
page.type=about
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 1458238..94c7026 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -943,7 +943,11 @@
float radius = st.mGradientRadius;
if (st.mGradientRadiusType == RADIUS_TYPE_FRACTION) {
- radius *= Math.min(st.mWidth, st.mHeight);
+ // Fall back to parent width or height if intrinsic
+ // size is not specified.
+ final float width = st.mWidth >= 0 ? st.mWidth : r.width();
+ final float height = st.mHeight >= 0 ? st.mHeight : r.height();
+ radius *= Math.min(width, height);
} else if (st.mGradientRadiusType == RADIUS_TYPE_FRACTION_PARENT) {
radius *= Math.min(r.width(), r.height());
}
@@ -954,9 +958,9 @@
mGradientRadius = radius;
- if (radius == 0) {
- // We can't have a shader with zero radius, so let's
- // have a very, very small radius.
+ if (radius <= 0) {
+ // We can't have a shader with non-positive radius, so
+ // let's have a very, very small radius.
radius = 0.001f;
}
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 85e442da..6b84494 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -36,6 +36,17 @@
namespace android {
+/**
+ * In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
+ * casting on raw data and expect char16_t to be exactly 16 bits.
+ */
+#if __cplusplus >= 201103L
+struct __assertChar16Size {
+ static_assert(sizeof(char16_t) == sizeof(uint16_t), "char16_t is not 16 bits");
+ static_assert(alignof(char16_t) == alignof(uint16_t), "char16_t is not 16-bit aligned");
+};
+#endif
+
/** ********************************************************************
* PNG Extensions
*
@@ -702,25 +713,25 @@
// These are available for all nodes:
int32_t getCommentID() const;
- const uint16_t* getComment(size_t* outLen) const;
+ const char16_t* getComment(size_t* outLen) const;
uint32_t getLineNumber() const;
// This is available for TEXT:
int32_t getTextID() const;
- const uint16_t* getText(size_t* outLen) const;
+ const char16_t* getText(size_t* outLen) const;
ssize_t getTextValue(Res_value* outValue) const;
// These are available for START_NAMESPACE and END_NAMESPACE:
int32_t getNamespacePrefixID() const;
- const uint16_t* getNamespacePrefix(size_t* outLen) const;
+ const char16_t* getNamespacePrefix(size_t* outLen) const;
int32_t getNamespaceUriID() const;
- const uint16_t* getNamespaceUri(size_t* outLen) const;
+ const char16_t* getNamespaceUri(size_t* outLen) const;
// These are available for START_TAG and END_TAG:
int32_t getElementNamespaceID() const;
- const uint16_t* getElementNamespace(size_t* outLen) const;
+ const char16_t* getElementNamespace(size_t* outLen) const;
int32_t getElementNameID() const;
- const uint16_t* getElementName(size_t* outLen) const;
+ const char16_t* getElementName(size_t* outLen) const;
// Remaining methods are for retrieving information about attributes
// associated with a START_TAG:
@@ -729,10 +740,10 @@
// Returns -1 if no namespace, -2 if idx out of range.
int32_t getAttributeNamespaceID(size_t idx) const;
- const uint16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
+ const char16_t* getAttributeNamespace(size_t idx, size_t* outLen) const;
int32_t getAttributeNameID(size_t idx) const;
- const uint16_t* getAttributeName(size_t idx, size_t* outLen) const;
+ const char16_t* getAttributeName(size_t idx, size_t* outLen) const;
uint32_t getAttributeNameResID(size_t idx) const;
// These will work only if the underlying string pool is UTF-8.
@@ -740,7 +751,7 @@
const char* getAttributeName8(size_t idx, size_t* outLen) const;
int32_t getAttributeValueStringID(size_t idx) const;
- const uint16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
+ const char16_t* getAttributeStringValue(size_t idx, size_t* outLen) const;
int32_t getAttributeDataType(size_t idx) const;
int32_t getAttributeData(size_t idx) const;
@@ -845,7 +856,7 @@
uint32_t id;
// Actual name of this package, \0-terminated.
- char16_t name[128];
+ uint16_t name[128];
// Offset to a ResStringPool_header defining the resource
// type symbol table. If zero, this package is inheriting from
@@ -1450,7 +1461,7 @@
uint32_t packageId;
// The package name of the shared library. \0 terminated.
- char16_t packageName[128];
+ uint16_t packageName[128];
};
/**
@@ -1681,7 +1692,7 @@
size_t defPackageLen = 0,
uint32_t* outTypeSpecFlags = NULL) const;
- static bool expandResourceRef(const uint16_t* refStr, size_t refLen,
+ static bool expandResourceRef(const char16_t* refStr, size_t refLen,
String16* outPackage,
String16* outType,
String16* outName,
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index dbee7ed..20d5470 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -14,7 +14,7 @@
LOCAL_PATH:= $(call my-dir)
-# libandroidfw is partially built for the host (used by obbtool and others)
+# libandroidfw is partially built for the host (used by obbtool, aapt, and others)
# These files are common to host and target builds.
commonSources := \
@@ -35,26 +35,17 @@
BackupHelpers.cpp \
CursorWindow.cpp
-hostSources := \
- $(commonSources)
+hostSources := $(commonSources)
# For the host
# =====================================================
-
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(hostSources)
-
LOCAL_MODULE:= libandroidfw
-
LOCAL_MODULE_TAGS := optional
-
LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
-
-LOCAL_C_INCLUDES := \
- external/zlib
-
-LOCAL_STATIC_LIBRARIES := liblog libziparchive-host libutils
+LOCAL_SRC_FILES:= $(hostSources)
+LOCAL_C_INCLUDES := external/zlib
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -64,8 +55,13 @@
include $(CLEAR_VARS)
+LOCAL_MODULE:= libandroidfw
+LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= $(deviceSources)
-
+LOCAL_C_INCLUDES := \
+ external/zlib \
+ system/core/include
+LOCAL_STATIC_LIBRARIES := libziparchive
LOCAL_SHARED_LIBRARIES := \
libbinder \
liblog \
@@ -73,16 +69,6 @@
libutils \
libz
-LOCAL_STATIC_LIBRARIES := libziparchive
-
-LOCAL_C_INCLUDES := \
- external/zlib \
- system/core/include
-
-LOCAL_MODULE:= libandroidfw
-
-LOCAL_MODULE_TAGS := optional
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 3bbca1a..f1e4858 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -87,11 +87,11 @@
// range checked; guaranteed to NUL-terminate within the stated number of available slots
// NOTE: if this truncates the dst string due to running out of space, no attempt is
// made to avoid splitting surrogate pairs.
-static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail)
+static void strcpy16_dtoh(char16_t* dst, const uint16_t* src, size_t avail)
{
- uint16_t* last = dst + avail - 1;
+ char16_t* last = dst + avail - 1;
while (*src && (dst < last)) {
- char16_t s = dtohs(*src);
+ char16_t s = dtohs(static_cast<char16_t>(*src));
*dst++ = s;
src++;
}
@@ -501,7 +501,7 @@
if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
charSize = sizeof(uint8_t);
} else {
- charSize = sizeof(char16_t);
+ charSize = sizeof(uint16_t);
}
// There should be at least space for the smallest string
@@ -547,8 +547,8 @@
e[i] = dtohl(mEntries[i]);
}
if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
- const char16_t* strings = (const char16_t*)mStrings;
- char16_t* s = const_cast<char16_t*>(strings);
+ const uint16_t* strings = (const uint16_t*)mStrings;
+ uint16_t* s = const_cast<uint16_t*>(strings);
for (i=0; i<mStringPoolSize; i++) {
s[i] = dtohs(strings[i]);
}
@@ -558,7 +558,7 @@
if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
(!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
- ((char16_t*)mStrings)[mStringPoolSize-1] != 0)) {
+ ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
ALOGW("Bad string block: last string is not 0-terminated\n");
return (mError=BAD_TYPE);
}
@@ -656,7 +656,7 @@
* add it together with the next character.
*/
static inline size_t
-decodeLength(const char16_t** str)
+decodeLength(const uint16_t** str)
{
size_t len = **str;
if ((len & 0x8000) != 0) {
@@ -689,19 +689,19 @@
return len;
}
-const uint16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
+const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
- const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
+ const uint32_t off = mEntries[idx]/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
if (off < (mStringPoolSize-1)) {
if (!isUTF8) {
- const char16_t* strings = (char16_t*)mStrings;
- const char16_t* str = strings+off;
+ const uint16_t* strings = (uint16_t*)mStrings;
+ const uint16_t* str = strings+off;
*u16len = decodeLength(&str);
if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
- return str;
+ return reinterpret_cast<const char16_t*>(str);
} else {
ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
(int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
@@ -1013,7 +1013,7 @@
return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
}
-const uint16_t* ResXMLParser::getComment(size_t* outLen) const
+const char16_t* ResXMLParser::getComment(size_t* outLen) const
{
int32_t id = getCommentID();
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
@@ -1032,7 +1032,7 @@
return -1;
}
-const uint16_t* ResXMLParser::getText(size_t* outLen) const
+const char16_t* ResXMLParser::getText(size_t* outLen) const
{
int32_t id = getTextID();
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
@@ -1055,7 +1055,7 @@
return -1;
}
-const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
+const char16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
{
int32_t id = getNamespacePrefixID();
//printf("prefix=%d event=%p\n", id, mEventCode);
@@ -1070,7 +1070,7 @@
return -1;
}
-const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
+const char16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
{
int32_t id = getNamespaceUriID();
//printf("uri=%d event=%p\n", id, mEventCode);
@@ -1088,7 +1088,7 @@
return -1;
}
-const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
+const char16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
{
int32_t id = getElementNamespaceID();
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
@@ -1105,7 +1105,7 @@
return -1;
}
-const uint16_t* ResXMLParser::getElementName(size_t* outLen) const
+const char16_t* ResXMLParser::getElementName(size_t* outLen) const
{
int32_t id = getElementNameID();
return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
@@ -1134,7 +1134,7 @@
return -2;
}
-const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
+const char16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
{
int32_t id = getAttributeNamespaceID(idx);
//printf("attribute namespace=%d idx=%d event=%p\n", id, idx, mEventCode);
@@ -1165,7 +1165,7 @@
return -1;
}
-const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
+const char16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
{
int32_t id = getAttributeNameID(idx);
//printf("attribute name=%d idx=%d event=%p\n", id, idx, mEventCode);
@@ -1205,7 +1205,7 @@
return -1;
}
-const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
+const char16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
{
int32_t id = getAttributeValueStringID(idx);
//XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
@@ -4239,7 +4239,7 @@
return 0;
}
-bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen,
+bool ResTable::expandResourceRef(const char16_t* refStr, size_t refLen,
String16* outPackage,
String16* outType,
String16* outName,
@@ -5665,8 +5665,8 @@
if (idx == 0) {
idx = mPackageGroups.size() + 1;
- char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
- strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
+ char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
+ strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
group = new PackageGroup(this, String16(tmpName), id);
if (group == NULL) {
delete package;
@@ -6036,7 +6036,10 @@
*outSize += 2 * sizeof(uint16_t);
// overlay packages are assumed to contain only one package group
- const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
+ const ResTable_package* overlayPackageStruct = overlay.mPackageGroups[0]->packages[0]->package;
+ char16_t tmpName[sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0])];
+ strcpy16_dtoh(tmpName, overlayPackageStruct->name, sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0]));
+ const String16 overlayPackage(tmpName);
for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) {
const TypeList& typeList = pg->types[typeIndex];
@@ -6345,8 +6348,10 @@
// Use a package's real ID, since the ID may have been assigned
// if this package is a shared library.
packageId = pkg->package->id;
+ char16_t tmpName[sizeof(pkg->package->name)/sizeof(pkg->package->name[0])];
+ strcpy16_dtoh(tmpName, pkg->package->name, sizeof(pkg->package->name)/sizeof(pkg->package->name[0]));
printf(" Package %d id=0x%02x name=%s\n", (int)pkgIndex,
- pkg->package->id, String8(String16(pkg->package->name)).string());
+ pkg->package->id, String8(tmpName).string());
}
for (size_t typeIndex=0; typeIndex < pg->types.size(); typeIndex++) {
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
index 29686ef..ea54cc5 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -22,9 +22,9 @@
#include <androidfw/misc.h>
#include <sys/stat.h>
-#include <string.h>
+#include <cstring>
#include <errno.h>
-#include <stdio.h>
+#include <cstdio>
using namespace android;
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index b2e465c..2d7906f 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -37,7 +37,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libandroidfw_tests
-
LOCAL_SRC_FILES := $(testFiles)
LOCAL_STATIC_LIBRARIES := \
libandroidfw \
@@ -55,11 +54,9 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libandroidfw_tests
-
LOCAL_SRC_FILES := $(testFiles) \
BackupData_test.cpp \
ObbFile_test.cpp
-
LOCAL_SHARED_LIBRARIES := \
libandroidfw \
libcutils \
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 281ca02..27ef06f 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -812,7 +812,7 @@
// determine point shape
SkPath path;
float radius = paintInfo.halfStrokeWidth;
- if (radius == 0.0f) radius = 0.25f;
+ if (radius == 0.0f) radius = 0.5f;
if (paintInfo.cap == SkPaint::kRound_Cap) {
path.addCircle(0, 0, radius);
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2f68382..29d4930 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -533,6 +533,8 @@
private AudioOrientationEventListener mOrientationListener;
+ private static Long mLastDeviceConnectMsgTime = new Long(0);
+
///////////////////////////////////////////////////////////////////////////
// Construction
///////////////////////////////////////////////////////////////////////////
@@ -740,15 +742,17 @@
}
private void checkAllAliasStreamVolumes() {
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- if (streamType != mStreamVolumeAlias[streamType]) {
- mStreamStates[streamType].
+ synchronized (VolumeStreamState.class) {
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = 0; streamType < numStreamTypes; streamType++) {
+ if (streamType != mStreamVolumeAlias[streamType]) {
+ mStreamStates[streamType].
setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
- }
- // apply stream volume
- if (!mStreamStates[streamType].isMuted()) {
- mStreamStates[streamType].applyAllVolumes();
+ }
+ // apply stream volume
+ if (!mStreamStates[streamType].isMuted_syncVSS()) {
+ mStreamStates[streamType].applyAllVolumes();
+ }
}
}
}
@@ -1520,7 +1524,9 @@
/** get stream mute state. */
public boolean isStreamMute(int streamType) {
- return mStreamStates[streamType].isMuted();
+ synchronized (VolumeStreamState.class) {
+ return mStreamStates[streamType].isMuted_syncVSS();
+ }
}
private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
@@ -1658,17 +1664,19 @@
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
int device = getDeviceForStream(streamType);
- int index = mStreamStates[streamType].getIndex(device);
+ synchronized (VolumeStreamState.class) {
+ int index = mStreamStates[streamType].getIndex(device);
- // by convention getStreamVolume() returns 0 when a stream is muted.
- if (mStreamStates[streamType].isMuted()) {
- index = 0;
+ // by convention getStreamVolume() returns 0 when a stream is muted.
+ if (mStreamStates[streamType].isMuted_syncVSS()) {
+ index = 0;
+ }
+ if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
+ (device & mFixedVolumeDevices) != 0) {
+ index = mStreamStates[streamType].getMaxIndex();
+ }
+ return (index + 5) / 10;
}
- if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
- (device & mFixedVolumeDevices) != 0) {
- index = mStreamStates[streamType].getMaxIndex();
- }
- return (index + 5) / 10;
}
public int getMasterVolume() {
@@ -1822,7 +1830,7 @@
// on voice capable devices
if (isPlatformVoice() &&
mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
- synchronized (mStreamStates[streamType]) {
+ synchronized (VolumeStreamState.class) {
Set set = mStreamStates[streamType].mIndex.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
@@ -2321,16 +2329,15 @@
continue;
}
- synchronized (streamState) {
- streamState.readSettings();
-
+ streamState.readSettings();
+ synchronized (VolumeStreamState.class) {
// unmute stream that was muted but is not affect by mute anymore
- if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
+ if (streamState.isMuted_syncVSS() && ((!isStreamAffectedByMute(streamType) &&
!isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
int size = streamState.mDeathHandlers.size();
for (int i = 0; i < size; i++) {
streamState.mDeathHandlers.get(i).mMuteCount = 1;
- streamState.mDeathHandlers.get(i).mute(false);
+ streamState.mDeathHandlers.get(i).mute_syncVSS(false);
}
}
}
@@ -3264,8 +3271,15 @@
} else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
return;
}
-
- handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
+ synchronized (mLastDeviceConnectMsgTime) {
+ long time = SystemClock.uptimeMillis() + delay;
+ handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
+ if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
+ msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
+ msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
+ mLastDeviceConnectMsgTime = time;
+ }
+ }
}
boolean checkAudioSettingsPermission(String method) {
@@ -3344,6 +3358,12 @@
// Inner classes
///////////////////////////////////////////////////////////////////////////
+ // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
+ // 1 mScoclient OR mSafeMediaVolumeState
+ // 2 mSetModeDeathHandlers
+ // 3 mSettingsLock
+ // 4 VolumeStreamState.class
+ // 5 mCameraSoundForced
public class VolumeStreamState {
private final int mStreamType;
@@ -3425,9 +3445,10 @@
}
}
- public void applyDeviceVolume(int device) {
+ // must be called while synchronized VolumeStreamState.class
+ public void applyDeviceVolume_syncVSS(int device) {
int index;
- if (isMuted()) {
+ if (isMuted_syncVSS()) {
index = 0;
} else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
|| ((device & mFullVolumeDevices) != 0)) {
@@ -3443,7 +3464,7 @@
// apply default volume first: by convention this will reset all
// devices volumes in audio policy manager to the supplied value
int index;
- if (isMuted()) {
+ if (isMuted_syncVSS()) {
index = 0;
} else {
index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
@@ -3456,7 +3477,7 @@
Map.Entry entry = (Map.Entry)i.next();
int device = ((Integer)entry.getKey()).intValue();
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
- if (isMuted()) {
+ if (isMuted_syncVSS()) {
index = 0;
} else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
mAvrcpAbsVolSupported)
@@ -3568,12 +3589,12 @@
public void mute(IBinder cb, boolean state) {
synchronized (VolumeStreamState.class) {
- VolumeDeathHandler handler = getDeathHandler(cb, state);
+ VolumeDeathHandler handler = getDeathHandler_syncVSS(cb, state);
if (handler == null) {
Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
return;
}
- handler.mute(state);
+ handler.mute_syncVSS(state);
}
}
@@ -3595,7 +3616,7 @@
|| (((device & mFixedVolumeDevices) != 0) && index != 0)) {
entry.setValue(mIndexMax);
}
- applyDeviceVolume(device);
+ applyDeviceVolume_syncVSS(device);
}
}
}
@@ -3619,8 +3640,8 @@
mICallback = cb;
}
- // must be called while synchronized on parent VolumeStreamState
- public void mute(boolean state) {
+ // must be called while synchronized VolumeStreamState.class
+ public void mute_syncVSS(boolean state) {
boolean updateVolume = false;
if (state) {
if (mMuteCount == 0) {
@@ -3632,7 +3653,7 @@
}
VolumeStreamState.this.mDeathHandlers.add(this);
// If the stream is not yet muted by any client, set level to 0
- if (!VolumeStreamState.this.isMuted()) {
+ if (!VolumeStreamState.this.isMuted_syncVSS()) {
updateVolume = true;
}
} catch (RemoteException e) {
@@ -3656,7 +3677,7 @@
if (mICallback != null) {
mICallback.unlinkToDeath(this, 0);
}
- if (!VolumeStreamState.this.isMuted()) {
+ if (!VolumeStreamState.this.isMuted_syncVSS()) {
updateVolume = true;
}
}
@@ -3674,15 +3695,17 @@
public void binderDied() {
Log.w(TAG, "Volume service client died for stream: "+mStreamType);
- if (mMuteCount != 0) {
- // Reset all active mute requests from this client.
- mMuteCount = 1;
- mute(false);
+ synchronized (VolumeStreamState.class) {
+ if (mMuteCount != 0) {
+ // Reset all active mute requests from this client.
+ mMuteCount = 1;
+ mute_syncVSS(false);
+ }
}
}
}
- private synchronized int muteCount() {
+ private int muteCount() {
int count = 0;
int size = mDeathHandlers.size();
for (int i = 0; i < size; i++) {
@@ -3691,12 +3714,13 @@
return count;
}
- private synchronized boolean isMuted() {
+ // must be called while synchronized VolumeStreamState.class
+ private boolean isMuted_syncVSS() {
return muteCount() != 0;
}
- // only called by mute() which is already synchronized
- private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
+ // must be called while synchronized VolumeStreamState.class
+ private VolumeDeathHandler getDeathHandler_syncVSS(IBinder cb, boolean state) {
VolumeDeathHandler handler;
int size = mDeathHandlers.size();
for (int i = 0; i < size; i++) {
@@ -3773,25 +3797,26 @@
private void setDeviceVolume(VolumeStreamState streamState, int device) {
- // Apply volume
- streamState.applyDeviceVolume(device);
+ synchronized (VolumeStreamState.class) {
+ // Apply volume
+ streamState.applyDeviceVolume_syncVSS(device);
- // Apply change to all streams using this one as alias
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- if (streamType != streamState.mStreamType &&
- mStreamVolumeAlias[streamType] == streamState.mStreamType) {
- // Make sure volume is also maxed out on A2DP device for aliased stream
- // that may have a different device selected
- int streamDevice = getDeviceForStream(streamType);
- if ((device != streamDevice) && mAvrcpAbsVolSupported &&
- ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
- mStreamStates[streamType].applyDeviceVolume(device);
+ // Apply change to all streams using this one as alias
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ if (streamType != streamState.mStreamType &&
+ mStreamVolumeAlias[streamType] == streamState.mStreamType) {
+ // Make sure volume is also maxed out on A2DP device for aliased stream
+ // that may have a different device selected
+ int streamDevice = getDeviceForStream(streamType);
+ if ((device != streamDevice) && mAvrcpAbsVolSupported &&
+ ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+ mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
+ }
+ mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
}
- mStreamStates[streamType].applyDeviceVolume(streamDevice);
}
}
-
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
@@ -4571,7 +4596,12 @@
if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
- delay = 1000;
+ synchronized (mLastDeviceConnectMsgTime) {
+ long time = SystemClock.uptimeMillis();
+ if (mLastDeviceConnectMsgTime > time) {
+ delay = (int)(mLastDeviceConnectMsgTime - time);
+ }
+ }
}
return delay;
}
@@ -5032,42 +5062,45 @@
boolean cameraSoundForced = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_camera_sound_forced);
synchronized (mSettingsLock) {
+ boolean cameraSoundForcedChanged = false;
synchronized (mCameraSoundForced) {
if (cameraSoundForced != mCameraSoundForced) {
mCameraSoundForced = cameraSoundForced;
-
- if (!isPlatformTelevision()) {
- VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
- if (cameraSoundForced) {
- s.setAllIndexesToMax();
- mRingerModeAffectedStreams &=
- ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- } else {
- s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
- mRingerModeAffectedStreams |=
- (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- }
- // take new state into account for streams muted by ringer mode
- setRingerModeInt(getRingerMode(), false);
- }
-
- sendMsg(mAudioHandler,
- MSG_SET_FORCE_USE,
- SENDMSG_QUEUE,
- AudioSystem.FOR_SYSTEM,
- cameraSoundForced ?
- AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
- null,
- 0);
-
- sendMsg(mAudioHandler,
- MSG_SET_ALL_VOLUMES,
- SENDMSG_QUEUE,
- 0,
- 0,
- mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
+ cameraSoundForcedChanged = true;
}
}
+ if (cameraSoundForcedChanged) {
+ if (!isPlatformTelevision()) {
+ VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
+ if (cameraSoundForced) {
+ s.setAllIndexesToMax();
+ mRingerModeAffectedStreams &=
+ ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
+ mRingerModeAffectedStreams |=
+ (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ }
+ // take new state into account for streams muted by ringer mode
+ setRingerModeInt(getRingerMode(), false);
+ }
+
+ sendMsg(mAudioHandler,
+ MSG_SET_FORCE_USE,
+ SENDMSG_QUEUE,
+ AudioSystem.FOR_SYSTEM,
+ cameraSoundForced ?
+ AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
+ null,
+ 0);
+
+ sendMsg(mAudioHandler,
+ MSG_SET_ALL_VOLUMES,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
+ }
}
mVolumeController.setLayoutDirection(config.getLayoutDirection());
} catch (Exception e) {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 0ca5810..93cca2f 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -159,15 +159,6 @@
}
/**
- * Get the number of callbacks that are registered.
- * @hide
- */
- @VisibleForTesting
- public final int getRegisteredCallbackCount() {
- return mCallbacks.getRegisteredCallbackCount();
- }
-
- /**
* Returns a concrete implementation of {@link Session}.
* <p>
* May return {@code null} if this TV input service fails to create a session for some reason.
@@ -550,13 +541,14 @@
* @param left Left position in pixels, relative to the overlay view.
* @param top Top position in pixels, relative to the overlay view.
* @param right Right position in pixels, relative to the overlay view.
- * @param bottm Bottom position in pixels, relative to the overlay view.
+ * @param bottom Bottom position in pixels, relative to the overlay view.
* @see #onOverlayViewSizeChanged
* @hide
*/
@SystemApi
- public void layoutSurface(final int left, final int top, final int right, final int bottm) {
- if (left > right || top > bottm) {
+ public void layoutSurface(final int left, final int top, final int right,
+ final int bottom) {
+ if (left > right || top > bottom) {
throw new IllegalArgumentException("Invalid parameter");
}
executeOrPostRunnable(new Runnable() {
@@ -564,8 +556,8 @@
public void run() {
try {
if (DEBUG) Log.d(TAG, "layoutSurface (l=" + left + ", t=" + top + ", r="
- + right + ", b=" + bottm + ",)");
- mSessionCallback.onLayoutSurface(left, top, right, bottm);
+ + right + ", b=" + bottom + ",)");
+ mSessionCallback.onLayoutSurface(left, top, right, bottom);
} catch (RemoteException e) {
Log.w(TAG, "error in layoutSurface");
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1c6dc2c..aa5819e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -518,7 +518,7 @@
* Determine whether the device is plugged in (USB, power, or wireless).
* @return true if the device is plugged in.
*/
- boolean isPluggedIn() {
+ public boolean isPluggedIn() {
return plugged == BatteryManager.BATTERY_PLUGGED_AC
|| plugged == BatteryManager.BATTERY_PLUGGED_USB
|| plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml
new file mode 100644
index 0000000..9add90c
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_bottom.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml
new file mode 100644
index 0000000..9add90c
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrow_top.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="567"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml
new file mode 100644
index 0000000..6c4e133
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_arrows.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="scaleX"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleX"
+ android:valueFrom="1"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="scaleY"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleY"
+ android:valueFrom="1"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:interpolator="@interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml
new file mode 100644
index 0000000..a8f5ce0
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_body.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="267"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueTo="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml
new file mode 100644
index 0000000..b9bb42d
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_from_auto_rotate_animation_device.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="-45"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml
new file mode 100644
index 0000000..b8823a9
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_bottom.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml
new file mode 100644
index 0000000..b8823a9
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrow_top.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="33"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml
new file mode 100644
index 0000000..14c2776
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_arrows.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueFrom="0.9"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleX"
+ android:valueFrom="0.9"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueFrom="0.9"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleY"
+ android:valueFrom="0.9"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:valueFrom="-135"
+ android:valueTo="-135"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="450"
+ android:propertyName="rotation"
+ android:valueFrom="-135"
+ android:valueTo="0"
+ android:interpolator="@interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml
new file mode 100644
index 0000000..ea8f979
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_body.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="267"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueTo="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml
new file mode 100644
index 0000000..4e3a356
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_landscape_to_auto_rotate_animation_device.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:valueFrom="-45"
+ android:valueTo="-45"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="-45"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml
new file mode 100644
index 0000000..d05c4e1
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_bottom.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml
new file mode 100644
index 0000000..d05c4e1
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrow_top.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="600"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml
new file mode 100644
index 0000000..8bcbf1e
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_arrows.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="scaleX"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleX"
+ android:valueFrom="1"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="317"
+ android:propertyName="scaleY"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleY"
+ android:valueFrom="1"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="617"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="-221"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml
new file mode 100644
index 0000000..79b1827
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="0"
+ android:valueTo="-135"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml
new file mode 100644
index 0000000..a8f5ce0
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_from_auto_rotate_animation_device_1.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="267"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueTo="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="217"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml
new file mode 100644
index 0000000..c3ae6c1
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_bottom.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml
new file mode 100644
index 0000000..c3ae6c1
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrow_top.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="fillAlpha"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml
new file mode 100644
index 0000000..fde172a
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_arrows.xml
@@ -0,0 +1,63 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleX"
+ android:valueFrom="0.9"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleX"
+ android:valueFrom="0.9"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleY"
+ android:valueFrom="0.9"
+ android:valueTo="0.9"
+ android:interpolator="@android:interpolator/linear" />
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="scaleY"
+ android:valueFrom="0.9"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/linear" />
+ </set>
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="rotation"
+ android:valueFrom="-221"
+ android:valueTo="-221"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="617"
+ android:propertyName="rotation"
+ android:valueFrom="-221"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml
new file mode 100644
index 0000000..accf16d
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="rotation"
+ android:valueFrom="-135"
+ android:valueTo="-135"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="400"
+ android:propertyName="rotation"
+ android:valueFrom="-135"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml
new file mode 100644
index 0000000..15c6705
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_portrait_to_auto_rotate_animation_device_1.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+ <set
+ android:ordering="sequentially" >
+ <objectAnimator
+ android:duration="250"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueTo="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ <objectAnimator
+ android:duration="500"
+ android:propertyName="pathData"
+ android:valueFrom="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:valueTo="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:valueType="pathType"
+ android:interpolator="@android:interpolator/fast_out_slow_in" />
+ </set>
+</set>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml
new file mode 100644
index 0000000..bc545ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate.xml
@@ -0,0 +1,62 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines"
+ android:translateX="24"
+ android:translateY="24" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines_pivot"
+ android:translateX="-24.15"
+ android:translateY="-24.25" >
+ <group
+ android:name="arrows"
+ android:translateX="24.1"
+ android:translateY="24.1" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.1"
+ android:translateY="-24.1" >
+ <path
+ android:name="arrow_top"
+ android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ <path
+ android:name="arrow_bottom"
+ android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ </group>
+ <group
+ android:name="device"
+ android:translateX="24.14999"
+ android:translateY="24.25" >
+ <path
+ android:name="body"
+ android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml
new file mode 100644
index 0000000..400a28b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_landscape_from_auto_rotate_animation.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_landscape_from_auto_rotate" >
+ <target
+ android:name="arrows"
+ android:animation="@anim/ic_landscape_from_auto_rotate_animation_arrows" />
+ <target
+ android:name="arrow_top"
+ android:animation="@anim/ic_landscape_from_auto_rotate_animation_arrow_top" />
+ <target
+ android:name="arrow_bottom"
+ android:animation="@anim/ic_landscape_from_auto_rotate_animation_arrow_bottom" />
+ <target
+ android:name="device"
+ android:animation="@anim/ic_landscape_from_auto_rotate_animation_device" />
+ <target
+ android:name="body"
+ android:animation="@anim/ic_landscape_from_auto_rotate_animation_body" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml
new file mode 100644
index 0000000..0bd75d1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines"
+ android:translateX="24"
+ android:translateY="24" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines_pivot"
+ android:translateX="-24.15"
+ android:translateY="-24.25" >
+ <group
+ android:name="arrows"
+ android:translateX="24.1"
+ android:translateY="24.1"
+ android:scaleX="0.9"
+ android:scaleY="0.9"
+ android:rotation="-135" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.1"
+ android:translateY="-24.1" >
+ <path
+ android:name="arrow_top"
+ android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="0" />
+ <path
+ android:name="arrow_bottom"
+ android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="0" />
+ </group>
+ </group>
+ <group
+ android:name="device"
+ android:translateX="24.14999"
+ android:translateY="24.25"
+ android:rotation="-45" >
+ <path
+ android:name="body"
+ android:pathData="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml
new file mode 100644
index 0000000..5263eb4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_landscape_to_auto_rotate_animation.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_landscape_to_auto_rotate" >
+ <target
+ android:name="arrows"
+ android:animation="@anim/ic_landscape_to_auto_rotate_animation_arrows" />
+ <target
+ android:name="arrow_top"
+ android:animation="@anim/ic_landscape_to_auto_rotate_animation_arrow_top" />
+ <target
+ android:name="arrow_bottom"
+ android:animation="@anim/ic_landscape_to_auto_rotate_animation_arrow_bottom" />
+ <target
+ android:name="device"
+ android:animation="@anim/ic_landscape_to_auto_rotate_animation_device" />
+ <target
+ android:name="body"
+ android:animation="@anim/ic_landscape_to_auto_rotate_animation_body" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml
new file mode 100644
index 0000000..1805a8e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate.xml
@@ -0,0 +1,62 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines"
+ android:translateX="24"
+ android:translateY="24" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines_pivot"
+ android:translateX="-24.15"
+ android:translateY="-24.25" >
+ <group
+ android:name="arrows"
+ android:translateX="24.1"
+ android:translateY="24.1" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.1"
+ android:translateY="-24.1" >
+ <path
+ android:name="arrow_top"
+ android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ <path
+ android:name="arrow_bottom"
+ android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ </group>
+ <group
+ android:name="device"
+ android:translateX="24.14999"
+ android:translateY="24.25" >
+ <path
+ android:name="device_1"
+ android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml
new file mode 100644
index 0000000..565ef26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_portrait_from_auto_rotate_animation.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_portrait_from_auto_rotate" >
+ <target
+ android:name="arrows"
+ android:animation="@anim/ic_portrait_from_auto_rotate_animation_arrows" />
+ <target
+ android:name="arrow_top"
+ android:animation="@anim/ic_portrait_from_auto_rotate_animation_arrow_top" />
+ <target
+ android:name="arrow_bottom"
+ android:animation="@anim/ic_portrait_from_auto_rotate_animation_arrow_bottom" />
+ <target
+ android:name="device"
+ android:animation="@anim/ic_portrait_from_auto_rotate_animation_device" />
+ <target
+ android:name="device_1"
+ android:animation="@anim/ic_portrait_from_auto_rotate_animation_device_1" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml
new file mode 100644
index 0000000..feb3025
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="48dp"
+ android:width="48dp"
+ android:viewportHeight="48"
+ android:viewportWidth="48" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines"
+ android:translateX="24"
+ android:translateY="24" >
+ <group
+ android:name="ic_screen_rotation_48px_outlines_pivot"
+ android:translateX="-24.15"
+ android:translateY="-24.25" >
+ <group
+ android:name="arrows"
+ android:translateX="24.1"
+ android:translateY="24.1"
+ android:scaleX="0.9"
+ android:scaleY="0.9"
+ android:rotation="-221" >
+ <group
+ android:name="arrows_pivot"
+ android:translateX="-24.1"
+ android:translateY="-24.1" >
+ <path
+ android:name="arrow_top"
+ android:pathData="M 33.1499938965,5.25 c 6.5,3.10000610352 11.1999969482,9.40000915527 11.8999938965,17.0 c 0.0,0.0 3.00001525879,0.0 3.00001525879,0.0 c -1.00001525879,-12.3000030518 -11.3000030518,-22.0 -23.9000091553,-22.0 c -0.399993896484,0.0 -0.899993896484,0.0 -1.30000305176,0.100006103516 c 0.0,0.0 7.60000610352,7.59999084473 7.60000610352,7.59999084473 c 0.0,0.0 2.69999694824,-2.69999694824 2.69999694824,-2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="0" />
+ <path
+ android:name="arrow_bottom"
+ android:pathData="M 15.1499938965,43.25 c -6.5,-3.09999084473 -11.1999969482,-9.5 -11.8999938965,-17.0 c 0.0,0.0 -3.0,0.0 -3.0,0.0 c 1.0,12.3000030518 11.299987793,22.0 23.8999938965,22.0 c 0.399993896484,0.0 0.899993896484,0.0 1.30000305176,-0.0999908447266 c 0.0,0.0 -7.60000610352,-7.60000610352 -7.60000610352,-7.60000610352 c 0.0,0.0 -2.69999694824,2.69999694824 -2.69999694824,2.69999694824 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="0" />
+ </group>
+ </group>
+ <group
+ android:name="device"
+ android:translateX="24.14999"
+ android:translateY="24.25"
+ android:rotation="-135" >
+ <path
+ android:name="device_1"
+ android:pathData="M -3.34053039551,-22.9980926514 c -1.3207244873,-1.3207244873 -3.46876525879,-1.26383972168 -4.74829101563,0.125762939453 c 0.0,0.0 -14.8512420654,14.7411804199 -14.8512420654,14.7411804199 c -1.39259338379,1.392578125 -1.44947814941,3.54061889648 -0.125762939453,4.74827575684 c 0.0,0.0 26.4143981934,26.4144134521 26.4143981934,26.4144134521 c 1.3207244873,1.3207244873 3.46876525879,1.26382446289 4.74829101562,-0.125762939453 c 0.0,0.0 14.7381896973,-14.7381896973 14.7381896973,-14.7381896973 c 1.392578125,-1.39259338379 1.44947814941,-3.54061889648 0.125762939453,-4.74829101562 c 0.0,0.0 -26.3013458252,-26.417388916 -26.3013458252,-26.417388916 Z M 2.87156677246,16.9857940674 c 0.0,0.0 -19.7573547363,-19.7573699951 -19.7573547363,-19.7573699951 c 0.0,0.0 14.0142059326,-14.2142181396 14.0142059326,-14.2142181396 c 0.0,0.0 19.7573699951,19.7573699951 19.7573699951,19.7573699951 c 0.0,0.0 -14.0142211914,14.2142181396 -14.0142211914,14.2142181396 Z"
+ android:fillColor="#FFFFFFFF"
+ android:fillAlpha="1" />
+ </group>
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml
new file mode 100644
index 0000000..f75617f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_portrait_to_auto_rotate_animation.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/ic_portrait_to_auto_rotate" >
+ <target
+ android:name="arrows"
+ android:animation="@anim/ic_portrait_to_auto_rotate_animation_arrows" />
+ <target
+ android:name="arrow_top"
+ android:animation="@anim/ic_portrait_to_auto_rotate_animation_arrow_top" />
+ <target
+ android:name="arrow_bottom"
+ android:animation="@anim/ic_portrait_to_auto_rotate_animation_arrow_bottom" />
+ <target
+ android:name="device"
+ android:animation="@anim/ic_portrait_to_auto_rotate_animation_device" />
+ <target
+ android:name="device_1"
+ android:animation="@anim/ic_portrait_to_auto_rotate_animation_device_1" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml
deleted file mode 100644
index 4bb3668..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_rotation_landscape.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.0,14.0l0.0,20.0c0.0,2.2 1.8,4.0 4.0,4.0l36.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,14.0c0.0,-2.2 -1.8,-4.0 -4.0,-4.0L6.0,10.0C3.8,10.0 2.0,11.8 2.0,14.0zM38.0,14.0l0.0,20.0L10.0,34.0L10.0,14.0L38.0,14.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml
deleted file mode 100644
index f0878c7..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_rotation_portrait.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M34.0,2.0L14.0,2.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,36.0c0.0,2.2 1.8,4.0 4.0,4.0l20.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L38.0,6.0C38.0,3.8 36.2,2.0 34.0,2.0zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0L34.0,38.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
deleted file mode 100644
index 94b3a6b..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="64dp"
- android:height="64dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M16.600000,2.500000c3.300000,1.500000 5.600000,4.700000 6.000000,8.500000l1.500000,0.000000c-0.600000,-6.200000 -5.700000,-11.000000 -12.000000,-11.000000c-0.200000,0.000000 -0.400000,0.000000 -0.700000,0.000000l3.800000,3.800000L16.600000,2.500000zM10.300000,1.700000c-0.600000,-0.600000 -1.500000,-0.600000 -2.100000,0.000000L1.800000,8.100000c-0.600000,0.600000 -0.600000,1.500000 0.000000,2.100000l12.000000,12.000000c0.600000,0.600000 1.500000,0.600000 2.100000,0.000000l6.400000,-6.400000c0.600000,-0.600000 0.600000,-1.500000 0.000000,-2.100000L10.300000,1.700000zM13.400000,19.700001l-9.200000,-9.200000l6.400000,-6.400000l9.200000,9.200000L13.400000,19.700001zM7.600000,21.500000C4.300000,20.000000 2.000000,16.799999 1.600000,13.000000L0.200000,13.000000c0.500000,6.200000 5.600000,11.000000 11.900000,11.000000c0.200000,0.000000 0.400000,0.000000 0.700000,0.000000L9.000000,20.200001L7.600000,21.500000z"/>
-</vector>
diff --git a/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml b/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml
new file mode 100644
index 0000000..76f5667
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/ic_landscape_from_auto_rotate_arrows_rotation_interpolator.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0,0 c 0.458031162,0 0.299442342,0.748308635 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml b/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml
new file mode 100644
index 0000000..ac27e4d
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/ic_landscape_to_auto_rotate_arrows_rotation_interpolator.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:pathData="M 0,0 c 0.4,0.143709151 0.2,1 1,1" />
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 4e93cd8..4a9eb55 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -35,5 +35,6 @@
<item type="id" name="top_inset_animator_start_value_tag"/>
<item type="id" name="height_animator_start_value_tag"/>
<item type="id" name="doze_saved_filter_tag"/>
+ <item type="id" name="qs_icon_tag"/>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 54a8414..1ddd352 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -203,7 +203,7 @@
}
}
- private void refreshAllTiles() {
+ public void refreshAllTiles() {
for (TileRecord r : mRecords) {
r.tile.refreshState();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 6ef6e9e..2a66484 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -18,11 +18,13 @@
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
+import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
@@ -299,10 +301,91 @@
}
}
+ public static abstract class Icon {
+ abstract public Drawable getDrawable(Context context);
+
+ @Override
+ public int hashCode() {
+ return Icon.class.hashCode();
+ }
+ }
+
+ public static class ResourceIcon extends Icon {
+ private static final SparseArray<Icon> ICONS = new SparseArray<Icon>();
+
+ private final int mResId;
+
+ private ResourceIcon(int resId) {
+ mResId = resId;
+ }
+
+ public static Icon get(int resId) {
+ Icon icon = ICONS.get(resId);
+ if (icon == null) {
+ icon = new ResourceIcon(resId);
+ ICONS.put(resId, icon);
+ }
+ return icon;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ return context.getDrawable(mResId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof ResourceIcon && ((ResourceIcon) o).mResId == mResId;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ResourceIcon[resId=0x%08x]", mResId);
+ }
+ }
+
+ protected class AnimationIcon extends ResourceIcon {
+ private boolean mAllowAnimation;
+
+ public AnimationIcon(int resId) {
+ super(resId);
+ }
+
+ public void setAllowAnimation(boolean allowAnimation) {
+ mAllowAnimation = allowAnimation;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ // workaround: get a clean state for every new AVD
+ final AnimatedVectorDrawable d = (AnimatedVectorDrawable) super.getDrawable(context)
+ .getConstantState().newDrawable();
+ d.start();
+ if (mAllowAnimation) {
+ mAllowAnimation = false;
+ } else {
+ d.stop(); // skip directly to end state
+ }
+ return d;
+ }
+ }
+
+ protected enum UserBoolean {
+ USER_TRUE(true, true),
+ USER_FALSE(true, false),
+ BACKGROUND_TRUE(false, true),
+ BACKGROUND_FALSE(false, false);
+ public final boolean value;
+ public final boolean userInitiated;
+ private UserBoolean(boolean userInitiated, boolean value) {
+ this.value = value;
+ this.userInitiated = userInitiated;
+ }
+ }
+
public static class State {
public boolean visible;
- public int iconId;
- public Drawable icon;
+ public Icon icon;
public String label;
public String contentDescription;
public String dualLabelContentDescription;
@@ -312,7 +395,6 @@
if (other == null) throw new IllegalArgumentException();
if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
final boolean changed = other.visible != visible
- || other.iconId != iconId
|| !Objects.equals(other.icon, icon)
|| !Objects.equals(other.label, label)
|| !Objects.equals(other.contentDescription, contentDescription)
@@ -320,7 +402,6 @@
|| !Objects.equals(other.dualLabelContentDescription,
dualLabelContentDescription);
other.visible = visible;
- other.iconId = iconId;
other.icon = icon;
other.label = label;
other.contentDescription = contentDescription;
@@ -335,9 +416,8 @@
}
protected StringBuilder toStringBuilder() {
- final StringBuilder sb = new StringBuilder( getClass().getSimpleName()).append('[');
+ final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
sb.append("visible=").append(visible);
- sb.append(",iconId=").append(iconId);
sb.append(",icon=").append(icon);
sb.append(",label=").append(label);
sb.append(",contentDescription=").append(contentDescription);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index d5c90d0..3d0f47c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -21,6 +21,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Typeface;
+import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Handler;
@@ -39,6 +40,8 @@
import com.android.systemui.R;
import com.android.systemui.qs.QSTile.State;
+import java.util.Objects;
+
/** View that represents a standard quick settings tile. **/
public class QSTileView extends ViewGroup {
private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
@@ -60,6 +63,7 @@
private boolean mDual;
private OnClickListener mClickPrimary;
private OnClickListener mClickSecondary;
+ private Drawable mTileBackground;
private RippleDrawable mRipple;
public QSTileView(Context context) {
@@ -72,6 +76,7 @@
mTilePaddingBelowIconPx = res.getDimensionPixelSize(R.dimen.qs_tile_padding_below_icon);
mDualTileVerticalPaddingPx =
res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
+ mTileBackground = newTileBackground();
recreateLabel();
setClipChildren(false);
@@ -172,22 +177,21 @@
if (changed) {
recreateLabel();
}
- Drawable tileBackground = getTileBackground();
- if (tileBackground instanceof RippleDrawable) {
- setRipple((RippleDrawable) tileBackground);
+ if (mTileBackground instanceof RippleDrawable) {
+ setRipple((RippleDrawable) mTileBackground);
}
if (dual) {
mTopBackgroundView.setOnClickListener(mClickPrimary);
setOnClickListener(null);
setClickable(false);
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
- mTopBackgroundView.setBackground(tileBackground);
+ mTopBackgroundView.setBackground(mTileBackground);
} else {
mTopBackgroundView.setOnClickListener(null);
mTopBackgroundView.setClickable(false);
setOnClickListener(mClickPrimary);
setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- setBackground(tileBackground);
+ setBackground(mTileBackground);
}
mTopBackgroundView.setFocusable(dual);
setFocusable(!dual);
@@ -214,7 +218,7 @@
return icon;
}
- private Drawable getTileBackground() {
+ private Drawable newTileBackground() {
final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless };
final TypedArray ta = mContext.obtainStyledAttributes(attrs);
final Drawable d = ta.getDrawable(0);
@@ -285,16 +289,7 @@
protected void handleStateChanged(QSTile.State state) {
if (mIcon instanceof ImageView) {
- ImageView iv = (ImageView) mIcon;
- if (state.icon != null) {
- iv.setImageDrawable(state.icon);
- } else if (state.iconId > 0) {
- iv.setImageResource(state.iconId);
- }
- Drawable drawable = iv.getDrawable();
- if (state.autoMirrorDrawable && drawable != null) {
- drawable.setAutoMirrored(true);
- }
+ setIcon((ImageView) mIcon, state);
}
if (mDual) {
mDualLabel.setText(state.label);
@@ -306,6 +301,22 @@
}
}
+ protected void setIcon(ImageView iv, QSTile.State state) {
+ if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
+ Drawable d = state.icon != null ? state.icon.getDrawable(mContext) : null;
+ if (d != null && state.autoMirrorDrawable) {
+ d.setAutoMirrored(true);
+ }
+ iv.setImageDrawable(d);
+ iv.setTag(R.id.qs_icon_tag, state.icon);
+ if (d instanceof Animatable) {
+ if (!iv.isShown()) {
+ ((Animatable) d).stop(); // skip directly to end state
+ }
+ }
+ }
+ }
+
public void onStateChanged(QSTile.State state) {
mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index cfcd74e..9ac7944 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -104,7 +104,7 @@
protected void handleStateChanged(QSTile.State state) {
super.handleStateChanged(state);
final SignalState s = (SignalState) state;
- mSignal.setImageResource(s.iconId);
+ setIcon(mSignal, s);
if (s.overlayIconId > 0) {
mOverlay.setVisibility(VISIBLE);
mOverlay.setImageResource(s.overlayIconId);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 51401c8..cd44a2b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -68,11 +68,11 @@
state.visible = true;
state.label = mContext.getString(R.string.quick_settings_airplane_mode_label);
if (airplaneMode) {
- state.iconId = R.drawable.ic_qs_airplane_on;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_airplane_on);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_airplane_on);
} else {
- state.iconId = R.drawable.ic_qs_airplane_off;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_airplane_off);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_airplane_off);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 84bfb8f..4d77348 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -92,17 +92,17 @@
if (enabled) {
state.label = null;
if (connected) {
- state.iconId = R.drawable.ic_qs_bluetooth_connected;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_connected);
state.label = mController.getLastDeviceName();
} else if (connecting) {
- state.iconId = R.drawable.ic_qs_bluetooth_connecting;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connecting);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_connecting);
state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
} else {
- state.iconId = R.drawable.ic_qs_bluetooth_on;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_on);
}
@@ -110,7 +110,7 @@
state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
}
} else {
- state.iconId = R.drawable.ic_qs_bluetooth_off;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_bluetooth_off);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 8304291..5bf6fb5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -107,7 +107,8 @@
if (!state.value && connecting) {
state.label = mContext.getString(R.string.quick_settings_connecting);
}
- state.iconId = state.value ? R.drawable.ic_qs_cast_on : R.drawable.ic_qs_cast_off;
+ state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
+ : R.drawable.ic_qs_cast_off);
mDetailAdapter.updateItems(devices);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 359a259..178590b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -87,16 +87,17 @@
if (cb == null) return;
final Resources r = mContext.getResources();
- state.iconId = cb.noSim ? R.drawable.ic_qs_no_sim
+ final int iconId = cb.noSim ? R.drawable.ic_qs_no_sim
: !cb.enabled || cb.airplaneModeEnabled ? R.drawable.ic_qs_signal_disabled
: cb.mobileSignalIconId > 0 ? cb.mobileSignalIconId
: R.drawable.ic_qs_signal_no_signal;
+ state.icon = ResourceIcon.get(iconId);
state.isOverlayIconWide = cb.isDataTypeIconWide;
state.autoMirrorDrawable = !cb.noSim;
state.overlayIconId = cb.enabled && (cb.dataTypeIconId > 0) && !cb.wifiConnected
? cb.dataTypeIconId
: 0;
- state.filter = state.iconId != R.drawable.ic_qs_no_sim;
+ state.filter = iconId != R.drawable.ic_qs_no_sim;
state.activityIn = cb.enabled && cb.activityIn;
state.activityOut = cb.enabled && cb.activityOut;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 7ba1dc0..b24f8bf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -88,7 +88,8 @@
state.visible = enabled || mUsageTracker.isRecentlyUsed();
state.value = enabled;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
- state.iconId = enabled ? R.drawable.ic_qs_inversion_on : R.drawable.ic_qs_inversion_off;
+ state.icon = ResourceIcon.get(enabled ? R.drawable.ic_qs_inversion_on
+ : R.drawable.ic_qs_inversion_off);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index e6b7f02..055a6b7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -92,8 +92,8 @@
// the camera is not available while it is being used for the flashlight.
state.visible = mWasLastOn != 0 || mFlashlightController.isAvailable();
state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
- state.iconId = state.value
- ? R.drawable.ic_qs_flashlight_on : R.drawable.ic_qs_flashlight_off;
+ state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_flashlight_on
+ : R.drawable.ic_qs_flashlight_off);
int onOrOffId = state.value
? R.string.accessibility_quick_settings_flashlight_on
: R.string.accessibility_quick_settings_flashlight_off;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index b30a1d3..64dab85 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -71,8 +71,8 @@
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
state.value = mController.isHotspotEnabled();
- state.iconId = state.visible && state.value ? R.drawable.ic_qs_hotspot_on
- : R.drawable.ic_qs_hotspot_off;
+ state.icon = ResourceIcon.get(state.visible && state.value ? R.drawable.ic_qs_hotspot_on
+ : R.drawable.ic_qs_hotspot_off);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index 58587e6..6fb9cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -31,6 +31,9 @@
import com.android.systemui.qs.QSTile;
+import java.util.Arrays;
+import java.util.Objects;
+
public class IntentTile extends QSTile<QSTile.State> {
public static final String PREFIX = "intent(";
@@ -96,13 +99,11 @@
state.visible = intent.getBooleanExtra("visible", true);
state.contentDescription = intent.getStringExtra("contentDescription");
state.label = intent.getStringExtra("label");
- state.iconId = 0;
state.icon = null;
final byte[] iconBitmap = intent.getByteArrayExtra("iconBitmap");
if (iconBitmap != null) {
try {
- final Bitmap b = BitmapFactory.decodeByteArray(iconBitmap, 0, iconBitmap.length);
- state.icon = new BitmapDrawable(mContext.getResources(), b);
+ state.icon = new BytesIcon(iconBitmap);
} catch (Throwable t) {
Log.w(TAG, "Error loading icon bitmap, length " + iconBitmap.length, t);
}
@@ -111,9 +112,9 @@
if (iconId != 0) {
final String iconPackage = intent.getStringExtra("iconPackage");
if (!TextUtils.isEmpty(iconPackage)) {
- state.icon = getPackageDrawable(iconPackage, iconId);
+ state.icon = new PackageDrawableIcon(iconPackage, iconId);
} else {
- state.iconId = iconId;
+ state.icon = ResourceIcon.get(iconId);
}
}
}
@@ -121,19 +122,66 @@
mOnClickUri = intent.getStringExtra("onClickUri");
}
- private Drawable getPackageDrawable(String pkg, int id) {
- try {
- return mContext.createPackageContext(pkg, 0).getDrawable(id);
- } catch (Throwable t) {
- Log.w(TAG, "Error loading package drawable pkg=" + pkg + " id=" + id, t);
- return null;
- }
- }
-
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
refreshState(intent);
}
};
+
+ private static class BytesIcon extends Icon {
+ private final byte[] mBytes;
+
+ public BytesIcon(byte[] bytes) {
+ mBytes = bytes;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ final Bitmap b = BitmapFactory.decodeByteArray(mBytes, 0, mBytes.length);
+ return new BitmapDrawable(context.getResources(), b);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof BytesIcon && Arrays.equals(((BytesIcon) o).mBytes, mBytes);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("BytesIcon[len=%s]", mBytes.length);
+ }
+ }
+
+ private class PackageDrawableIcon extends Icon {
+ private final String mPackage;
+ private final int mResId;
+
+ public PackageDrawableIcon(String pkg, int resId) {
+ mPackage = pkg;
+ mResId = resId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof PackageDrawableIcon)) return false;
+ final PackageDrawableIcon other = (PackageDrawableIcon) o;
+ return Objects.equals(other.mPackage, mPackage) && other.mResId == mResId;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ try {
+ return context.createPackageContext(mPackage, 0).getDrawable(mResId);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error loading package drawable pkg=" + mPackage + " id=" + mResId, t);
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PackageDrawableIcon[pkg=%s,id=0x%08x]", mPackage, mResId);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index d1dc5d2..81741ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -67,12 +67,12 @@
state.visible = !mKeyguard.isShowing();
state.value = locationEnabled;
if (locationEnabled) {
- state.iconId = R.drawable.ic_qs_location_on;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_location_on);
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location_on);
} else {
- state.iconId = R.drawable.ic_qs_location_off;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_location_off);
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_location_off);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index ae40a4d..49cd14a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -17,7 +17,6 @@
package com.android.systemui.qs.tiles;
import android.content.res.Configuration;
-import android.content.res.Resources;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
@@ -26,6 +25,15 @@
/** Quick settings tile: Rotation **/
public class RotationLockTile extends QSTile<QSTile.BooleanState> {
+ private final AnimationIcon PORTRAIT_TO_AUTO
+ = new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation);
+ private final AnimationIcon AUTO_TO_PORTRAIT
+ = new AnimationIcon(R.drawable.ic_portrait_from_auto_rotate_animation);
+
+ private final AnimationIcon LANDSCAPE_TO_AUTO
+ = new AnimationIcon(R.drawable.ic_landscape_to_auto_rotate_animation);
+ private final AnimationIcon AUTO_TO_LANDSCAPE
+ = new AnimationIcon(R.drawable.ic_landscape_from_auto_rotate_animation);
private final RotationLockController mController;
@@ -51,30 +59,34 @@
@Override
protected void handleClick() {
if (mController == null) return;
- mController.setRotationLocked(!mState.value);
+ final boolean newState = !mState.value;
+ mController.setRotationLocked(newState);
+ refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
if (mController == null) return;
- final boolean rotationLocked = mController.isRotationLocked();
+ final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value
+ : mController.isRotationLocked();
+ final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
state.visible = mController.isRotationLockAffordanceVisible();
- final Resources res = mContext.getResources();
state.value = rotationLocked;
+ final boolean portrait = mContext.getResources().getConfiguration().orientation
+ != Configuration.ORIENTATION_LANDSCAPE;
+ final AnimationIcon icon;
if (rotationLocked) {
- final boolean portrait = res.getConfiguration().orientation
- != Configuration.ORIENTATION_LANDSCAPE;
final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
: R.string.quick_settings_rotation_locked_landscape_label;
- final int icon = portrait ? R.drawable.ic_qs_rotation_portrait
- : R.drawable.ic_qs_rotation_landscape;
state.label = mContext.getString(label);
- state.icon = mContext.getDrawable(icon);
+ icon = portrait ? AUTO_TO_PORTRAIT : AUTO_TO_LANDSCAPE;
} else {
state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
- state.icon = res.getDrawable(R.drawable.ic_qs_rotation_unlocked);
+ icon = portrait ? PORTRAIT_TO_AUTO : LANDSCAPE_TO_AUTO;
}
- state.contentDescription = getAccessibilityString(
+ icon.setAllowAnimation(userInitiated);
+ state.icon = icon;
+ state.contentDescription = getAccessibilityString(rotationLocked,
R.string.accessibility_rotation_lock_on_portrait,
R.string.accessibility_rotation_lock_on_landscape,
R.string.accessibility_rotation_lock_off);
@@ -83,14 +95,16 @@
/**
* Get the correct accessibility string based on the state
*
+ * @param locked Whether or not rotation is locked.
* @param idWhenPortrait The id which should be used when locked in portrait.
* @param idWhenLandscape The id which should be used when locked in landscape.
* @param idWhenOff The id which should be used when the rotation lock is off.
* @return
*/
- private String getAccessibilityString(int idWhenPortrait, int idWhenLandscape, int idWhenOff) {
+ private String getAccessibilityString(boolean locked, int idWhenPortrait, int idWhenLandscape,
+ int idWhenOff) {
int stringID;
- if (mState.value) {
+ if (locked) {
final boolean portrait = mContext.getResources().getConfiguration().orientation
!= Configuration.ORIENTATION_LANDSCAPE;
stringID = portrait ? idWhenPortrait: idWhenLandscape;
@@ -102,7 +116,7 @@
@Override
protected String composeChangeAnnouncement() {
- return getAccessibilityString(
+ return getAccessibilityString(mState.value,
R.string.accessibility_rotation_lock_on_portrait_changed,
R.string.accessibility_rotation_lock_on_landscape_changed,
R.string.accessibility_rotation_lock_off_changed);
@@ -111,7 +125,8 @@
private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
@Override
public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
- refreshState();
+ refreshState(rotationLocked ? UserBoolean.BACKGROUND_TRUE
+ : UserBoolean.BACKGROUND_FALSE);
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 20c4ee8..7aa884e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -120,19 +120,19 @@
final String signalContentDescription;
final Resources r = mContext.getResources();
if (!state.enabled) {
- state.iconId = R.drawable.ic_qs_wifi_disabled;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled);
state.label = r.getString(R.string.quick_settings_wifi_label);
signalContentDescription = r.getString(R.string.accessibility_wifi_off);
} else if (wifiConnected) {
- state.iconId = cb.wifiSignalIconId;
+ state.icon = ResourceIcon.get(cb.wifiSignalIconId);
state.label = removeDoubleQuotes(cb.enabledDesc);
signalContentDescription = cb.wifiSignalContentDescription;
} else if (wifiNotConnected) {
- state.iconId = R.drawable.ic_qs_wifi_0;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_0);
state.label = r.getString(R.string.quick_settings_wifi_label);
signalContentDescription = r.getString(R.string.accessibility_no_wifi);
} else {
- state.iconId = R.drawable.ic_qs_wifi_no_network;
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_no_network);
state.label = r.getString(R.string.quick_settings_wifi_label);
signalContentDescription = r.getString(R.string.accessibility_wifi_off);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 2a782cc..4c3460e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -728,7 +728,7 @@
final ActivityManager am = (ActivityManager)
getContext().getSystemService(Context.ACTIVITY_SERVICE);
if (am != null) {
- am.removeTask(ad.persistentTaskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ am.removeTask(ad.persistentTaskId);
// Accessibility feedback
setContentDescription(
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 71a3ef1..b661385 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -291,18 +291,18 @@
}
}
- /** Removes the task and kills the process */
- public void removeTask(int taskId, boolean isDocument) {
+ /** Removes the task */
+ public void removeTask(int taskId) {
if (mAm == null) return;
if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
- // Remove the task, and only kill the process if it is not a document
- mAm.removeTask(taskId, isDocument ? 0 : ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ // Remove the task.
+ mAm.removeTask(taskId);
}
/**
* Returns the activity info for a given component name.
- *
+ *
* @param cn The component name of the activity.
* @param userId The userId of the user that this is for.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index a0dee07..e1179fa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents.misc;
import android.animation.Animator;
-import android.content.Intent;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
@@ -184,12 +183,6 @@
sPropertyMethod.invoke(null, property, value);
}
- /** Returns whether the specified intent is a document. */
- public static boolean isDocument(Intent intent) {
- int flags = intent.getFlags();
- return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
- }
-
/**
* Cancels an animation ensuring that if it has listeners, onCancel and onEnd
* are not called.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 6b0d306..ff0330d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -34,7 +34,6 @@
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.RecentsPackageMonitor;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -522,8 +521,7 @@
loader.deleteTaskData(t, false);
// Remove the old task from activity manager
- RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id,
- Utilities.isDocument(t.key.baseIntent));
+ RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ce35e4b..992aa9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -162,8 +162,9 @@
KeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() {
@Override
public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
- mPowerPluggedIn = status.status == BatteryManager.BATTERY_STATUS_CHARGING
+ boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
|| status.status == BatteryManager.BATTERY_STATUS_FULL;
+ mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
mPowerCharged = status.isCharged();
updateIndication();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 32fb567..e89e15d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -45,6 +45,7 @@
public static final int MODE_LIGHTS_OUT = 3;
public static final int MODE_TRANSPARENT = 4;
public static final int MODE_WARNING = 5;
+ public static final int MODE_LIGHTS_OUT_TRANSPARENT = 6;
public static final int LIGHTS_IN_DURATION = 250;
public static final int LIGHTS_OUT_DURATION = 750;
@@ -75,6 +76,9 @@
|| mode == MODE_TRANSPARENT)) {
mode = MODE_OPAQUE;
}
+ if (!HIGH_END && (mode == MODE_LIGHTS_OUT_TRANSPARENT)) {
+ mode = MODE_LIGHTS_OUT;
+ }
if (mMode == mode) return;
int oldMode = mMode;
mMode = mode;
@@ -102,6 +106,7 @@
if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
if (mode == MODE_WARNING) return "MODE_WARNING";
+ if (mode == MODE_LIGHTS_OUT_TRANSPARENT) return "MODE_LIGHTS_OUT_TRANSPARENT";
throw new IllegalArgumentException("Unknown mode " + mode);
}
@@ -109,6 +114,10 @@
mBarBackground.finishAnimation();
}
+ protected boolean isLightsOut(int mode) {
+ return mode == MODE_LIGHTS_OUT || mode == MODE_LIGHTS_OUT_TRANSPARENT;
+ }
+
private static class BarBackgroundDrawable extends Drawable {
private final int mOpaque;
private final int mSemiTransparent;
@@ -196,7 +205,7 @@
targetColor = mSemiTransparent;
} else if (mMode == MODE_SEMI_TRANSPARENT) {
targetColor = mSemiTransparent;
- } else if (mMode == MODE_TRANSPARENT) {
+ } else if (mMode == MODE_TRANSPARENT || mMode == MODE_LIGHTS_OUT_TRANSPARENT) {
targetColor = mTransparent;
} else {
targetColor = mOpaque;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 052b6c6..15f6dc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -84,7 +84,7 @@
applyBackButtonQuiescentAlpha(mode, animate);
// apply to lights out
- applyLightsOut(mode == MODE_LIGHTS_OUT, animate, force);
+ applyLightsOut(isLightsOut(mode), animate, force);
}
private float alphaForMode(int mode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index d9e44c3..bb992b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -291,8 +291,8 @@
} else {
setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
mNotificationStackScroller.setStackHeight(getExpandedHeight());
- updateHeader();
}
+ updateHeader();
mNotificationStackScroller.updateIsSmallScreen(
mHeader.getCollapsedHeight() + mQsPeekHeight);
}
@@ -1329,6 +1329,16 @@
float notificationHeight = mNotificationStackScroller.getHeight()
- mNotificationStackScroller.getEmptyBottomMargin()
- mNotificationStackScroller.getTopPadding();
+
+ // When only empty shade view is visible in QS collapsed state, simulate that we would have
+ // it in expanded QS state as well so we don't run into troubles when fading the view in/out
+ // and expanding/collapsing the whole panel from/to quick settings.
+ if (mNotificationStackScroller.getNotGoneChildCount() == 0
+ && mShadeEmpty) {
+ notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
+ + mNotificationStackScroller.getBottomStackPeekSize()
+ + mNotificationStackScroller.getCollapseSecondCardPadding();
+ }
float totalHeight = Math.max(
mQsMaxExpansionHeight + mNotificationStackScroller.getNotificationTopPadding(),
mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index fc7081b..142791d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -23,6 +23,7 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
@@ -2600,8 +2601,10 @@
}
private int barMode(int vis, int transientFlag, int translucentFlag) {
+ int lightsOutTransparent = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_TRANSPARENT;
return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
: (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
+ : (vis & lightsOutTransparent) == lightsOutTransparent ? MODE_LIGHTS_OUT_TRANSPARENT
: (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT
: (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
: MODE_OPAQUE;
@@ -3597,6 +3600,12 @@
instantCollapseNotificationPanel();
}
updateKeyguardState(staying, false /* fromShadeLocked */);
+
+ // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
+ // visibilities so next time we open the panel we know the correct height already.
+ if (mQSPanel != null) {
+ mQSPanel.refreshAllTiles();
+ }
return staying;
}
@@ -3630,9 +3639,7 @@
}
private void updatePublicMode() {
- setLockscreenPublicMode(
- (mStatusBarKeyguardViewManager.isShowing() ||
- mStatusBarKeyguardViewManager.isOccluded())
+ setLockscreenPublicMode(mStatusBarKeyguardViewManager.isShowing()
&& mStatusBarKeyguardViewManager.isSecure());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index 8520f40..fb1addf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -57,19 +57,19 @@
}
private float getNonBatteryClockAlphaFor(int mode) {
- return mode == MODE_LIGHTS_OUT ? ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK
+ return isLightsOut(mode) ? ICON_ALPHA_WHEN_LIGHTS_OUT_NON_BATTERY_CLOCK
: !isOpaque(mode) ? ICON_ALPHA_WHEN_NOT_OPAQUE
: mIconAlphaWhenOpaque;
}
private float getBatteryClockAlpha(int mode) {
- return mode == MODE_LIGHTS_OUT ? ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK
+ return isLightsOut(mode) ? ICON_ALPHA_WHEN_LIGHTS_OUT_BATTERY_CLOCK
: getNonBatteryClockAlphaFor(mode);
}
private boolean isOpaque(int mode) {
return !(mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
- || mode == MODE_TRANSPARENT);
+ || mode == MODE_TRANSPARENT || mode == MODE_LIGHTS_OUT_TRANSPARENT);
}
@Override
@@ -94,7 +94,7 @@
animateTransitionTo(mBattery, newAlphaBC),
animateTransitionTo(mClock, newAlphaBC)
);
- if (mode == MODE_LIGHTS_OUT) {
+ if (isLightsOut(mode)) {
anims.setDuration(LIGHTS_OUT_DURATION);
}
anims.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index a4db46a..45a1386 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -21,6 +21,7 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.Process;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -108,7 +109,8 @@
mKeyguard = keyguard;
mSecurity = security;
- final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName());
+ final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
+ Process.THREAD_PRIORITY_BACKGROUND);
ht.start();
mLooper = ht.getLooper();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 87ce565..d543cff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2272,6 +2272,10 @@
return height;
}
+ public int getEmptyShadeViewHeight() {
+ return mEmptyShadeView.getHeight();
+ }
+
public float getBottomMostNotificationBottom() {
final int count = getChildCount();
float max = 0;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index bf5cdff..b516f00 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -116,6 +116,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
+import java.util.List;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -2299,24 +2300,19 @@
boolean goingToNotificationShade) {
if (goingToNotificationShade) {
return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in);
- } else if (onWallpaper) {
- Animation a = AnimationUtils.loadAnimation(mContext,
- R.anim.lock_screen_behind_enter_wallpaper);
- AnimationSet set = (AnimationSet) a;
-
- // TODO: Use XML interpolators when we have log interpolators available in XML.
- set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator);
- set.getAnimations().get(1).setInterpolator(mLogDecelerateInterpolator);
- return set;
- } else {
- Animation a = AnimationUtils.loadAnimation(mContext,
- R.anim.lock_screen_behind_enter);
- AnimationSet set = (AnimationSet) a;
-
- // TODO: Use XML interpolators when we have log interpolators available in XML.
- set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator);
- return set;
}
+
+ AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(mContext, onWallpaper ?
+ R.anim.lock_screen_behind_enter_wallpaper :
+ R.anim.lock_screen_behind_enter);
+
+ // TODO: Use XML interpolators when we have log interpolators available in XML.
+ final List<Animation> animations = set.getAnimations();
+ for (int i = animations.size() - 1; i >= 0; --i) {
+ animations.get(i).setInterpolator(mLogDecelerateInterpolator);
+ }
+
+ return set;
}
@@ -4767,18 +4763,39 @@
@Override
public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
if ((policyFlags & FLAG_WAKE) != 0) {
- wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion);
- return 0;
+ if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion)) {
+ return 0;
+ }
}
+
if (shouldDispatchInputWhenNonInteractive()) {
return ACTION_PASS_TO_USER;
}
+
return 0;
}
private boolean shouldDispatchInputWhenNonInteractive() {
- return keyguardIsShowingTq() && mDisplay != null &&
- mDisplay.getState() != Display.STATE_OFF;
+ // Send events to keyguard while the screen is on.
+ if (keyguardIsShowingTq() && mDisplay != null && mDisplay.getState() != Display.STATE_OFF) {
+ return true;
+ }
+
+ // Send events to a dozing dream even if the screen is off since the dream
+ // is in control of the state of the screen.
+ IDreamManager dreamManager = getDreamManager();
+
+ try {
+ if (dreamManager != null && dreamManager.isDreaming()) {
+ return true;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException when checking if dreaming", e);
+ }
+
+ // Otherwise, consume events since the user can't see what is being
+ // interacted with.
+ return false;
}
void dispatchMediaKeyWithWakeLock(KeyEvent event) {
@@ -4949,12 +4966,13 @@
wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
}
- private void wakeUp(long wakeTime, boolean wakeInTheaterMode) {
+ private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) {
if (!wakeInTheaterMode && isTheaterModeEnabled()) {
- return;
+ return false;
}
mPowerManager.wakeUp(wakeTime);
+ return true;
}
// Called on the PowerManager's Notifier thread.
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index b708c3f..11ba8e8 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -18,49 +18,38 @@
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
import static android.content.Context.USER_SERVICE;
import static android.Manifest.permission.READ_PROFILE;
-import android.database.Cursor;
+
import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
-import android.os.Environment;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.storage.IMountService;
import android.os.ServiceManager;
-import android.os.storage.StorageManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
-import android.security.KeyChain;
-import android.security.KeyChain.KeyChainConnection;
import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.ILockSettingsObserver;
import com.android.internal.widget.LockPatternUtils;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -73,27 +62,17 @@
*/
public class LockSettingsService extends ILockSettings.Stub {
- private static final String PERMISSION = "android.permission.ACCESS_KEYGUARD_SECURE_STORAGE";
+ private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- private final DatabaseHelper mOpenHelper;
+
private static final String TAG = "LockSettingsService";
- private static final String TABLE = "locksettings";
- private static final String COLUMN_KEY = "name";
- private static final String COLUMN_USERID = "user";
- private static final String COLUMN_VALUE = "value";
-
- private static final String[] COLUMNS_FOR_QUERY = {
- COLUMN_VALUE
- };
-
- private static final String SYSTEM_DIRECTORY = "/system/";
- private static final String LOCK_PATTERN_FILE = "gesture.key";
- private static final String LOCK_PASSWORD_FILE = "password.key";
-
private final Context mContext;
+
+ private final LockSettingsStorage mStorage;
+
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
@@ -102,7 +81,6 @@
public LockSettingsService(Context context) {
mContext = context;
// Open the database
- mOpenHelper = new DatabaseHelper(mContext);
mLockPatternUtils = new LockPatternUtils(context);
mFirstCallToVold = true;
@@ -110,6 +88,18 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
+ mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
+ @Override
+ public void initialize(SQLiteDatabase db) {
+ // Get the lockscreen default from a system property, if available
+ boolean lockScreenDisable = SystemProperties.getBoolean(
+ "ro.lockscreen.disable.default", false);
+ if (lockScreenDisable) {
+ mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
+ }
+ }
+ });
}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -220,29 +210,31 @@
@Override
public void setBoolean(String key, boolean value, int userId) throws RemoteException {
checkWritePermission(userId);
-
- writeToDb(key, value ? "1" : "0", userId);
+ setStringUnchecked(key, userId, value ? "1" : "0");
}
@Override
public void setLong(String key, long value, int userId) throws RemoteException {
checkWritePermission(userId);
-
- writeToDb(key, Long.toString(value), userId);
+ setStringUnchecked(key, userId, Long.toString(value));
}
@Override
public void setString(String key, String value, int userId) throws RemoteException {
checkWritePermission(userId);
+ setStringUnchecked(key, userId, value);
+ }
- writeToDb(key, value, userId);
+ private void setStringUnchecked(String key, int userId, String value) {
+ mStorage.writeKeyValue(key, value, userId);
+ notifyObservers(key, userId);
}
@Override
public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
- String value = readFromDb(key, null, userId);
+ String value = mStorage.readKeyValue(key, null, userId);
return TextUtils.isEmpty(value) ?
defaultValue : (value.equals("1") || value.equals("true"));
}
@@ -251,7 +243,7 @@
public long getLong(String key, long defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
- String value = readFromDb(key, null, userId);
+ String value = mStorage.readKeyValue(key, null, userId);
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
}
@@ -259,7 +251,7 @@
public String getString(String key, String defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
- return readFromDb(key, defaultValue, userId);
+ return mStorage.readKeyValue(key, defaultValue, userId);
}
@Override
@@ -308,57 +300,18 @@
}
}
- private int getUserParentOrSelfId(int userId) {
- if (userId != 0) {
- final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
- final UserInfo pi = um.getProfileParent(userId);
- if (pi != null) {
- return pi.id;
- }
- }
- return userId;
- }
-
- private String getLockPatternFilename(int userId) {
- String dataSystemDirectory =
- android.os.Environment.getDataDirectory().getAbsolutePath() +
- SYSTEM_DIRECTORY;
- userId = getUserParentOrSelfId(userId);
- if (userId == 0) {
- // Leave it in the same place for user 0
- return dataSystemDirectory + LOCK_PATTERN_FILE;
- } else {
- return new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
- .getAbsolutePath();
- }
- }
-
- private String getLockPasswordFilename(int userId) {
- userId = getUserParentOrSelfId(userId);
- String dataSystemDirectory =
- android.os.Environment.getDataDirectory().getAbsolutePath() +
- SYSTEM_DIRECTORY;
- if (userId == 0) {
- // Leave it in the same place for user 0
- return dataSystemDirectory + LOCK_PASSWORD_FILE;
- } else {
- return new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
- .getAbsolutePath();
- }
- }
-
@Override
public boolean havePassword(int userId) throws RemoteException {
// Do we need a permissions check here?
- return new File(getLockPasswordFilename(userId)).length() > 0;
+ return mStorage.hasPassword(userId);
}
@Override
public boolean havePattern(int userId) throws RemoteException {
// Do we need a permissions check here?
- return new File(getLockPatternFilename(userId)).length() > 0;
+ return mStorage.hasPattern(userId);
}
private void maybeUpdateKeystore(String password, int userHandle) {
@@ -394,7 +347,7 @@
final byte[] hash = LockPatternUtils.patternToHash(
LockPatternUtils.stringToPattern(pattern));
- writeFile(getLockPatternFilename(userId), hash);
+ mStorage.writePatternHash(hash, userId);
}
@Override
@@ -403,68 +356,46 @@
maybeUpdateKeystore(password, userId);
- writeFile(getLockPasswordFilename(userId),
- mLockPatternUtils.passwordToHash(password, userId));
+ mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
}
@Override
public boolean checkPattern(String pattern, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- try {
- // Read all the bytes from the file
- RandomAccessFile raf = new RandomAccessFile(getLockPatternFilename(userId), "r");
- final byte[] stored = new byte[(int) raf.length()];
- int got = raf.read(stored, 0, stored.length);
- raf.close();
- if (got <= 0) {
- return true;
- }
- // Compare the hash from the file with the entered pattern's hash
- final byte[] hash = LockPatternUtils.patternToHash(
- LockPatternUtils.stringToPattern(pattern));
- final boolean matched = Arrays.equals(stored, hash);
- if (matched && !TextUtils.isEmpty(pattern)) {
- maybeUpdateKeystore(pattern, userId);
- }
- return matched;
- } catch (FileNotFoundException fnfe) {
- Slog.e(TAG, "Cannot read file " + fnfe);
- } catch (IOException ioe) {
- Slog.e(TAG, "Cannot read file " + ioe);
+ byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern));
+ byte[] storedHash = mStorage.readPatternHash(userId);
+
+ if (storedHash == null) {
+ return true;
}
- return true;
+
+ boolean matched = Arrays.equals(hash, storedHash);
+ if (matched && !TextUtils.isEmpty(pattern)) {
+ maybeUpdateKeystore(pattern, userId);
+ }
+ return matched;
}
@Override
public boolean checkPassword(String password, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- try {
- // Read all the bytes from the file
- RandomAccessFile raf = new RandomAccessFile(getLockPasswordFilename(userId), "r");
- final byte[] stored = new byte[(int) raf.length()];
- int got = raf.read(stored, 0, stored.length);
- raf.close();
- if (got <= 0) {
- return true;
- }
- // Compare the hash from the file with the entered password's hash
- final byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
- final boolean matched = Arrays.equals(stored, hash);
- if (matched && !TextUtils.isEmpty(password)) {
- maybeUpdateKeystore(password, userId);
- }
- return matched;
- } catch (FileNotFoundException fnfe) {
- Slog.e(TAG, "Cannot read file " + fnfe);
- } catch (IOException ioe) {
- Slog.e(TAG, "Cannot read file " + ioe);
+ byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
+ byte[] storedHash = mStorage.readPasswordHash(userId);
+
+ if (storedHash == null) {
+ return true;
}
- return true;
+
+ boolean matched = Arrays.equals(hash, storedHash);
+ if (matched && !TextUtils.isEmpty(password)) {
+ maybeUpdateKeystore(password, userId);
+ }
+ return matched;
}
@Override
- public boolean checkVoldPassword(int userId) throws RemoteException {
+ public boolean checkVoldPassword(int userId) throws RemoteException {
if (!mFirstCallToVold) {
return false;
}
@@ -512,166 +443,14 @@
public void removeUser(int userId) {
checkWritePermission(userId);
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- try {
- final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
- final UserInfo parentInfo = um.getProfileParent(userId);
- if (parentInfo == null) {
- // This user owns its lock settings files - safe to delete them
- File file = new File(getLockPasswordFilename(userId));
- if (file.exists()) {
- file.delete();
- }
- file = new File(getLockPatternFilename(userId));
- if (file.exists()) {
- file.delete();
- }
- }
-
- db.beginTransaction();
- db.delete(TABLE, COLUMN_USERID + "='" + userId + "'", null);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
+ mStorage.removeUser(userId);
+ notifyObservers(null /* key */, userId);
final KeyStore ks = KeyStore.getInstance();
final int userUid = UserHandle.getUid(userId, Process.SYSTEM_UID);
ks.resetUid(userUid);
}
- private void writeFile(String name, byte[] hash) {
- try {
- // Write the hash to file
- RandomAccessFile raf = new RandomAccessFile(name, "rw");
- // Truncate the file if pattern is null, to clear the lock
- if (hash == null || hash.length == 0) {
- raf.setLength(0);
- } else {
- raf.write(hash, 0, hash.length);
- }
- raf.close();
- } catch (IOException ioe) {
- Slog.e(TAG, "Error writing to file " + ioe);
- }
- }
-
- private void writeToDb(String key, String value, int userId) {
- writeToDb(mOpenHelper.getWritableDatabase(), key, value, userId);
- notifyObservers(key, userId);
- }
-
- private void writeToDb(SQLiteDatabase db, String key, String value, int userId) {
- ContentValues cv = new ContentValues();
- cv.put(COLUMN_KEY, key);
- cv.put(COLUMN_USERID, userId);
- cv.put(COLUMN_VALUE, value);
-
- db.beginTransaction();
- try {
- db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
- new String[] {key, Integer.toString(userId)});
- db.insert(TABLE, null, cv);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
-
- private String readFromDb(String key, String defaultValue, int userId) {
- Cursor cursor;
- String result = defaultValue;
- SQLiteDatabase db = mOpenHelper.getReadableDatabase();
- if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
- COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
- new String[] { Integer.toString(userId), key },
- null, null, null)) != null) {
- if (cursor.moveToFirst()) {
- result = cursor.getString(0);
- }
- cursor.close();
- }
- return result;
- }
-
- class DatabaseHelper extends SQLiteOpenHelper {
- private static final String TAG = "LockSettingsDB";
- private static final String DATABASE_NAME = "locksettings.db";
-
- private static final int DATABASE_VERSION = 2;
-
- public DatabaseHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- setWriteAheadLoggingEnabled(true);
- }
-
- private void createTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE + " (" +
- "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
- COLUMN_KEY + " TEXT," +
- COLUMN_USERID + " INTEGER," +
- COLUMN_VALUE + " TEXT" +
- ");");
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- createTable(db);
- initializeDefaults(db);
- }
-
- private void initializeDefaults(SQLiteDatabase db) {
- // Get the lockscreen default from a system property, if available
- boolean lockScreenDisable = SystemProperties.getBoolean("ro.lockscreen.disable.default",
- false);
- if (lockScreenDisable) {
- writeToDb(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
- }
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
- int upgradeVersion = oldVersion;
- if (upgradeVersion == 1) {
- // Set the initial value for {@link LockPatternUtils#LOCKSCREEN_WIDGETS_ENABLED}
- // during upgrade based on whether each user previously had widgets in keyguard.
- maybeEnableWidgetSettingForUsers(db);
- upgradeVersion = 2;
- }
-
- if (upgradeVersion != DATABASE_VERSION) {
- Log.w(TAG, "Failed to upgrade database!");
- }
- }
-
- private void maybeEnableWidgetSettingForUsers(SQLiteDatabase db) {
- final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
- final ContentResolver cr = mContext.getContentResolver();
- final List<UserInfo> users = um.getUsers();
- for (int i = 0; i < users.size(); i++) {
- final int userId = users.get(i).id;
- final boolean enabled = mLockPatternUtils.hasWidgetsEnabledInKeyguard(userId);
- Log.v(TAG, "Widget upgrade uid=" + userId + ", enabled="
- + enabled + ", w[]=" + mLockPatternUtils.getAppWidgets());
- loadSetting(db, LockPatternUtils.LOCKSCREEN_WIDGETS_ENABLED, userId, enabled);
- }
- }
-
- private void loadSetting(SQLiteDatabase db, String key, int userId, boolean value) {
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement(
- "INSERT OR REPLACE INTO locksettings(name,user,value) VALUES(?,?,?);");
- stmt.bindString(1, key);
- stmt.bindLong(2, userId);
- stmt.bindLong(3, value ? 1 : 0);
- stmt.execute();
- } finally {
- if (stmt != null) stmt.close();
- }
- }
- }
-
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
new file mode 100644
index 0000000..acbf8ef
--- /dev/null
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Environment;
+import android.os.UserManager;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import static android.content.Context.USER_SERVICE;
+
+/**
+ * Storage for the lock settings service.
+ */
+class LockSettingsStorage {
+
+ private static final String TAG = "LockSettingsStorage";
+ private static final String TABLE = "locksettings";
+
+ private static final String COLUMN_KEY = "name";
+ private static final String COLUMN_USERID = "user";
+ private static final String COLUMN_VALUE = "value";
+
+ private static final String[] COLUMNS_FOR_QUERY = {
+ COLUMN_VALUE
+ };
+
+ private static final String SYSTEM_DIRECTORY = "/system/";
+ private static final String LOCK_PATTERN_FILE = "gesture.key";
+ private static final String LOCK_PASSWORD_FILE = "password.key";
+
+ private final DatabaseHelper mOpenHelper;
+ private final Context mContext;
+ private final Object mFileWriteLock = new Object();
+
+ LockSettingsStorage(Context context, Callback callback) {
+ mContext = context;
+ mOpenHelper = new DatabaseHelper(context, callback);
+ }
+
+ void writeKeyValue(String key, String value, int userId) {
+ writeKeyValue(mOpenHelper.getWritableDatabase(), key, value, userId);
+ }
+
+ void writeKeyValue(SQLiteDatabase db, String key, String value, int userId) {
+ ContentValues cv = new ContentValues();
+ cv.put(COLUMN_KEY, key);
+ cv.put(COLUMN_USERID, userId);
+ cv.put(COLUMN_VALUE, value);
+
+ db.beginTransaction();
+ try {
+ db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
+ new String[] {key, Integer.toString(userId)});
+ db.insert(TABLE, null, cv);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ }
+
+ String readKeyValue(String key, String defaultValue, int userId) {
+ Cursor cursor;
+ String result = defaultValue;
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
+ COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
+ new String[] { Integer.toString(userId), key },
+ null, null, null)) != null) {
+ if (cursor.moveToFirst()) {
+ result = cursor.getString(0);
+ }
+ cursor.close();
+ }
+ return result;
+ }
+
+ byte[] readPasswordHash(int userId) {
+ final byte[] stored = readFile(getLockPasswordFilename(userId), userId);
+ if (stored != null && stored.length > 0) {
+ return stored;
+ }
+ return null;
+ }
+
+ byte[] readPatternHash(int userId) {
+ final byte[] stored = readFile(getLockPatternFilename(userId), userId);
+ if (stored != null && stored.length > 0) {
+ return stored;
+ }
+ return null;
+ }
+
+ boolean hasPassword(int userId) {
+ return hasFile(getLockPasswordFilename(userId), userId);
+ }
+
+ boolean hasPattern(int userId) {
+ return hasFile(getLockPatternFilename(userId), userId);
+ }
+
+ private boolean hasFile(String name, int userId) {
+ byte[] contents = readFile(name, userId);
+ return contents != null && contents.length > 0;
+ }
+
+ private byte[] readFile(String name, int userId) {
+ RandomAccessFile raf = null;
+ byte[] stored = null;
+ try {
+ raf = new RandomAccessFile(name, "r");
+ stored = new byte[(int) raf.length()];
+ raf.readFully(stored, 0, stored.length);
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Cannot read file " + e);
+ } finally {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error closing file " + e);
+ }
+ }
+ }
+ return stored;
+ }
+
+ private void writeFile(String name, byte[] hash, int userId) {
+ synchronized (mFileWriteLock) {
+ RandomAccessFile raf = null;
+ try {
+ // Write the hash to file
+ raf = new RandomAccessFile(name, "rw");
+ // Truncate the file if pattern is null, to clear the lock
+ if (hash == null || hash.length == 0) {
+ raf.setLength(0);
+ } else {
+ raf.write(hash, 0, hash.length);
+ }
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error writing to file " + e);
+ } finally {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException e) {
+ Slog.e(TAG, "Error closing file " + e);
+ }
+ }
+ }
+ }
+ }
+
+ public void writePatternHash(byte[] hash, int userId) {
+ writeFile(getLockPatternFilename(userId), hash, userId);
+ }
+
+ public void writePasswordHash(byte[] hash, int userId) {
+ writeFile(getLockPasswordFilename(userId), hash, userId);
+ }
+
+
+ private String getLockPatternFilename(int userId) {
+ String dataSystemDirectory =
+ android.os.Environment.getDataDirectory().getAbsolutePath() +
+ SYSTEM_DIRECTORY;
+ userId = getUserParentOrSelfId(userId);
+ if (userId == 0) {
+ // Leave it in the same place for user 0
+ return dataSystemDirectory + LOCK_PATTERN_FILE;
+ } else {
+ return new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
+ .getAbsolutePath();
+ }
+ }
+
+ private String getLockPasswordFilename(int userId) {
+ userId = getUserParentOrSelfId(userId);
+ String dataSystemDirectory =
+ android.os.Environment.getDataDirectory().getAbsolutePath() +
+ SYSTEM_DIRECTORY;
+ if (userId == 0) {
+ // Leave it in the same place for user 0
+ return dataSystemDirectory + LOCK_PASSWORD_FILE;
+ } else {
+ return new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
+ .getAbsolutePath();
+ }
+ }
+
+ private int getUserParentOrSelfId(int userId) {
+ if (userId != 0) {
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final UserInfo pi = um.getProfileParent(userId);
+ if (pi != null) {
+ return pi.id;
+ }
+ }
+ return userId;
+ }
+
+
+ public void removeUser(int userId) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+
+ final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
+ final UserInfo parentInfo = um.getProfileParent(userId);
+
+ synchronized (mFileWriteLock) {
+ if (parentInfo == null) {
+ // This user owns its lock settings files - safe to delete them
+ File file = new File(getLockPasswordFilename(userId));
+ if (file.exists()) {
+ file.delete();
+ }
+ file = new File(getLockPatternFilename(userId));
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+ }
+
+ try {
+ db.beginTransaction();
+ db.delete(TABLE, COLUMN_USERID + "='" + userId + "'", null);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+
+ interface Callback {
+ void initialize(SQLiteDatabase db);
+ }
+
+ class DatabaseHelper extends SQLiteOpenHelper {
+ private static final String TAG = "LockSettingsDB";
+ private static final String DATABASE_NAME = "locksettings.db";
+
+ private static final int DATABASE_VERSION = 2;
+
+ private final Callback mCallback;
+
+ public DatabaseHelper(Context context, Callback callback) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ setWriteAheadLoggingEnabled(true);
+ mCallback = callback;
+ }
+
+ private void createTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE + " (" +
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+ COLUMN_KEY + " TEXT," +
+ COLUMN_USERID + " INTEGER," +
+ COLUMN_VALUE + " TEXT" +
+ ");");
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ createTable(db);
+ mCallback.initialize(db);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
+ int upgradeVersion = oldVersion;
+ if (upgradeVersion == 1) {
+ // Previously migrated lock screen widget settings. Now defunct.
+ upgradeVersion = 2;
+ }
+
+ if (upgradeVersion != DATABASE_VERSION) {
+ Log.w(TAG, "Failed to upgrade database!");
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9179cc4..91e2df0 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1836,8 +1836,8 @@
ComponentName cn = tr.intent.getComponent();
if (cn != null && cn.getPackageName().equals(packageName)) {
- // If the package name matches, remove the task and kill the process
- removeTaskByIdLocked(tr.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ // If the package name matches, remove the task
+ removeTaskByIdLocked(tr.taskId, true);
}
}
}
@@ -1891,9 +1891,7 @@
// Prune all the tasks with removed components from the list of recent tasks
synchronized (ActivityManagerService.this) {
for (int i = tasksToRemove.size() - 1; i >= 0; i--) {
- // Remove the task but don't kill the process (since other components in that
- // package may still be running and in the background)
- removeTaskByIdLocked(tasksToRemove.get(i), 0);
+ removeTaskByIdLocked(tasksToRemove.get(i), false);
}
}
}
@@ -4313,9 +4311,9 @@
boolean res;
if (finishTask && r == rootR) {
// If requested, remove the task that is associated to this activity only if it
- // was the root activity in the task. The result code and data is ignored because
- // we don't support returning them across task boundaries.
- res = removeTaskByIdLocked(tr.taskId, 0);
+ // was the root activity in the task. The result code and data is ignored
+ // because we don't support returning them across task boundaries.
+ res = removeTaskByIdLocked(tr.taskId, false);
} else {
res = tr.stack.requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
@@ -5142,7 +5140,7 @@
tr.getBaseIntent().getComponent().getPackageName();
if (tr.userId != userId) continue;
if (!taskPackageName.equals(packageName)) continue;
- removeTaskByIdLocked(tr.taskId, 0);
+ removeTaskByIdLocked(tr.taskId, false);
}
}
@@ -8287,52 +8285,65 @@
return mTaskPersister.getTaskDescriptionIcon(filename);
}
- private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) {
+ private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess) {
mRecentTasks.remove(tr);
tr.removedFromRecents(mTaskPersister);
- final boolean killProcesses = (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0;
- Intent baseIntent = new Intent(
- tr.intent != null ? tr.intent : tr.affinityIntent);
- ComponentName component = baseIntent.getComponent();
+ ComponentName component = tr.getBaseIntent().getComponent();
if (component == null) {
- Slog.w(TAG, "Now component for base intent of task: " + tr);
+ Slog.w(TAG, "No component for base intent of task: " + tr);
return;
}
- // Find any running services associated with this app.
- mServices.cleanUpRemovedTaskLocked(tr, component, baseIntent);
+ if (!killProcess) {
+ return;
+ }
- if (killProcesses) {
- // Find any running processes associated with this app.
- final String pkg = component.getPackageName();
- ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
- ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
- for (int i=0; i<pmap.size(); i++) {
- SparseArray<ProcessRecord> uids = pmap.valueAt(i);
- for (int j=0; j<uids.size(); j++) {
- ProcessRecord proc = uids.valueAt(j);
- if (proc.userId != tr.userId) {
- continue;
- }
- if (!proc.pkgList.containsKey(pkg)) {
- continue;
- }
- procs.add(proc);
+ // Determine if the process(es) for this task should be killed.
+ final String pkg = component.getPackageName();
+ ArrayList<ProcessRecord> procsToKill = new ArrayList<ProcessRecord>();
+ ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
+ for (int i = 0; i < pmap.size(); i++) {
+
+ SparseArray<ProcessRecord> uids = pmap.valueAt(i);
+ for (int j = 0; j < uids.size(); j++) {
+ ProcessRecord proc = uids.valueAt(j);
+ if (proc.userId != tr.userId) {
+ // Don't kill process for a different user.
+ continue;
}
- }
-
- // Kill the running processes.
- for (int i=0; i<procs.size(); i++) {
- ProcessRecord pr = procs.get(i);
- if (pr == mHomeProcess) {
+ if (proc == mHomeProcess) {
// Don't kill the home process along with tasks from the same package.
continue;
}
- if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- pr.kill("remove task", true);
- } else {
- pr.waitingToKill = "remove task";
+ if (!proc.pkgList.containsKey(pkg)) {
+ // Don't kill process that is not associated with this task.
+ continue;
}
+
+ for (int k = 0; k < proc.activities.size(); k++) {
+ TaskRecord otherTask = proc.activities.get(k).task;
+ if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
+ // Don't kill process(es) that has an activity in a different task that is
+ // also in recents.
+ return;
+ }
+ }
+
+ // Add process to kill list.
+ procsToKill.add(proc);
+ }
+ }
+
+ // Find any running services associated with this app and stop if needed.
+ mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
+
+ // Kill the running processes.
+ for (int i = 0; i < procsToKill.size(); i++) {
+ ProcessRecord pr = procsToKill.get(i);
+ if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ pr.kill("remove task", true);
+ } else {
+ pr.waitingToKill = "remove task";
}
}
}
@@ -8341,15 +8352,14 @@
* Removes the task with the specified task id.
*
* @param taskId Identifier of the task to be removed.
- * @param flags Additional operational flags. May be 0 or
- * {@link ActivityManager#REMOVE_TASK_KILL_PROCESS}.
+ * @param killProcess Kill any process associated with the task if possible.
* @return Returns true if the given task was found and removed.
*/
- private boolean removeTaskByIdLocked(int taskId, int flags) {
+ private boolean removeTaskByIdLocked(int taskId, boolean killProcess) {
TaskRecord tr = recentTaskForIdLocked(taskId);
if (tr != null) {
tr.removeTaskActivitiesLocked();
- cleanUpRemovedTaskLocked(tr, flags);
+ cleanUpRemovedTaskLocked(tr, killProcess);
if (tr.isPersistable) {
notifyTaskPersisterLocked(null, true);
}
@@ -8359,19 +8369,19 @@
}
@Override
- public boolean removeTask(int taskId, int flags) {
+ public boolean removeTask(int taskId) {
synchronized (this) {
enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
"removeTask()");
long ident = Binder.clearCallingIdentity();
try {
- return removeTaskByIdLocked(taskId, flags);
+ return removeTaskByIdLocked(taskId, true);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
-
+
/**
* TODO: Add mController hook
*/
@@ -19167,16 +19177,9 @@
synchronized (ActivityManagerService.this) {
long origId = Binder.clearCallingIdentity();
try {
- TaskRecord tr = recentTaskForIdLocked(mTaskId);
- if (tr == null) {
+ if (!removeTaskByIdLocked(mTaskId, false)) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
- // Only kill the process if we are not a new document
- int flags = tr.getBaseIntent().getFlags();
- boolean isDocument = (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
- Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
- removeTaskByIdLocked(mTaskId,
- !isDocument ? ActivityManager.REMOVE_TASK_KILL_PROCESS : 0);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e1b8278..b61bd8a 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -835,7 +835,7 @@
prev.task.touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
- if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task)) {
+ if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
prev.updateThumbnail(screenshotActivities(prev), null);
}
stopFullyDrawnTraceIfNeeded();
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 238402f..debda14 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -191,8 +191,8 @@
}
try {
if (add) {
- mNetd.setPermission(CHANGE_NETWORK_STATE, toIntArray(network));
- mNetd.setPermission(CONNECTIVITY_INTERNAL, toIntArray(system));
+ mNetd.setPermission("NETWORK", toIntArray(network));
+ mNetd.setPermission("SYSTEM", toIntArray(system));
} else {
mNetd.clearPermission(toIntArray(network));
mNetd.clearPermission(toIntArray(system));
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 61ea1e8..8d93141 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -91,6 +91,9 @@
boolean mKeyguardGoingAwayToNotificationShade;
boolean mKeyguardGoingAwayDisableWindowAnimations;
+ /** Use one animation for all entering activities after keyguard is dismissed. */
+ Animation mPostKeyguardExitAnimation;
+
// forceHiding states.
static final int KEYGUARD_NOT_SHOWN = 0;
static final int KEYGUARD_ANIMATING_IN = 1;
@@ -220,9 +223,6 @@
++mAnimTransactionSequence;
final WindowList windows = mService.getWindowListLocked(displayId);
- ArrayList<WindowStateAnimator> unForceHiding = null;
- boolean wallpaperInUnForceHiding = false;
- WindowState wallpaper = null;
if (mKeyguardGoingAway) {
for (int i = windows.size() - 1; i >= 0; i--) {
@@ -261,6 +261,9 @@
final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
null : winShowWhenLocked.mAppToken;
+ boolean wallpaperInUnForceHiding = false;
+ ArrayList<WindowStateAnimator> unForceHiding = null;
+ WindowState wallpaper = null;
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState win = windows.get(i);
WindowStateAnimator winAnimator = win.mWinAnimator;
@@ -327,40 +330,53 @@
} else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
final boolean hideWhenLocked = !((win.mIsImWindow && showImeOverKeyguard) ||
(appShowWhenLocked != null && appShowWhenLocked == win.mAppToken));
- final boolean changed;
if (((mForceHiding == KEYGUARD_ANIMATING_IN)
&& (!winAnimator.isAnimating() || hideWhenLocked))
|| ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked)) {
- changed = win.hideLw(false, false);
- if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
- && changed) Slog.v(TAG, "Now policy hidden: " + win);
+ if (!win.hideLw(false, false)) {
+ // Was already hidden
+ continue;
+ }
+ if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+ "Now policy hidden: " + win);
} else {
- changed = win.showLw(false, false);
- if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
- && changed) Slog.v(TAG, "Now policy shown: " + win);
- if (changed) {
- if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
- && win.isVisibleNow() /*w.isReadyForDisplay()*/) {
- if (unForceHiding == null) {
- unForceHiding = new ArrayList<WindowStateAnimator>();
- }
- unForceHiding.add(winAnimator);
- if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
- wallpaperInUnForceHiding = true;
- }
+ if (!win.showLw(false, false)) {
+ // Was already showing.
+ continue;
+ }
+ final boolean visibleNow = win.isVisibleNow();
+ if (!visibleNow) {
+ // Couldn't really show, must showLw() again when win becomes visible.
+ win.hideLw(false, false);
+ continue;
+ }
+ if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+ "Now policy shown: " + win);
+ if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
+ if (unForceHiding == null) {
+ unForceHiding = new ArrayList<>();
}
- final WindowState currentFocus = mService.mCurrentFocus;
- if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
- // We are showing on to of the current
- // focus, so re-evaluate focus to make
- // sure it is correct.
- if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
- "updateWindowsLocked: setting mFocusMayChange true");
- mService.mFocusMayChange = true;
+ unForceHiding.add(winAnimator);
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
+ wallpaperInUnForceHiding = true;
}
+ } else if (mPostKeyguardExitAnimation != null) {
+ // We're already in the middle of an animation. Use the existing
+ // animation to bring in this window.
+ winAnimator.setAnimation(mPostKeyguardExitAnimation);
+ winAnimator.keyguardGoingAwayAnimation = true;
+ }
+ final WindowState currentFocus = mService.mCurrentFocus;
+ if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
+ // We are showing on top of the current
+ // focus, so re-evaluate focus to make
+ // sure it is correct.
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
+ "updateWindowsLocked: setting mFocusMayChange true");
+ mService.mFocusMayChange = true;
}
}
- if (changed && (flags & FLAG_SHOW_WALLPAPER) != 0) {
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
@@ -403,42 +419,44 @@
// If we have windows that are being show due to them no longer
// being force-hidden, apply the appropriate animation to them.
if (unForceHiding != null) {
- boolean startKeyguardExit = true;
- for (int i=unForceHiding.size()-1; i>=0; i--) {
- Animation a = null;
- if (!mKeyguardGoingAwayDisableWindowAnimations) {
- a = mPolicy.createForceHideEnterAnimation(wallpaperInUnForceHiding,
- mKeyguardGoingAwayToNotificationShade);
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim=" + a
- + " for win=" + unForceHiding.get(i));
- } else {
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for win="
- + unForceHiding.get(i));
- }
- if (a != null) {
+ // This only happens the first time that we detect the keyguard is animating out.
+ if (mKeyguardGoingAwayDisableWindowAnimations) {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for windows");
+ } else {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim for windows");
+ mPostKeyguardExitAnimation = mPolicy.createForceHideEnterAnimation(
+ wallpaperInUnForceHiding, mKeyguardGoingAwayToNotificationShade);
+ }
+ if (mPostKeyguardExitAnimation != null) {
+ for (int i=unForceHiding.size()-1; i>=0; i--) {
final WindowStateAnimator winAnimator = unForceHiding.get(i);
- winAnimator.setAnimation(a);
+ winAnimator.setAnimation(mPostKeyguardExitAnimation);
winAnimator.keyguardGoingAwayAnimation = true;
- if (startKeyguardExit && mKeyguardGoingAway) {
- // Do one time only.
- mPolicy.startKeyguardExitAnimation(mCurrentTime + a.getStartOffset(),
- a.getDuration());
- mKeyguardGoingAway = false;
- startKeyguardExit = false;
- }
}
}
+ }
- // Wallpaper is going away in un-force-hide motion, animate it as well.
- if (!wallpaperInUnForceHiding && wallpaper != null
- && !mKeyguardGoingAwayDisableWindowAnimations) {
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
- Animation a = mPolicy.createForceHideWallpaperExitAnimation(
- mKeyguardGoingAwayToNotificationShade);
- if (a != null) {
- WindowStateAnimator animator = wallpaper.mWinAnimator;
- animator.setAnimation(a);
- }
+ if (mPostKeyguardExitAnimation != null) {
+ // We're in the midst of a keyguard exit animation.
+ if (mKeyguardGoingAway) {
+ mPolicy.startKeyguardExitAnimation(mCurrentTime +
+ mPostKeyguardExitAnimation.getStartOffset(),
+ mPostKeyguardExitAnimation.getDuration());
+ mKeyguardGoingAway = false;
+ } else if (mPostKeyguardExitAnimation.hasEnded()) {
+ // Done with the animation, reset.
+ mPostKeyguardExitAnimation = null;
+ }
+ }
+
+ // Wallpaper is going away in un-force-hide motion, animate it as well.
+ if (!wallpaperInUnForceHiding && wallpaper != null
+ && !mKeyguardGoingAwayDisableWindowAnimations) {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
+ Animation a = mPolicy.createForceHideWallpaperExitAnimation(
+ mKeyguardGoingAwayToNotificationShade);
+ if (a != null) {
+ wallpaper.mWinAnimator.setAnimation(a);
}
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 11da380..098b3ef 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -119,6 +119,7 @@
if (!files.valueAt(start).getBaseFile().getName().endsWith("-c")) {
break;
}
+ start++;
}
if (start == fileCount - 1) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 4eac5ac..d98a255 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -17,6 +17,7 @@
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
+import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -926,7 +927,6 @@
* @param accountHandle The handle for the account the MMI code should apply to.
* @param dialString The digits to dial.
* @return True if the digits were processed as an MMI code, false otherwise.
- *
*/
public boolean handleMmi(PhoneAccountHandle accountHandle, String dialString) {
ITelecomService service = getTelecomService();
@@ -941,6 +941,24 @@
}
/**
+ * @param accountHandle The handle for the account to derive an adn query URI for or
+ * {@code null} to return a URI which will use the default account.
+ * @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
+ * for the the content retrieve.
+ */
+ public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
+ ITelecomService service = getTelecomService();
+ if (service != null && accountHandle != null) {
+ try {
+ return service.getAdnUriForPhoneAccount(accountHandle);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecomService#getAdnUriForPhoneAccount", e);
+ }
+ }
+ return Uri.parse("content://icc/adn");
+ }
+
+ /**
* Removes the missed-call notification if one is present.
* <p>
* Requires that the method-caller be set as the system dialer app.
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index fd47213..cbd9d69 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.telecom.PhoneAccountHandle;
+import android.net.Uri;
import android.os.Bundle;
import android.telecom.PhoneAccount;
@@ -174,6 +175,11 @@
boolean handlePinMmiForPhoneAccount(in PhoneAccountHandle accountHandle, String dialString);
/**
+ * @see TelecomServiceImpl#getAdnUriForPhoneAccount
+ */
+ Uri getAdnUriForPhoneAccount(in PhoneAccountHandle accountHandle);
+
+ /**
* @see TelecomServiceImpl#isTtySupported
*/
boolean isTtySupported();
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
index 4a3d67e..e08f255 100644
--- a/telephony/java/android/telephony/SubInfoRecord.java
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -29,98 +29,138 @@
* Subscription Identifier, this is a device unique number
* and not an index into an array
*/
- public int subId;
- /** The GID for a SIM that maybe associated with this subscription, empty if unknown */
- public String iccId;
+ private int mId;
+
/**
- * The slot identifier for that currently contains the subscription
+ * The GID for a SIM that maybe associated with this subscription, empty if unknown
+ */
+ private String mIccId;
+
+ /**
+ * The index of the slot that currently contains the subscription
* and not necessarily unique and maybe INVALID_SLOT_ID if unknown
*/
- public int slotId;
+ private int mSimSlotIndex;
+
/**
- * The string displayed to the user that identifies this subscription
+ * The name displayed to the user that identifies this subscription
*/
- public String displayName;
+ private CharSequence mDisplayName;
+
/**
* The source of the name, NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
* NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
*/
- public int nameSource;
+ private int mNameSource;
+
/**
* The color to be used for when displaying to the user
*/
- public int color;
+ private int mColor;
+
/**
* A number presented to the user identify this subscription
*/
- public String number;
- /**
- * How to display the phone number, DISPLAY_NUMBER_NONE, DISPLAY_NUMBER_FIRST,
- * DISPLAY_NUMBER_LAST
- */
- public int displayNumberFormat;
+ private String mNumber;
+
/**
* Data roaming state, DATA_RAOMING_ENABLE, DATA_RAOMING_DISABLE
*/
- public int dataRoaming;
+ private int mDataRoaming;
+
/**
* SIM Icon resource identifiers. FIXME: Check with MTK what it really is
*/
- public int[] simIconRes;
+ private int[] mSimIconRes;
+
/**
* Mobile Country Code
*/
- public int mcc;
+ private int mMcc;
+
/**
* Mobile Network Code
*/
- public int mnc;
+ private int mMnc;
+ /**
+ * @hide
public SubInfoRecord() {
- this.subId = SubscriptionManager.INVALID_SUB_ID;
- this.iccId = "";
- this.slotId = SubscriptionManager.INVALID_SLOT_ID;
- this.displayName = "";
- this.nameSource = 0;
- this.color = 0;
- this.number = "";
- this.displayNumberFormat = 0;
- this.dataRoaming = 0;
- this.simIconRes = new int[2];
- this.mcc = 0;
- this.mnc = 0;
+ this.mId = SubscriptionManager.INVALID_SUB_ID;
+ this.mIccId = "";
+ this.mSimSlotIndex = SubscriptionManager.INVALID_SLOT_ID;
+ this.mDisplayName = "";
+ this.mNameSource = 0;
+ this.mColor = 0;
+ this.mNumber = "";
+ this.mDataRoaming = 0;
+ this.mSimIconRes = new int[2];
+ this.mMcc = 0;
+ this.mMnc = 0;
}
+ */
- public SubInfoRecord(int subId, String iccId, int slotId, String displayName, int nameSource,
- int color, String number, int displayFormat, int roaming, int[] iconRes,
- int mcc, int mnc) {
- this.subId = subId;
- this.iccId = iccId;
- this.slotId = slotId;
- this.displayName = displayName;
- this.nameSource = nameSource;
- this.color = color;
- this.number = number;
- this.displayNumberFormat = displayFormat;
- this.dataRoaming = roaming;
- this.simIconRes = iconRes;
- this.mcc = mcc;
- this.mnc = mnc;
+ /**
+ * @hide
+ */
+ public SubInfoRecord(int id, String iccId, int simSlotIndex, CharSequence displayName,
+ int nameSource, int color, String number, int roaming, int[] iconRes, int mcc,
+ int mnc) {
+ this.mId = id;
+ this.mIccId = iccId;
+ this.mSimSlotIndex = simSlotIndex;
+ this.mDisplayName = displayName;
+ this.mNameSource = nameSource;
+ this.mColor = color;
+ this.mNumber = number;
+ this.mDataRoaming = roaming;
+ this.mSimIconRes = iconRes;
+ this.mMcc = mcc;
+ this.mMnc = mnc;
}
/**
- * Returns the string displayed to the user that identifies this subscription
+ * Returns the subscription ID.
*/
- public String getLabel() {
- return this.displayName;
+ public int getSubscriptionId() {
+ return this.mId;
}
/**
- * Return the icon used to identify this SIM.
- * TODO: return the correct drawable.
+ * Returns the ICC ID.
*/
- public BitmapDrawable getIconDrawable() {
- return new BitmapDrawable();
+ public String getIccId() {
+ return this.mIccId;
+ }
+
+ /**
+ * Returns the slot index of this Subscription's SIM card.
+ */
+ public int getSimSlotIndex() {
+ return this.mSimSlotIndex;
+ }
+
+ /**
+ * Returns the name displayed to the user that identifies this subscription
+ */
+ public CharSequence getDisplayName() {
+ return this.mDisplayName;
+ }
+
+ /**
+ * Sets the name displayed to the user that identifies this subscription
+ * @hide
+ */
+ public void setDisplayName(CharSequence name) {
+ this.mDisplayName = name;
+ }
+
+ /**
+ * Return the source of the name, eg NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
+ * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
+ */
+ public int getNameSource() {
+ return this.mNameSource;
}
/**
@@ -130,28 +170,70 @@
public int getColor() {
// Note: This color is currently an index into a list of drawables, but this is soon to
// change.
- return this.color;
+ return this.mColor;
+ }
+
+ /**
+ * Sets the color displayed to the user that identifies this subscription
+ * @hide
+ */
+ public void setColor(int color) {
+ this.mColor = color;
+ }
+
+ /**
+ * Returns the number of this subscription.
+ */
+ public String getNumber() {
+ return mNumber;
+ }
+
+ /**
+ * Return the data roaming value.
+ */
+ public int getDataRoaming() {
+ return this.mDataRoaming;
+ }
+
+ /**
+ * Return the icon used to identify this subscription.
+ */
+ public BitmapDrawable getIcon() {
+ return new BitmapDrawable();
+ }
+
+ /**
+ * Returns the MCC.
+ */
+ public int getMcc() {
+ return this.mMcc;
+ }
+
+ /**
+ * Returns the MNC.
+ */
+ public int getMnc() {
+ return this.mMnc;
}
public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
@Override
public SubInfoRecord createFromParcel(Parcel source) {
- int subId = source.readInt();
+ int id = source.readInt();
String iccId = source.readString();
- int slotId = source.readInt();
- String displayName = source.readString();
+ int simSlotIndex = source.readInt();
+ CharSequence displayName = source.readCharSequence();
int nameSource = source.readInt();
int color = source.readInt();
String number = source.readString();
- int displayNumberFormat = source.readInt();
int dataRoaming = source.readInt();
int[] iconRes = new int[2];
source.readIntArray(iconRes);
int mcc = source.readInt();
int mnc = source.readInt();
- return new SubInfoRecord(subId, iccId, slotId, displayName, nameSource, color, number,
- displayNumberFormat, dataRoaming, iconRes, mcc, mnc);
+ return new SubInfoRecord(id, iccId, simSlotIndex, displayName, nameSource, color, number,
+ dataRoaming, iconRes, mcc, mnc);
}
@Override
@@ -162,18 +244,17 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(subId);
- dest.writeString(iccId);
- dest.writeInt(slotId);
- dest.writeString(displayName);
- dest.writeInt(nameSource);
- dest.writeInt(color);
- dest.writeString(number);
- dest.writeInt(displayNumberFormat);
- dest.writeInt(dataRoaming);
- dest.writeIntArray(simIconRes);
- dest.writeInt(mcc);
- dest.writeInt(mnc);
+ dest.writeInt(mId);
+ dest.writeString(mIccId);
+ dest.writeInt(mSimSlotIndex);
+ dest.writeCharSequence(mDisplayName);
+ dest.writeInt(mNameSource);
+ dest.writeInt(mColor);
+ dest.writeString(mNumber.toString());
+ dest.writeInt(mDataRoaming);
+ dest.writeIntArray(mSimIconRes);
+ dest.writeInt(mMcc);
+ dest.writeInt(mMnc);
}
@Override
@@ -183,10 +264,9 @@
@Override
public String toString() {
- return "{mSubId=" + subId + ", mIccId=" + iccId + " mSlotId=" + slotId
- + " mDisplayName=" + displayName + " mNameSource=" + nameSource
- + " mColor=" + color + " mNumber=" + number
- + " mDisplayNumberFormat=" + displayNumberFormat + " mDataRoaming=" + dataRoaming
- + " mSimIconRes=" + simIconRes + " mMcc " + mcc + " mMnc " + mnc + "}";
+ return "{id=" + mId + ", iccId=" + mIccId + " simSlotIndex=" + mSimSlotIndex
+ + " displayName=" + mDisplayName + " nameSource=" + mNameSource + " color=" + mColor
+ + " number=" + mNumber + " dataRoaming=" + mDataRoaming + " simIconRes=" + mSimIconRes
+ + " mcc " + mMcc + " mnc " + mMnc + "}";
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index edfddc7..9cd533d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -209,7 +209,7 @@
public static final int DISPLAY_NUMBER_LAST = 2;
/** @hide */
- public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
+ public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
/**
* TelephonyProvider column name for permission for data roaming of a SIM.
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 6837d22..94874c8 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -127,7 +127,7 @@
@Override
public boolean onLongClick(View v) {
if (task.id >= 0 && thumbs != null) {
- mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ mAm.removeTask(task.id);
buildUi();
return true;
}
diff --git a/tools/aapt/AaptUtil.h b/tools/aapt/AaptUtil.h
index 47a704a..89e1ee8 100644
--- a/tools/aapt/AaptUtil.h
+++ b/tools/aapt/AaptUtil.h
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-#ifndef __AAPT_UTIL_H
-#define __AAPT_UTIL_H
+#ifndef H_AAPT_UTIL
+#define H_AAPT_UTIL
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -25,6 +27,38 @@
android::Vector<android::String8> split(const android::String8& str, const char sep);
android::Vector<android::String8> splitAndLowerCase(const android::String8& str, const char sep);
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::Vector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value);
+
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::SortedVector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value);
+
+//
+// Implementations
+//
+
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::Vector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value) {
+ ssize_t idx = keyedVector.indexOfKey(key);
+ if (idx < 0) {
+ idx = keyedVector.add(key, android::Vector<VALUE>());
+ }
+ keyedVector.editValueAt(idx).add(value);
+}
+
+template <typename KEY, typename VALUE>
+void appendValue(android::KeyedVector<KEY, android::SortedVector<VALUE> >& keyedVector,
+ const KEY& key, const VALUE& value) {
+ ssize_t idx = keyedVector.indexOfKey(key);
+ if (idx < 0) {
+ idx = keyedVector.add(key, android::SortedVector<VALUE>());
+ }
+ keyedVector.editValueAt(idx).add(value);
+}
+
} // namespace AaptUtil
-#endif // __AAPT_UTIL_H
+#endif // H_AAPT_UTIL
diff --git a/tools/aapt/AaptXml.cpp b/tools/aapt/AaptXml.cpp
index 708e405..b04a55d 100644
--- a/tools/aapt/AaptXml.cpp
+++ b/tools/aapt/AaptXml.cpp
@@ -41,7 +41,7 @@
}
size_t len;
- const uint16_t* str = tree.getAttributeStringValue(attrIndex, &len);
+ const char16_t* str = tree.getAttributeStringValue(attrIndex, &len);
return str ? String8(str, len) : String8();
}
@@ -103,7 +103,7 @@
if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
if (value.dataType == Res_value::TYPE_STRING) {
size_t len;
- const uint16_t* str = tree.getAttributeStringValue(idx, &len);
+ const char16_t* str = tree.getAttributeStringValue(idx, &len);
return str ? String8(str, len) : String8();
}
resTable.resolveReference(&value, 0);
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 2cbabe1..bc9c1f7 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -33,20 +33,20 @@
Command.cpp \
CrunchCache.cpp \
FileFinder.cpp \
+ Images.cpp \
Package.cpp \
- StringPool.cpp \
- XMLNode.cpp \
+ pseudolocalize.cpp \
+ qsort_r_compat.c \
+ Resource.cpp \
ResourceFilter.cpp \
ResourceIdCache.cpp \
ResourceTable.cpp \
- Images.cpp \
- Resource.cpp \
- pseudolocalize.cpp \
SourcePos.cpp \
+ StringPool.cpp \
WorkQueue.cpp \
+ XMLNode.cpp \
ZipEntry.cpp \
- ZipFile.cpp \
- qsort_r_compat.c
+ ZipFile.cpp
aaptTests := \
tests/AaptConfig_test.cpp \
@@ -88,16 +88,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libaapt
-
-LOCAL_SRC_FILES := $(aaptSources)
-LOCAL_C_INCLUDES += $(aaptCIncludes)
-
-LOCAL_CFLAGS += -Wno-format-y2k
-LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
-LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_CFLAGS += -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
+LOCAL_CPPFLAGS += $(aaptCppFlags)
ifeq (darwin,$(HOST_OS))
LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
endif
+LOCAL_C_INCLUDES += $(aaptCIncludes)
+LOCAL_SRC_FILES := $(aaptSources)
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -108,15 +105,11 @@
include $(CLEAR_VARS)
LOCAL_MODULE := aapt
-
-LOCAL_SRC_FILES := $(aaptMain)
-
-LOCAL_STATIC_LIBRARIES += \
- libaapt \
- $(aaptHostStaticLibs)
-
-LOCAL_LDLIBS += $(aaptHostLdLibs)
LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_CPPFLAGS += $(aaptCppFlags)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_SRC_FILES := $(aaptMain)
+LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
include $(BUILD_HOST_EXECUTABLE)
@@ -127,16 +120,12 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libaapt_tests
-
+LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_CPPFLAGS += $(aaptCppFlags)
+LOCAL_LDLIBS += $(aaptHostLdLibs)
LOCAL_SRC_FILES += $(aaptTests)
LOCAL_C_INCLUDES += $(LOCAL_PATH)
-
-LOCAL_STATIC_LIBRARIES += \
- libaapt \
- $(aaptHostStaticLibs)
-
-LOCAL_LDLIBS += $(aaptHostLdLibs)
-LOCAL_CFLAGS += $(aaptCFlags)
+LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
include $(BUILD_HOST_NATIVE_TEST)
@@ -148,13 +137,12 @@
include $(CLEAR_VARS)
LOCAL_MODULE := aapt
-
+LOCAL_CFLAGS += $(aaptCFlags)
LOCAL_SRC_FILES := $(aaptSources) $(aaptMain)
LOCAL_C_INCLUDES += \
$(aaptCIncludes) \
bionic \
external/stlport/stlport
-
LOCAL_SHARED_LIBRARIES := \
libandroidfw \
libutils \
@@ -162,14 +150,10 @@
libpng \
liblog \
libz
-
LOCAL_STATIC_LIBRARIES := \
libstlport_static \
libexpat_static
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += -Wno-non-virtual-dtor
-
include $(BUILD_EXECUTABLE)
endif # Not SDK_ONLY
diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h
index efb2453..fade53a 100644
--- a/tools/aapt/CacheUpdater.h
+++ b/tools/aapt/CacheUpdater.h
@@ -30,6 +30,8 @@
*/
class CacheUpdater {
public:
+ virtual ~CacheUpdater() {}
+
// Make sure all the directories along this path exist
virtual void ensureDirectoriesExist(String8 path) = 0;
@@ -107,4 +109,4 @@
Bundle* bundle;
};
-#endif // CACHE_UPDATER_H
\ No newline at end of file
+#endif // CACHE_UPDATER_H
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 2857b59..18b8e1e 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -11,9 +11,9 @@
#include <utils/List.h>
#include <utils/Errors.h>
-#include <stdlib.h>
+#include <cstdlib>
#include <getopt.h>
-#include <assert.h>
+#include <cassert>
using namespace android;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index a4c9dab..b9bd03a 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -261,7 +261,7 @@
ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
"minSdkVersion");
if (minSdkIndex >= 0) {
- const uint16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len);
+ const char16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len);
const char* minSdk8 = strdup(String8(minSdk16).string());
bundle->setManifestMinSdkVersion(minSdk8);
}
@@ -450,7 +450,7 @@
size_t len;
ssize_t index = parser.indexOfAttribute(ns, attr);
- const uint16_t* str;
+ const char16_t* str;
Res_value value;
if (index >= 0 && parser.getAttributeValue(index, &value) >= 0) {
const ResStringPool* pool = &parser.getStrings();
@@ -503,7 +503,7 @@
}
if (validChars) {
for (size_t i=0; i<len; i++) {
- uint16_t c = str[i];
+ char16_t c = str[i];
const char* p = validChars;
bool okay = false;
while (*p) {
@@ -1710,7 +1710,7 @@
}
size_t len;
ssize_t index = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "name");
- const uint16_t* id = block.getAttributeStringValue(index, &len);
+ const char16_t* id = block.getAttributeStringValue(index, &len);
if (id == NULL) {
fprintf(stderr, "%s:%d: missing name attribute in element <%s>.\n",
manifestPath.string(), block.getLineNumber(),
@@ -1753,7 +1753,7 @@
hasErrors = true;
}
syms->addStringSymbol(String8(e), idStr, srcPos);
- const uint16_t* cmt = block.getComment(&len);
+ const char16_t* cmt = block.getComment(&len);
if (cmt != NULL && *cmt != 0) {
//printf("Comment of %s: %s\n", String8(e).string(),
// String8(cmt).string());
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 4587a4b..0f94f85 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -399,7 +399,7 @@
ssize_t l10nIdx = block.indexOfAttribute(NULL, "localization");
if (l10nIdx >= 0) {
- const uint16_t* str = block.getAttributeStringValue(l10nIdx, &len);
+ const char16_t* str = block.getAttributeStringValue(l10nIdx, &len);
bool error;
uint32_t l10n_required = parse_flags(str, len, l10nRequiredFlags, &error);
if (error) {
@@ -1325,7 +1325,7 @@
size_t n = block.getAttributeCount();
for (size_t i = 0; i < n; i++) {
size_t length;
- const uint16_t* attr = block.getAttributeName(i, &length);
+ const char16_t* attr = block.getAttributeName(i, &length);
if (strcmp16(attr, name16.string()) == 0) {
name.setTo(block.getAttributeStringValue(i, &length));
} else if (strcmp16(attr, translatable16.string()) == 0) {
@@ -1441,14 +1441,14 @@
// translatable.
for (size_t i = 0; i < n; i++) {
size_t length;
- const uint16_t* attr = block.getAttributeName(i, &length);
+ const char16_t* attr = block.getAttributeName(i, &length);
if (strcmp16(attr, formatted16.string()) == 0) {
- const uint16_t* value = block.getAttributeStringValue(i, &length);
+ const char16_t* value = block.getAttributeStringValue(i, &length);
if (strcmp16(value, false16.string()) == 0) {
curIsFormatted = false;
}
} else if (strcmp16(attr, translatable16.string()) == 0) {
- const uint16_t* value = block.getAttributeStringValue(i, &length);
+ const char16_t* value = block.getAttributeStringValue(i, &length);
if (strcmp16(value, false16.string()) == 0) {
isTranslatable = false;
}
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 06769e4..2727b3d 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -21,7 +21,8 @@
#define NOISY(x) //x
-void strcpy16_htod(uint16_t* dst, const uint16_t* src)
+#if __cplusplus >= 201103L
+void strcpy16_htod(char16_t* dst, const char16_t* src)
{
while (*src) {
char16_t s = htods(*src);
@@ -30,6 +31,17 @@
}
*dst = 0;
}
+#endif
+
+void strcpy16_htod(uint16_t* dst, const char16_t* src)
+{
+ while (*src) {
+ uint16_t s = htods(static_cast<uint16_t>(*src));
+ *dst++ = s;
+ src++;
+ }
+ *dst = 0;
+}
void printStringPool(const ResStringPool* pool)
{
@@ -416,7 +428,7 @@
return NO_MEMORY;
}
- const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t);
+ const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(uint16_t);
size_t strPos = 0;
for (i=0; i<STRINGS; i++) {
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 1b3abfd..a9c7bec 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -26,7 +26,10 @@
#define PRINT_STRING_METRICS 0
-void strcpy16_htod(uint16_t* dst, const uint16_t* src);
+#if __cplusplus >= 201103L
+void strcpy16_htod(char16_t* dst, const char16_t* src);
+#endif
+void strcpy16_htod(uint16_t* dst, const char16_t* src);
void printStringPool(const ResStringPool* pool);
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 51a4154..899fb63 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -234,9 +234,9 @@
const String8 element8(element16);
size_t nslen;
- const uint16_t* ns = inXml->getElementNamespace(&nslen);
+ const char16_t* ns = inXml->getElementNamespace(&nslen);
if (ns == NULL) {
- ns = (const uint16_t*)"\0\0";
+ ns = (const char16_t*)"\0\0";
nslen = 0;
}
const String8 nspace(String16(ns, nslen));
@@ -291,9 +291,9 @@
} else if (code == ResXMLTree::END_TAG) {
size_t nslen;
- const uint16_t* ns = inXml->getElementNamespace(&nslen);
+ const char16_t* ns = inXml->getElementNamespace(&nslen);
if (ns == NULL) {
- ns = (const uint16_t*)"\0\0";
+ ns = (const char16_t*)"\0\0";
nslen = 0;
}
const String8 nspace(String16(ns, nslen));
@@ -422,7 +422,7 @@
}
static String8 build_namespace(const Vector<namespace_entry>& namespaces,
- const uint16_t* ns)
+ const char16_t* ns)
{
String8 str;
if (ns != NULL) {
@@ -453,9 +453,9 @@
int i;
if (code == ResXMLTree::START_TAG) {
size_t len;
- const uint16_t* ns16 = block->getElementNamespace(&len);
+ const char16_t* ns16 = block->getElementNamespace(&len);
String8 elemNs = build_namespace(namespaces, ns16);
- const uint16_t* com16 = block->getComment(&len);
+ const char16_t* com16 = block->getComment(&len);
if (com16) {
printf("%s <!-- %s -->\n", prefix.string(), String8(com16).string());
}
@@ -503,7 +503,7 @@
} else if (code == ResXMLTree::START_NAMESPACE) {
namespace_entry ns;
size_t len;
- const uint16_t* prefix16 = block->getNamespacePrefix(&len);
+ const char16_t* prefix16 = block->getNamespacePrefix(&len);
if (prefix16) {
ns.prefix = String8(prefix16);
} else {
@@ -518,7 +518,7 @@
depth--;
const namespace_entry& ns = namespaces.top();
size_t len;
- const uint16_t* prefix16 = block->getNamespacePrefix(&len);
+ const char16_t* prefix16 = block->getNamespacePrefix(&len);
String8 pr;
if (prefix16) {
pr = String8(prefix16);
diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
new file mode 100644
index 0000000..78242a8
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.view.ActionMode.Callback;
+import android.view.WindowManager.LayoutParams;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * An empty implementation of {@link Window.Callback} that always returns null/false.
+ */
+public class WindowCallback implements Window.Callback {
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchKeyShortcutEvent(KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchTrackballEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ return false;
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ return false;
+ }
+
+ @Override
+ public View onCreatePanelView(int featureId) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreatePanelMenu(int featureId, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onPreparePanel(int featureId, View view, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onMenuOpened(int featureId, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ return false;
+ }
+
+ @Override
+ public void onWindowAttributesChanged(LayoutParams attrs) {
+
+ }
+
+ @Override
+ public void onContentChanged() {
+
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+
+ }
+
+ @Override
+ public void onPanelClosed(int featureId, Menu menu) {
+
+ }
+
+ @Override
+ public boolean onSearchRequested() {
+ return false;
+ }
+
+ @Override
+ public ActionMode onWindowStartingActionMode(Callback callback) {
+ return null;
+ }
+
+ @Override
+ public void onActionModeStarted(ActionMode mode) {
+
+ }
+
+ @Override
+ public void onActionModeFinished(ActionMode mode) {
+
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/widget/Toolbar_Accessor.java b/tools/layoutlib/bridge/src/android/widget/Toolbar_Accessor.java
new file mode 100644
index 0000000..fdd1779
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/widget/Toolbar_Accessor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.content.Context;
+
+/**
+ * To access non public members of classes in {@link Toolbar}
+ */
+public class Toolbar_Accessor {
+ public static ActionMenuPresenter getActionMenuPresenter(Toolbar toolbar) {
+ return toolbar.getOuterActionMenuPresenter();
+ }
+
+ public static Context getPopupContext(Toolbar toolbar) {
+ return toolbar.getPopupContext();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 825731b..ec78712 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -19,6 +19,7 @@
import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+import com.android.annotations.NonNull;
import com.android.ide.common.rendering.api.Capability;
import com.android.ide.common.rendering.api.DrawableParams;
import com.android.ide.common.rendering.api.LayoutLog;
@@ -459,7 +460,7 @@
public static void setLog(LayoutLog log) {
// check only the thread currently owning the lock can do this.
- if (sLock.isHeldByCurrentThread() == false) {
+ if (!sLock.isHeldByCurrentThread()) {
throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
}
@@ -489,7 +490,6 @@
/**
* Returns the name of a framework resource whose value is an int array.
- * @param array
*/
public static String resolveResourceId(int[] array) {
sIntArrayWrapper.set(array);
@@ -502,6 +502,7 @@
* @param name the name of the resource.
* @return an {@link Integer} containing the resource id, or null if no resource were found.
*/
+ @NonNull
public static Integer getResourceId(ResourceType type, String name) {
Map<String, Integer> map = sRevRMap.get(type);
Integer value = null;
@@ -509,11 +510,8 @@
value = map.get(name);
}
- if (value == null) {
- value = sDynamicIds.getId(type, name);
- }
+ return value == null ? sDynamicIds.getId(type, name) : value;
- return value;
}
/**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index d804230..3d3afa4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -52,7 +52,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
-import android.content.res.TypedArray;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
@@ -127,7 +126,6 @@
* @param metrics the {@link DisplayMetrics}.
* @param renderResources the configured resources (both framework and projects) for this
* render.
- * @param projectCallback
* @param config the Configuration object for this render.
* @param targetSdkVersion the targetSdkVersion of the application.
*/
@@ -331,7 +329,7 @@
boolean attachToRoot, boolean skipCallbackParser) {
boolean isPlatformLayout = resource.isFramework();
- if (isPlatformLayout == false && skipCallbackParser == false) {
+ if (!isPlatformLayout && !skipCallbackParser) {
// check if the project callback can provide us with a custom parser.
ILayoutPullParser parser = getParser(resource);
@@ -663,7 +661,7 @@
}
String attrName = attribute.getFirst();
- boolean frameworkAttr = attribute.getSecond().booleanValue();
+ boolean frameworkAttr = attribute.getSecond();
String value = null;
if (set != null) {
value = set.getAttributeValue(
@@ -672,7 +670,7 @@
// if this is an app attribute, and the first get fails, try with the
// new res-auto namespace as well
- if (frameworkAttr == false && value == null) {
+ if (!frameworkAttr && value == null) {
value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName);
}
}
@@ -789,13 +787,13 @@
List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length);
// for each attribute, get its name so that we can search it in the style
- for (int i = 0 ; i < attrs.length ; i++) {
- Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]);
+ for (int attr : attrs) {
+ Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attr);
boolean isFramework = false;
if (resolvedResource != null) {
isFramework = true;
} else {
- resolvedResource = mProjectCallback.resolveResourceId(attrs[i]);
+ resolvedResource = mProjectCallback.resolveResourceId(attr);
}
if (resolvedResource != null) {
@@ -841,7 +839,7 @@
if (id == null) {
// generate a new id
- id = Integer.valueOf(++mDynamicIdGenerator);
+ id = ++mDynamicIdGenerator;
// and add it to the maps.
mDynamicIdToStyleMap.put(id, resValue);
@@ -860,19 +858,24 @@
}
public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
- Integer value = Bridge.getResourceId(resType, resName);
- if (value != null) {
- return value.intValue();
+ if (getRenderResources().getFrameworkResource(resType, resName) != null) {
+ // Bridge.getResourceId creates a new resource id if an existing one isn't found. So,
+ // we check for the existence of the resource before calling it.
+ return Bridge.getResourceId(resType, resName);
}
return defValue;
}
public int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
- if (mProjectCallback != null) {
- Integer value = mProjectCallback.getResourceId(resType, resName);
- if (value != null) {
- return value.intValue();
+ // getResourceId creates a new resource id if an existing resource id isn't found. So, we
+ // check for the existence of the resource before calling it.
+ if (getRenderResources().getProjectResource(resType, resName) != null) {
+ if (mProjectCallback != null) {
+ Integer value = mProjectCallback.getResourceId(resType, resName);
+ if (value != null) {
+ return value;
+ }
}
}
@@ -1455,9 +1458,6 @@
return null;
}
- /**
- * @hide
- */
@Override
public int getUserId() {
return 0; // not used
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
index d95c815..57fd68e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -18,36 +18,24 @@
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
-import com.android.ide.common.rendering.api.ActionBarCallback;
-import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
-import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams;
import com.android.internal.R;
-import com.android.internal.app.WindowDecorActionBar;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
-import com.android.internal.widget.ActionBarAccessor;
-import com.android.internal.widget.ActionBarContainer;
-import com.android.internal.widget.ActionBarView;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.ResourceHelper;
-import com.android.resources.ResourceType;
-import android.app.ActionBar;
-import android.app.ActionBar.Tab;
-import android.app.ActionBar.TabListener;
-import android.app.FragmentTransaction;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.TypedValue;
-import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.MenuInflater;
import android.view.View;
+import android.view.View.MeasureSpec;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ActionMenuPresenter;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
@@ -56,172 +44,72 @@
import java.util.ArrayList;
-/**
- * A layout representing the action bar.
- */
-public class ActionBarLayout extends LinearLayout {
+public class ActionBarLayout {
+
+ private static final String LAYOUT_ATTR_NAME = "windowActionBarFullscreenDecorLayout";
+
+ // The Action Bar
+ @NonNull private CustomActionBarWrapper mActionBar;
// Store another reference to the context so that we don't have to cast it repeatedly.
@NonNull private final BridgeContext mBridgeContext;
- @NonNull private final Context mThemedContext;
- @NonNull private final ActionBar mActionBar;
-
- // Data for Action Bar.
- @Nullable private final String mIcon;
- @Nullable private final String mTitle;
- @Nullable private final String mSubTitle;
- private final boolean mSplit;
- private final boolean mShowHomeAsUp;
- private final int mNavMode;
-
- // Helper fields.
- @NonNull private final MenuBuilder mMenuBuilder;
- private final int mPopupMaxWidth;
- @NonNull private final RenderResources res;
- @Nullable private final ActionBarView mActionBarView;
- @Nullable private FrameLayout mContentRoot;
- @NonNull private final ActionBarCallback mCallback;
+ @NonNull private FrameLayout mContentRoot;
// A fake parent for measuring views.
@Nullable private ViewGroup mMeasureParent;
- public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params) {
+ /**
+ * Inflate the action bar and attach it to {@code parentView}
+ */
+ public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params,
+ @NonNull ViewGroup parentView) {
- super(context);
- setOrientation(LinearLayout.HORIZONTAL);
- setGravity(Gravity.CENTER_VERTICAL);
-
- // Inflate action bar layout.
- LayoutInflater.from(context).inflate(R.layout.screen_action_bar, this,
- true /*attachToRoot*/);
- mActionBar = new WindowDecorActionBar(this);
-
- // Set contexts.
mBridgeContext = context;
- mThemedContext = mActionBar.getThemedContext();
- // Set data for action bar.
- mCallback = params.getProjectCallback().getActionBarCallback();
- mIcon = params.getAppIcon();
- mTitle = params.getAppLabel();
- // Split Action Bar when the screen size is narrow and the application requests split action
- // bar when narrow.
- mSplit = context.getResources().getBoolean(R.bool.split_action_bar_is_narrow) &&
- mCallback.getSplitActionBarWhenNarrow();
- mNavMode = mCallback.getNavigationMode();
- // TODO: Support Navigation Drawer Indicator.
- mShowHomeAsUp = mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP;
- mSubTitle = mCallback.getSubTitle();
-
-
- // Set helper fields.
- mMenuBuilder = new MenuBuilder(mThemedContext);
- res = mBridgeContext.getRenderResources();
- mPopupMaxWidth = Math.max(mBridgeContext.getMetrics().widthPixels / 2,
- mThemedContext.getResources().getDimensionPixelSize(
- R.dimen.config_prefDialogWidth));
- mActionBarView = (ActionBarView) findViewById(R.id.action_bar);
- mContentRoot = (FrameLayout) findViewById(android.R.id.content);
-
- setupActionBar();
- }
-
- /**
- * Sets up the action bar by filling the appropriate data.
- */
- private void setupActionBar() {
- // Add title and sub title.
- ResourceValue titleValue = res.findResValue(mTitle, false /*isFramework*/);
- if (titleValue != null && titleValue.getValue() != null) {
- mActionBar.setTitle(titleValue.getValue());
+ ResourceValue layoutName = context.getRenderResources()
+ .findItemInTheme(LAYOUT_ATTR_NAME, true);
+ if (layoutName != null) {
+ // We may need to resolve the reference obtained.
+ layoutName = context.getRenderResources().findResValue(layoutName.getValue(),
+ layoutName.isFramework());
+ }
+ int layoutId = 0;
+ String error = null;
+ if (layoutName == null) {
+ error = "Unable to find action bar layout (" + LAYOUT_ATTR_NAME
+ + ") in the current theme.";
} else {
- mActionBar.setTitle(mTitle);
- }
- if (mSubTitle != null) {
- mActionBar.setSubtitle(mSubTitle);
- }
-
- // Add show home as up icon.
- if (mShowHomeAsUp) {
- mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
- }
-
- // Set the navigation mode.
- mActionBar.setNavigationMode(mNavMode);
- if (mNavMode == ActionBar.NAVIGATION_MODE_TABS) {
- setupTabs(3);
- }
-
- if (mActionBarView != null) {
- // If the action bar style doesn't specify an icon, set the icon obtained from the session
- // params.
- if (!mActionBarView.hasIcon() && mIcon != null) {
- Drawable iconDrawable = getDrawable(mIcon, false /*isFramework*/);
- if (iconDrawable != null) {
- mActionBar.setIcon(iconDrawable);
- }
- }
-
- // Set action bar to be split, if needed.
- ActionBarContainer splitView = (ActionBarContainer) findViewById(R.id.split_action_bar);
- mActionBarView.setSplitView(splitView);
- mActionBarView.setSplitToolbar(mSplit);
-
- inflateMenus();
- }
- }
-
- /**
- * Gets the menus to add to the action bar from the callback, resolves them, inflates them and
- * adds them to the action bar.
- */
- private void inflateMenus() {
- if (mActionBarView == null) {
- return;
- }
- final MenuInflater inflater = new MenuInflater(mThemedContext);
- for (String name : mCallback.getMenuIdNames()) {
- if (mBridgeContext.getRenderResources().getProjectResource(ResourceType.MENU, name)
- != null) {
- int id = mBridgeContext.getProjectResourceValue(ResourceType.MENU, name, -1);
- if (id > -1) {
- inflater.inflate(id, mMenuBuilder);
- }
+ layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(),
+ layoutName.getName(), 0);
+ if (layoutId == 0) {
+ error = String.format("Unable to resolve attribute \"%s\" of type \"%s\"",
+ layoutName.getName(), layoutName.getResourceType());
}
}
- mActionBarView.setMenu(mMenuBuilder, null /*callback*/);
- }
-
- // TODO: Use an adapter, like List View to set up tabs.
- private void setupTabs(int num) {
- for (int i = 1; i <= num; i++) {
- Tab tab = mActionBar.newTab().setText("Tab" + i).setTabListener(new TabListener() {
- @Override
- public void onTabUnselected(Tab t, FragmentTransaction ft) {
- // pass
- }
- @Override
- public void onTabSelected(Tab t, FragmentTransaction ft) {
- // pass
- }
- @Override
- public void onTabReselected(Tab t, FragmentTransaction ft) {
- // pass
- }
- });
- mActionBar.addTab(tab);
+ if (layoutId == 0) {
+ throw new RuntimeException(error);
}
- }
+ // Inflate action bar layout.
+ View decorContent = LayoutInflater.from(context).inflate(layoutId, parentView, true);
- @Nullable
- private Drawable getDrawable(@NonNull String name, boolean isFramework) {
- ResourceValue value = res.findResValue(name, isFramework);
- value = res.resolveResValue(value);
- if (value != null) {
- return ResourceHelper.getDrawable(value, mBridgeContext);
+ mActionBar = CustomActionBarWrapper.getActionBarWrapper(context, params, decorContent);
+
+ FrameLayout contentRoot = (FrameLayout) parentView.findViewById(android.R.id.content);
+
+ // If something went wrong and we were not able to initialize the content root,
+ // just add a frame layout inside this and return.
+ if (contentRoot == null) {
+ contentRoot = new FrameLayout(context);
+ contentRoot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT));
+ parentView.addView(contentRoot);
+ mContentRoot = contentRoot;
+ } else {
+ mContentRoot = contentRoot;
+ mActionBar.setupActionBar();
+ mActionBar.inflateMenus();
}
- return null;
}
/**
@@ -229,7 +117,7 @@
* the content frame which shall serve as the new content root.
*/
public void createMenuPopup() {
- assert mContentRoot != null && findViewById(android.R.id.content) == mContentRoot
+ assert mContentRoot.getId() == android.R.id.content
: "Action Bar Menus have already been created.";
if (!isOverflowPopupNeeded()) {
@@ -237,7 +125,7 @@
}
// Create a layout to hold the menus and the user's content.
- RelativeLayout layout = new RelativeLayout(mThemedContext);
+ RelativeLayout layout = new RelativeLayout(mActionBar.getPopupContext());
layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
mContentRoot.addView(layout);
@@ -259,13 +147,14 @@
@NonNull
private View createMenuView() {
DisplayMetrics metrics = mBridgeContext.getMetrics();
- OverflowMenuAdapter adapter = new OverflowMenuAdapter(mMenuBuilder, mThemedContext);
+ MenuBuilder menu = mActionBar.getMenuBuilder();
+ OverflowMenuAdapter adapter = new OverflowMenuAdapter(menu, mActionBar.getPopupContext());
- LinearLayout layout = new LinearLayout(mThemedContext);
+ LinearLayout layout = new LinearLayout(mActionBar.getPopupContext());
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
measureContentWidth(adapter), LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END);
- if (mSplit) {
+ if (mActionBar.isSplit()) {
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
// TODO: Find correct value instead of hardcoded 10dp.
layoutParams.bottomMargin = getPixelValue("-10dp", metrics);
@@ -273,7 +162,7 @@
layoutParams.topMargin = getPixelValue("-10dp", metrics);
}
layout.setLayoutParams(layoutParams);
- final TypedArray a = mThemedContext.obtainStyledAttributes(null,
+ final TypedArray a = mActionBar.getPopupContext().obtainStyledAttributes(null,
R.styleable.PopupWindow, R.attr.popupMenuStyle, 0);
layout.setBackground(a.getDrawable(R.styleable.PopupWindow_popupBackground));
layout.setDividerDrawable(a.getDrawable(R.attr.actionBarDivider));
@@ -282,20 +171,25 @@
layout.setDividerPadding(getPixelValue("12dp", metrics));
layout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
- ListView listView = new ListView(mThemedContext, null, R.attr.dropDownListViewStyle);
+ ListView listView = new ListView(mActionBar.getPopupContext(), null,
+ R.attr.dropDownListViewStyle);
listView.setAdapter(adapter);
layout.addView(listView);
return layout;
}
private boolean isOverflowPopupNeeded() {
- boolean needed = mCallback.isOverflowPopupNeeded();
+ boolean needed = mActionBar.isOverflowPopupNeeded();
if (!needed) {
return false;
}
// Copied from android.widget.ActionMenuPresenter.updateMenuView()
- ArrayList<MenuItemImpl> menus = mMenuBuilder.getNonActionItems();
- if (ActionBarAccessor.getActionMenuPresenter(mActionBarView).isOverflowReserved() &&
+ ArrayList<MenuItemImpl> menus = mActionBar.getMenuBuilder().getNonActionItems();
+ ActionMenuPresenter presenter = mActionBar.getActionMenuPresenter();
+ if (presenter == null) {
+ throw new RuntimeException("Failed to create a Presenter for Action Bar Menus.");
+ }
+ if (presenter.isOverflowReserved() &&
menus != null) {
final int count = menus.size();
if (count == 1) {
@@ -307,7 +201,7 @@
return needed;
}
- @Nullable
+ @NonNull
public FrameLayout getContentRoot() {
return mContentRoot;
}
@@ -319,6 +213,7 @@
View itemView = null;
int itemType = 0;
+ Context context = mActionBar.getPopupContext();
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final int count = adapter.getCount();
@@ -330,15 +225,17 @@
}
if (mMeasureParent == null) {
- mMeasureParent = new FrameLayout(mThemedContext);
+ mMeasureParent = new FrameLayout(context);
}
itemView = adapter.getView(i, itemView, mMeasureParent);
itemView.measure(widthMeasureSpec, heightMeasureSpec);
final int itemWidth = itemView.getMeasuredWidth();
- if (itemWidth >= mPopupMaxWidth) {
- return mPopupMaxWidth;
+ int popupMaxWidth = Math.max(mBridgeContext.getMetrics().widthPixels / 2,
+ context.getResources().getDimensionPixelSize(R.dimen.config_prefDialogWidth));
+ if (itemWidth >= popupMaxWidth) {
+ return popupMaxWidth;
} else if (itemWidth > maxWidth) {
maxWidth = itemWidth;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
new file mode 100644
index 0000000..70b9cc3
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.bars;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.ActionBarCallback;
+import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.internal.R;
+import com.android.internal.app.ToolbarActionBar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.widget.ActionBarAccessor;
+import com.android.internal.widget.ActionBarView;
+import com.android.internal.widget.DecorToolbar;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowCallback;
+import android.widget.ActionMenuPresenter;
+import android.widget.Toolbar;
+import android.widget.Toolbar_Accessor;
+
+import static com.android.SdkConstants.ANDROID_NS_NAME_PREFIX;
+import static com.android.resources.ResourceType.MENU;
+
+/**
+ * A common API to access {@link ToolbarActionBar} and {@link WindowDecorActionBar}.
+ */
+public abstract class CustomActionBarWrapper {
+
+ @NonNull protected ActionBar mActionBar;
+ @NonNull protected SessionParams mParams;
+ @NonNull protected ActionBarCallback mCallback;
+ @NonNull protected BridgeContext mContext;
+
+ /**
+ * Returns a wrapper around different implementations of the Action Bar to provide a common API.
+ *
+ * @param decorContent the top level view returned by inflating
+ * ?attr/windowActionBarFullscreenDecorLayout
+ */
+ @NonNull
+ public static CustomActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context,
+ @NonNull SessionParams params, @NonNull View decorContent) {
+ View view = decorContent.findViewById(R.id.action_bar);
+ if (view instanceof Toolbar) {
+ return new ToolbarWrapper(context, params, ((Toolbar) view)
+ );
+ } else if (view instanceof ActionBarView) {
+ return new WindowActionBarWrapper(context, params, decorContent, ((ActionBarView) view)
+ );
+ } else {
+ throw new IllegalStateException("Can't make an action bar out of " +
+ view.getClass().getSimpleName());
+ }
+ }
+
+ CustomActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+ @NonNull ActionBar actionBar) {
+ mActionBar = actionBar;
+ mParams = params;
+ mCallback = params.getProjectCallback().getActionBarCallback();
+ mContext = context;
+ }
+
+ protected void setupActionBar() {
+ // Do the things that are common to all implementations.
+ RenderResources res = mContext.getRenderResources();
+
+ String title = mParams.getAppLabel();
+ ResourceValue titleValue = res.findResValue(title, false);
+ if (titleValue != null && titleValue.getValue() != null) {
+ mActionBar.setTitle(titleValue.getValue());
+ } else {
+ mActionBar.setTitle(title);
+ }
+
+ String subTitle = mCallback.getSubTitle();
+ if (subTitle != null) {
+ mActionBar.setSubtitle(subTitle);
+ }
+
+ // Add show home as up icon.
+ if (mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP) {
+ mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
+ }
+ }
+
+ protected boolean isSplit() {
+ return getDecorToolbar().isSplit();
+ }
+
+ protected boolean isOverflowPopupNeeded() {
+ return mCallback.isOverflowPopupNeeded();
+ }
+
+ /**
+ * Gets the menus to add to the action bar from the callback, resolves them, inflates them and
+ * adds them to the action bar.
+ */
+ protected void inflateMenus() {
+ MenuInflater inflater = new MenuInflater(getActionMenuContext());
+ MenuBuilder menuBuilder = getMenuBuilder();
+ for (String name : mCallback.getMenuIdNames()) {
+ int id;
+ if (name.startsWith(ANDROID_NS_NAME_PREFIX)) {
+ // Framework menu.
+ name = name.substring(ANDROID_NS_NAME_PREFIX.length());
+ id = mContext.getFrameworkResourceValue(MENU, name, -1);
+ } else {
+ // Project menu.
+ id = mContext.getProjectResourceValue(MENU, name, -1);
+ }
+ if (id > -1) {
+ inflater.inflate(id, menuBuilder);
+ }
+ }
+ }
+
+ /**
+ * The context used for the ActionBar and the menus in the ActionBarView.
+ */
+ @NonNull
+ protected Context getActionMenuContext() {
+ return mActionBar.getThemedContext();
+ }
+
+ /**
+ * The context used to inflate the popup menu.
+ */
+ @NonNull
+ abstract Context getPopupContext();
+
+ /**
+ * The Menu in which to inflate the user's menus.
+ */
+ @NonNull
+ abstract MenuBuilder getMenuBuilder();
+
+ @Nullable
+ abstract ActionMenuPresenter getActionMenuPresenter();
+
+ /**
+ * Framework's wrapper over two ActionBar implementations.
+ */
+ @NonNull
+ abstract DecorToolbar getDecorToolbar();
+
+ // ---- The implementations ----
+
+ /**
+ * Material theme uses {@link Toolbar} as the action bar. This wrapper provides access to
+ * Toolbar using a common API.
+ */
+ private static class ToolbarWrapper extends CustomActionBarWrapper {
+
+ @NonNull
+ private final Toolbar mToolbar; // This is the view.
+
+ ToolbarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+ @NonNull Toolbar toolbar) {
+ super(context, params, new ToolbarActionBar(toolbar, "", new WindowCallback())
+ );
+ mToolbar = toolbar;
+ }
+
+ @Override
+ protected void inflateMenus() {
+ super.inflateMenus();
+ // Inflating the menus doesn't initialize the ActionMenuPresenter. Setting a fake menu
+ // and then setting it back does the trick.
+ MenuBuilder menu = getMenuBuilder();
+ DecorToolbar decorToolbar = getDecorToolbar();
+ decorToolbar.setMenu(new MenuBuilder(getActionMenuContext()), null);
+ decorToolbar.setMenu(menu, null);
+ }
+
+ @NonNull
+ @Override
+ Context getPopupContext() {
+ return Toolbar_Accessor.getPopupContext(mToolbar);
+ }
+
+ @NonNull
+ @Override
+ MenuBuilder getMenuBuilder() {
+ return (MenuBuilder) mToolbar.getMenu();
+ }
+
+ @Nullable
+ @Override
+ ActionMenuPresenter getActionMenuPresenter() {
+ return Toolbar_Accessor.getActionMenuPresenter(mToolbar);
+ }
+
+ @NonNull
+ @Override
+ DecorToolbar getDecorToolbar() {
+ return mToolbar.getWrapper();
+ }
+ }
+
+ /**
+ * Holo theme uses {@link WindowDecorActionBar} as the action bar. This wrapper provides
+ * access to it using a common API.
+ */
+ private static class WindowActionBarWrapper extends CustomActionBarWrapper{
+
+ @NonNull
+ private final WindowDecorActionBar mActionBar;
+ private final ActionBarView mActionBarView;
+ private MenuBuilder mMenuBuilder;
+
+ public WindowActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params,
+ @NonNull View decorContentRoot, @NonNull ActionBarView actionBarView) {
+ super(context, params, new WindowDecorActionBar(decorContentRoot)
+ );
+ mActionBarView = actionBarView;
+ mActionBar = ((WindowDecorActionBar) super.mActionBar);
+ }
+
+ @Override
+ protected void setupActionBar() {
+ super.setupActionBar();
+
+ // Set the navigation mode.
+ int navMode = mCallback.getNavigationMode();
+ mActionBar.setNavigationMode(navMode);
+ //noinspection deprecation
+ if (navMode == ActionBar.NAVIGATION_MODE_TABS) {
+ setupTabs(3);
+ }
+
+ String icon = mParams.getAppIcon();
+ // If the action bar style doesn't specify an icon, set the icon obtained from the
+ // session params.
+ if (!mActionBar.hasIcon() && icon != null) {
+ Drawable iconDrawable = getDrawable(icon, false);
+ if (iconDrawable != null) {
+ mActionBar.setIcon(iconDrawable);
+ }
+ }
+
+ // Set action bar to be split, if needed.
+ ViewGroup splitView = (ViewGroup) mActionBarView.findViewById(R.id.split_action_bar);
+ if (splitView != null) {
+ mActionBarView.setSplitView(splitView);
+ Resources res = mContext.getResources();
+ boolean split = res.getBoolean(R.bool.split_action_bar_is_narrow)
+ && mCallback.getSplitActionBarWhenNarrow();
+ mActionBarView.setSplitToolbar(split);
+ }
+ }
+
+ @Override
+ protected void inflateMenus() {
+ super.inflateMenus();
+ // The super implementation doesn't set the menu on the view. Set it here.
+ mActionBarView.setMenu(getMenuBuilder(), null);
+ }
+
+ @NonNull
+ @Override
+ Context getPopupContext() {
+ return getActionMenuContext();
+ }
+
+ @NonNull
+ @Override
+ MenuBuilder getMenuBuilder() {
+ if (mMenuBuilder == null) {
+ mMenuBuilder = new MenuBuilder(getActionMenuContext());
+ }
+ return mMenuBuilder;
+ }
+
+ @Nullable
+ @Override
+ ActionMenuPresenter getActionMenuPresenter() {
+ return ActionBarAccessor.getActionMenuPresenter(mActionBarView);
+ }
+
+ @NonNull
+ @Override
+ ActionBarView getDecorToolbar() {
+ return mActionBarView;
+ }
+
+ // TODO: Use an adapter, like List View to set up tabs.
+ @SuppressWarnings("deprecation") // For Tab
+ private void setupTabs(int num) {
+ for (int i = 1; i <= num; i++) {
+ Tab tab = mActionBar.newTab().setText("Tab" + i).setTabListener(new TabListener() {
+ @Override
+ public void onTabUnselected(Tab t, FragmentTransaction ft) {
+ // pass
+ }
+ @Override
+ public void onTabSelected(Tab t, FragmentTransaction ft) {
+ // pass
+ }
+ @Override
+ public void onTabReselected(Tab t, FragmentTransaction ft) {
+ // pass
+ }
+ });
+ mActionBar.addTab(tab);
+ }
+ }
+
+ @Nullable
+ private Drawable getDrawable(@NonNull String name, boolean isFramework) {
+ RenderResources res = mContext.getRenderResources();
+ ResourceValue value = res.findResValue(name, isFramework);
+ value = res.resolveResValue(value);
+ if (value != null) {
+ return ResourceHelper.getDrawable(value, mContext);
+ }
+ return null;
+ }
+
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index b8dce70..a2eed9a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -353,8 +353,7 @@
// if the theme says no title/action bar, then the size will be 0
if (mActionBarSize > 0) {
- ActionBarLayout actionBar = createActionBar(context, params);
- backgroundLayout.addView(actionBar);
+ ActionBarLayout actionBar = createActionBar(context, params, backgroundLayout);
actionBar.createMenuPopup();
mContentRoot = actionBar.getContentRoot();
} else if (mTitleBarSize > 0) {
@@ -1624,11 +1623,9 @@
/**
* Creates the action bar. Also queries the project callback for missing information.
*/
- private ActionBarLayout createActionBar(BridgeContext context, SessionParams params) {
- ActionBarLayout actionBar = new ActionBarLayout(context, params);
- actionBar.setLayoutParams(new LinearLayout.LayoutParams(
- LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- return actionBar;
+ private ActionBarLayout createActionBar(BridgeContext context, SessionParams params,
+ ViewGroup parentView) {
+ return new ActionBarLayout(context, params, parentView);
}
public BufferedImage getImage() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
index a1fae95..979aa33 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java
@@ -16,6 +16,7 @@
package com.android.layoutlib.bridge.util;
+import com.android.annotations.NonNull;
import com.android.resources.ResourceType;
import com.android.util.Pair;
@@ -48,6 +49,7 @@
* @param name the name of the resource
* @return an integer.
*/
+ @NonNull
public Integer getId(ResourceType type, String name) {
return getId(Pair.of(type, name));
}
@@ -59,10 +61,11 @@
* @param resource the type/name of the resource
* @return an integer.
*/
+ @NonNull
public Integer getId(Pair<ResourceType, String> resource) {
Integer value = mDynamicIds.get(resource);
if (value == null) {
- value = Integer.valueOf(++mDynamicSeed);
+ value = ++mDynamicSeed;
mDynamicIds.put(resource, value);
mRevDynamicIds.put(value, resource);
}
diff --git a/tools/split-select/Abi.cpp b/tools/split-select/Abi.cpp
index 20654b6..180dd8f 100644
--- a/tools/split-select/Abi.cpp
+++ b/tools/split-select/Abi.cpp
@@ -16,42 +16,58 @@
#include "Abi.h"
+using namespace android;
+
namespace split {
namespace abi {
-static const std::vector<Variant> sNoneVariants = {};
-static const std::vector<Variant> sArmVariants =
- {Variant::armeabi, Variant::armeabi_v7a, Variant::arm64_v8a};
-static const std::vector<Variant> sIntelVariants = {Variant::x86, Variant::x86_64};
-static const std::vector<Variant> sMipsVariants = {Variant::mips, Variant::mips64};
+static Vector<Variant> buildVariants(Variant v1, Variant v2) {
+ Vector<Variant> v;
+ v.add(v1);
+ v.add(v2);
+ return v;
+}
+
+static Vector<Variant> buildVariants(Variant v1, Variant v2, Variant v3) {
+ Vector<Variant> v;
+ v.add(v1);
+ v.add(v2);
+ v.add(v3);
+ return v;
+}
+
+static const Vector<Variant> sNoneVariants;
+static const Vector<Variant> sArmVariants = buildVariants(Variant_armeabi, Variant_armeabi_v7a, Variant_arm64_v8a);
+static const Vector<Variant> sIntelVariants = buildVariants(Variant_x86, Variant_x86_64);
+static const Vector<Variant> sMipsVariants = buildVariants(Variant_mips, Variant_mips64);
Family getFamily(Variant variant) {
switch (variant) {
- case Variant::none:
- return Family::none;
- case Variant::armeabi:
- case Variant::armeabi_v7a:
- case Variant::arm64_v8a:
- return Family::arm;
- case Variant::x86:
- case Variant::x86_64:
- return Family::intel;
- case Variant::mips:
- case Variant::mips64:
- return Family::mips;
+ case Variant_none:
+ return Family_none;
+ case Variant_armeabi:
+ case Variant_armeabi_v7a:
+ case Variant_arm64_v8a:
+ return Family_arm;
+ case Variant_x86:
+ case Variant_x86_64:
+ return Family_intel;
+ case Variant_mips:
+ case Variant_mips64:
+ return Family_mips;
}
- return Family::none;
+ return Family_none;
}
-const std::vector<Variant>& getVariants(Family family) {
+const Vector<Variant>& getVariants(Family family) {
switch (family) {
- case Family::none:
+ case Family_none:
return sNoneVariants;
- case Family::arm:
+ case Family_arm:
return sArmVariants;
- case Family::intel:
+ case Family_intel:
return sIntelVariants;
- case Family::mips:
+ case Family_mips:
return sMipsVariants;
}
return sNoneVariants;
@@ -59,21 +75,21 @@
const char* toString(Variant variant) {
switch (variant) {
- case Variant::none:
+ case Variant_none:
return "";
- case Variant::armeabi:
+ case Variant_armeabi:
return "armeabi";
- case Variant::armeabi_v7a:
+ case Variant_armeabi_v7a:
return "armeabi-v7a";
- case Variant::arm64_v8a:
+ case Variant_arm64_v8a:
return "arm64-v8a";
- case Variant::x86:
+ case Variant_x86:
return "x86";
- case Variant::x86_64:
+ case Variant_x86_64:
return "x86_64";
- case Variant::mips:
+ case Variant_mips:
return "mips";
- case Variant::mips64:
+ case Variant_mips64:
return "mips64";
}
return "";
diff --git a/tools/split-select/Abi.h b/tools/split-select/Abi.h
index 3e00eba..85b4d62 100644
--- a/tools/split-select/Abi.h
+++ b/tools/split-select/Abi.h
@@ -17,31 +17,31 @@
#ifndef H_ANDROID_SPLIT_ABI
#define H_ANDROID_SPLIT_ABI
-#include <vector>
+#include <utils/Vector.h>
namespace split {
namespace abi {
-enum class Variant {
- none = 0,
- armeabi,
- armeabi_v7a,
- arm64_v8a,
- x86,
- x86_64,
- mips,
- mips64,
+enum Variant {
+ Variant_none = 0,
+ Variant_armeabi,
+ Variant_armeabi_v7a,
+ Variant_arm64_v8a,
+ Variant_x86,
+ Variant_x86_64,
+ Variant_mips,
+ Variant_mips64,
};
-enum class Family {
- none,
- arm,
- intel,
- mips,
+enum Family {
+ Family_none,
+ Family_arm,
+ Family_intel,
+ Family_mips,
};
Family getFamily(Variant variant);
-const std::vector<Variant>& getVariants(Family family);
+const android::Vector<Variant>& getVariants(Family family);
const char* toString(Variant variant);
} // namespace abi
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
index d0b7287..dc48ea8 100644
--- a/tools/split-select/Android.mk
+++ b/tools/split-select/Android.mk
@@ -17,10 +17,6 @@
# This tool is prebuilt if we're doing an app-only build.
ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
-# TODO(adamlesinski): Enable OS X builds when I figure out how
-# to build with clang and libc++
-ifneq ($(HOST_OS),darwin)
-
# ==========================================================
# Setup some common variables for the different build
# targets here.
@@ -55,7 +51,7 @@
libexpat \
libziparchive-host
-cFlags := -std=c++11 -Wall -Werror
+cFlags := -Wall -Werror
ifeq ($(HOST_OS),linux)
hostLdLibs += -lrt -ldl -lpthread
@@ -115,5 +111,4 @@
include $(BUILD_HOST_EXECUTABLE)
-endif # Not OS X
endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/split-select/Grouper.cpp b/tools/split-select/Grouper.cpp
index 15edf89..22685cd 100644
--- a/tools/split-select/Grouper.cpp
+++ b/tools/split-select/Grouper.cpp
@@ -16,25 +16,17 @@
#include "Grouper.h"
+#include "aapt/AaptUtil.h"
#include "SplitDescription.h"
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
using namespace android;
+using AaptUtil::appendValue;
namespace split {
-template <typename Key, typename Value>
-static void addToVector(KeyedVector<Key, SortedVector<Value> >& group,
- const Key& key, const Value& value) {
- ssize_t idx = group.indexOfKey(key);
- if (idx < 0) {
- idx = group.add(key, SortedVector<Value>());
- }
- group.editValueAt(idx).add(value);
-}
-
Vector<SortedVector<SplitDescription> >
groupByMutualExclusivity(const Vector<SplitDescription>& splits) {
Vector<SortedVector<SplitDescription> > groups;
@@ -43,20 +35,22 @@
KeyedVector<SplitDescription, SortedVector<SplitDescription> > densityGroups;
KeyedVector<SplitDescription, SortedVector<SplitDescription> > abiGroups;
KeyedVector<SplitDescription, SortedVector<SplitDescription> > localeGroups;
- for (const SplitDescription& split : splits) {
+ const size_t splitCount = splits.size();
+ for (size_t i = 0; i < splitCount; i++) {
+ const SplitDescription& split = splits[i];
if (split.config.density != 0) {
SplitDescription key(split);
key.config.density = 0;
key.config.sdkVersion = 0; // Ignore density so we can support anydpi.
- addToVector(densityGroups, key, split);
- } else if (split.abi != abi::Variant::none) {
+ appendValue(densityGroups, key, split);
+ } else if (split.abi != abi::Variant_none) {
SplitDescription key(split);
- key.abi = abi::Variant::none;
- addToVector(abiGroups, key, split);
+ key.abi = abi::Variant_none;
+ appendValue(abiGroups, key, split);
} else if (split.config.locale != 0) {
SplitDescription key(split);
key.config.clearLocale();
- addToVector(localeGroups, key, split);
+ appendValue(localeGroups, key, split);
} else {
groups.add();
groups.editTop().add(split);
diff --git a/tools/split-select/Grouper_test.cpp b/tools/split-select/Grouper_test.cpp
index 4d146cd..a5f9c5a 100644
--- a/tools/split-select/Grouper_test.cpp
+++ b/tools/split-select/Grouper_test.cpp
@@ -19,7 +19,6 @@
#include "SplitDescription.h"
#include <gtest/gtest.h>
-#include <initializer_list>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -55,7 +54,11 @@
}
void addSplit(Vector<SplitDescription>& splits, const char* str);
- void expectHasGroupWithSplits(std::initializer_list<const char*> l);
+ void expectHasGroupWithSplits(const char* a);
+ void expectHasGroupWithSplits(const char* a, const char* b);
+ void expectHasGroupWithSplits(const char* a, const char* b, const char* c);
+ void expectHasGroupWithSplits(const char* a, const char* b, const char* c, const char* d);
+ void expectHasGroupWithSplits(const Vector<const char*>& expectedStrs);
Vector<SortedVector<SplitDescription> > mGroups;
};
@@ -65,39 +68,70 @@
}
TEST_F(GrouperTest, shouldGroupDensities) {
- expectHasGroupWithSplits({"en-rUS-sw300dp-hdpi", "en-rUS-sw300dp-xhdpi"});
- expectHasGroupWithSplits({"en-rUS-sw600dp-hdpi", "en-rUS-sw600dp-xhdpi"});
- expectHasGroupWithSplits({"fr-rFR-sw600dp-hdpi", "fr-rFR-sw600dp-xhdpi"});
- expectHasGroupWithSplits({"hdpi", "xhdpi", "xxhdpi", "anydpi"});
+ expectHasGroupWithSplits("en-rUS-sw300dp-hdpi", "en-rUS-sw300dp-xhdpi");
+ expectHasGroupWithSplits("en-rUS-sw600dp-hdpi", "en-rUS-sw600dp-xhdpi");
+ expectHasGroupWithSplits("fr-rFR-sw600dp-hdpi", "fr-rFR-sw600dp-xhdpi");
+ expectHasGroupWithSplits("hdpi", "xhdpi", "xxhdpi", "anydpi");
}
TEST_F(GrouperTest, shouldGroupAbi) {
- expectHasGroupWithSplits({":armeabi", ":x86"});
+ expectHasGroupWithSplits(":armeabi", ":x86");
}
TEST_F(GrouperTest, shouldGroupLocale) {
- expectHasGroupWithSplits({"pl-rPL", "de-rDE"});
+ expectHasGroupWithSplits("pl-rPL", "de-rDE");
}
TEST_F(GrouperTest, shouldGroupEachSplitIntoItsOwnGroup) {
- expectHasGroupWithSplits({"large"});
- expectHasGroupWithSplits({"xlarge"});
- expectHasGroupWithSplits({"v7"});
- expectHasGroupWithSplits({"v8"});
- expectHasGroupWithSplits({"sw600dp"});
- expectHasGroupWithSplits({"sw300dp"});
+ expectHasGroupWithSplits("large");
+ expectHasGroupWithSplits("xlarge");
+ expectHasGroupWithSplits("v7");
+ expectHasGroupWithSplits("v8");
+ expectHasGroupWithSplits("sw600dp");
+ expectHasGroupWithSplits("sw300dp");
}
//
// Helper methods
//
-void GrouperTest::expectHasGroupWithSplits(std::initializer_list<const char*> l) {
+void GrouperTest::expectHasGroupWithSplits(const char* a) {
+ Vector<const char*> expected;
+ expected.add(a);
+ expectHasGroupWithSplits(expected);
+}
+
+void GrouperTest::expectHasGroupWithSplits(const char* a, const char* b) {
+ Vector<const char*> expected;
+ expected.add(a);
+ expected.add(b);
+ expectHasGroupWithSplits(expected);
+}
+
+void GrouperTest::expectHasGroupWithSplits(const char* a, const char* b, const char* c) {
+ Vector<const char*> expected;
+ expected.add(a);
+ expected.add(b);
+ expected.add(c);
+ expectHasGroupWithSplits(expected);
+}
+
+void GrouperTest::expectHasGroupWithSplits(const char* a, const char* b, const char* c, const char* d) {
+ Vector<const char*> expected;
+ expected.add(a);
+ expected.add(b);
+ expected.add(c);
+ expected.add(d);
+ expectHasGroupWithSplits(expected);
+}
+
+void GrouperTest::expectHasGroupWithSplits(const Vector<const char*>& expectedStrs) {
Vector<SplitDescription> splits;
- for (const char* str : l) {
+ const size_t expectedStrCount = expectedStrs.size();
+ for (size_t i = 0; i < expectedStrCount; i++) {
splits.add();
- if (!SplitDescription::parse(String8(str), &splits.editTop())) {
- ADD_FAILURE() << "Failed to parse SplitDescription " << str;
+ if (!SplitDescription::parse(String8(expectedStrs[i]), &splits.editTop())) {
+ ADD_FAILURE() << "Failed to parse SplitDescription " << expectedStrs[i];
return;
}
}
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
index d6251c3..434494e 100644
--- a/tools/split-select/Main.cpp
+++ b/tools/split-select/Main.cpp
@@ -63,7 +63,7 @@
class SplitSelector {
public:
- SplitSelector() = default;
+ SplitSelector();
SplitSelector(const Vector<SplitDescription>& splits);
Vector<SplitDescription> getBestSplits(const SplitDescription& target) const;
@@ -75,6 +75,9 @@
Vector<SortedVector<SplitDescription> > mGroups;
};
+SplitSelector::SplitSelector() {
+}
+
SplitSelector::SplitSelector(const Vector<SplitDescription>& splits)
: mGroups(groupByMutualExclusivity(splits)) {
}
diff --git a/tools/split-select/RuleGenerator.cpp b/tools/split-select/RuleGenerator.cpp
index 669ae78..b8f3bcb 100644
--- a/tools/split-select/RuleGenerator.cpp
+++ b/tools/split-select/RuleGenerator.cpp
@@ -65,12 +65,12 @@
sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) {
const abi::Variant thisAbi = splitAbis[index];
- const std::vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi));
+ const Vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi));
- std::vector<abi::Variant>::const_iterator start =
+ Vector<abi::Variant>::const_iterator start =
std::find(familyVariants.begin(), familyVariants.end(), thisAbi);
- std::vector<abi::Variant>::const_iterator end = familyVariants.end();
+ Vector<abi::Variant>::const_iterator end = familyVariants.end();
if (index + 1 < splitAbis.size()) {
end = std::find(start, familyVariants.end(), splitAbis[index + 1]);
}
@@ -127,7 +127,7 @@
rootRule->subrules.add(generateDensity(allDensities, densityIndex));
}
- if (group[index].abi != abi::Variant::none) {
+ if (group[index].abi != abi::Variant_none) {
size_t abiIndex = 0;
Vector<abi::Variant> allVariants;
allVariants.add(group[index].abi);
diff --git a/tools/split-select/RuleGenerator_test.cpp b/tools/split-select/RuleGenerator_test.cpp
index 60baabe..ee387be 100644
--- a/tools/split-select/RuleGenerator_test.cpp
+++ b/tools/split-select/RuleGenerator_test.cpp
@@ -25,19 +25,19 @@
namespace split {
static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan);
-static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant,
- std::initializer_list<const char*> matches);
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a);
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a, const char* b);
TEST(RuleGeneratorTest, testAbiRules) {
Vector<abi::Variant> abis;
- abis.add(abi::Variant::armeabi);
- abis.add(abi::Variant::armeabi_v7a);
- abis.add(abi::Variant::x86);
+ abis.add(abi::Variant_armeabi);
+ abis.add(abi::Variant_armeabi_v7a);
+ abis.add(abi::Variant_x86);
std::sort(abis.begin(), abis.end());
- expectAbiRule(abis, abi::Variant::armeabi, {"armeabi"});
- expectAbiRule(abis, abi::Variant::armeabi_v7a, {"armeabi-v7a", "arm64-v8a"});
- expectAbiRule(abis, abi::Variant::x86, {"x86", "x86_64"});
+ expectAbiRule(abis, abi::Variant_armeabi, "armeabi");
+ expectAbiRule(abis, abi::Variant_armeabi_v7a, "armeabi-v7a", "arm64-v8a");
+ expectAbiRule(abis, abi::Variant_x86, "x86", "x86_64");
}
TEST(RuleGeneratorTest, testDensityRules) {
@@ -126,8 +126,7 @@
}
}
-static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant,
- std::initializer_list<const char*> matches) {
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const Vector<const char*>& matches) {
const abi::Variant* iter = std::find(abis.begin(), abis.end(), variant);
if (abis.end() == iter) {
ADD_FAILURE() << abi::toString(variant) << " was not in the abi list.";
@@ -143,7 +142,9 @@
EXPECT_EQ(matches.size(), rule->stringArgs.size())
<< " for " << abi::toString(variant) << " rule";
- for (const char* match : matches) {
+ const size_t matchCount = matches.size();
+ for (size_t i = 0; i < matchCount; i++) {
+ const char* match = matches[i];
if (rule->stringArgs.end() ==
std::find(rule->stringArgs.begin(), rule->stringArgs.end(), String8(match))) {
ADD_FAILURE() << "Rule for abi " << abi::toString(variant)
@@ -152,4 +153,17 @@
}
}
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a) {
+ Vector<const char*> matches;
+ matches.add(a);
+ expectAbiRule(abis, variant, matches);
+}
+
+static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a, const char* b) {
+ Vector<const char*> matches;
+ matches.add(a);
+ matches.add(b);
+ expectAbiRule(abis, variant, matches);
+}
+
} // namespace split
diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp
index 8037ef0..99bc23d 100644
--- a/tools/split-select/SplitDescription.cpp
+++ b/tools/split-select/SplitDescription.cpp
@@ -27,7 +27,7 @@
namespace split {
SplitDescription::SplitDescription()
-: abi(abi::Variant::none) {
+: abi(abi::Variant_none) {
}
int SplitDescription::compare(const SplitDescription& rhs) const {
@@ -38,11 +38,11 @@
}
bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const {
- if (abi != abi::Variant::none || o.abi != abi::Variant::none) {
+ if (abi != abi::Variant_none || o.abi != abi::Variant_none) {
abi::Family family = abi::getFamily(abi);
abi::Family oFamily = abi::getFamily(o.abi);
if (family != oFamily) {
- return family != abi::Family::none;
+ return family != abi::Family_none;
}
if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) {
@@ -53,7 +53,7 @@
}
bool SplitDescription::match(const SplitDescription& o) const {
- if (abi != abi::Variant::none) {
+ if (abi != abi::Variant_none) {
abi::Family family = abi::getFamily(abi);
abi::Family oFamily = abi::getFamily(o.abi);
if (family != oFamily) {
@@ -69,7 +69,7 @@
String8 SplitDescription::toString() const {
String8 extension;
- if (abi != abi::Variant::none) {
+ if (abi != abi::Variant_none) {
if (extension.isEmpty()) {
extension.append(":");
} else {
@@ -85,40 +85,40 @@
ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index,
SplitDescription* outSplit) {
const ssize_t N = parts.size();
- abi::Variant abi = abi::Variant::none;
+ abi::Variant abi = abi::Variant_none;
ssize_t endIndex = index;
if (parts[endIndex] == "arm64") {
endIndex++;
if (endIndex < N) {
if (parts[endIndex] == "v8a") {
endIndex++;
- abi = abi::Variant::arm64_v8a;
+ abi = abi::Variant_arm64_v8a;
}
}
} else if (parts[endIndex] == "armeabi") {
endIndex++;
- abi = abi::Variant::armeabi;
+ abi = abi::Variant_armeabi;
if (endIndex < N) {
if (parts[endIndex] == "v7a") {
endIndex++;
- abi = abi::Variant::armeabi_v7a;
+ abi = abi::Variant_armeabi_v7a;
}
}
} else if (parts[endIndex] == "x86") {
endIndex++;
- abi = abi::Variant::x86;
+ abi = abi::Variant_x86;
} else if (parts[endIndex] == "x86_64") {
endIndex++;
- abi = abi::Variant::x86_64;
+ abi = abi::Variant_x86_64;
} else if (parts[endIndex] == "mips") {
endIndex++;
- abi = abi::Variant::mips;
+ abi = abi::Variant_mips;
} else if (parts[endIndex] == "mips64") {
endIndex++;
- abi = abi::Variant::mips64;
+ abi = abi::Variant_mips64;
}
- if (abi == abi::Variant::none && endIndex != index) {
+ if (abi == abi::Variant_none && endIndex != index) {
return -1;
}
diff --git a/tools/split-select/SplitDescription.h b/tools/split-select/SplitDescription.h
index 5fcafc8..b13c9ee 100644
--- a/tools/split-select/SplitDescription.h
+++ b/tools/split-select/SplitDescription.h
@@ -27,7 +27,6 @@
struct SplitDescription {
SplitDescription();
- SplitDescription(const SplitDescription&) = default;
ConfigDescription config;
abi::Variant abi;