Merge "More debugging for issue #17656716: Unhandled exception in Window Manager" into lmp-dev
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 005baed..3d14c58 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -635,14 +635,7 @@
if (mIcon != null) {
return mIcon;
}
- if (mIconFilename != null) {
- try {
- return ActivityManagerNative.getDefault().
- getTaskDescriptionIcon(mIconFilename);
- } catch (RemoteException e) {
- }
- }
- return null;
+ return loadTaskDescriptionIcon(mIconFilename);
}
/** @hide */
@@ -650,6 +643,23 @@
return mIconFilename;
}
+ /** @hide */
+ public Bitmap getInMemoryIcon() {
+ return mIcon;
+ }
+
+ /** @hide */
+ public static Bitmap loadTaskDescriptionIcon(String iconFilename) {
+ if (iconFilename != null) {
+ try {
+ return ActivityManagerNative.getDefault().
+ getTaskDescriptionIcon(iconFilename);
+ } catch (RemoteException e) {
+ }
+ }
+ return null;
+ }
+
/**
* @return The color override on the theme's primary color.
*/
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index ab0fc66..d0aa0fd 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -58,6 +58,8 @@
private OnBreadCrumbClickListener mOnBreadCrumbClickListener;
private int mGravity;
+ private int mLayoutResId;
+ private int mTextColor;
private static final int DEFAULT_GRAVITY = Gravity.START | Gravity.CENTER_VERTICAL;
@@ -103,6 +105,12 @@
mGravity = a.getInt(com.android.internal.R.styleable.FragmentBreadCrumbs_gravity,
DEFAULT_GRAVITY);
+ mLayoutResId = a.getResourceId(
+ com.android.internal.R.styleable.FragmentBreadCrumbs_itemLayout,
+ com.android.internal.R.layout.fragment_bread_crumb_item);
+ mTextColor = a.getColor(
+ com.android.internal.R.styleable.FragmentBreadCrumbs_itemColor,
+ 0);
a.recycle();
}
@@ -311,12 +319,11 @@
}
}
if (i >= numViews) {
- final View item = mInflater.inflate(
- com.android.internal.R.layout.fragment_bread_crumb_item,
- this, false);
+ final View item = mInflater.inflate(mLayoutResId, this, false);
final TextView text = (TextView) item.findViewById(com.android.internal.R.id.title);
text.setText(bse.getBreadCrumbTitle());
text.setTag(bse);
+ text.setTextColor(mTextColor);
if (i == 0) {
item.findViewById(com.android.internal.R.id.left_icon).setVisibility(View.GONE);
}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index b9507d7..68926d0 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -633,7 +633,11 @@
@Override
public void onDrained() {
if (VERBOSE) Log.v(TAG, mIdString + "onIdleDrained");
- synchronized (CameraCaptureSessionImpl.this) {
+
+ // Take device lock before session lock so that we can call back into device
+ // without causing a deadlock
+ synchronized (mDeviceImpl.mInterfaceLock) {
+ synchronized (CameraCaptureSessionImpl.this) {
/*
* The device is now IDLE, and has settled. It will not transition to
* ACTIVE or BUSY again by itself.
@@ -642,28 +646,31 @@
*
* This operation is idempotent; a session will not be closed twice.
*/
- if (VERBOSE) Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
- mSkipUnconfigure);
+ if (VERBOSE)
+ Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
+ mSkipUnconfigure);
- // Fast path: A new capture session has replaced this one; don't unconfigure.
- if (mSkipUnconfigure) {
- mStateCallback.onClosed(CameraCaptureSessionImpl.this);
- return;
+ // Fast path: A new capture session has replaced this one; don't unconfigure.
+ if (mSkipUnconfigure) {
+ mStateCallback.onClosed(CameraCaptureSessionImpl.this);
+ return;
+ }
+
+ // Slow path: #close was called explicitly on this session; unconfigure first
+
+ try {
+ mUnconfigureDrainer.taskStarted();
+ mDeviceImpl
+ .configureOutputsChecked(null); // begin transition to unconfigured
+ } catch (CameraAccessException e) {
+ // OK: do not throw checked exceptions.
+ Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
+
+ // TODO: call onError instead of onClosed if this happens
+ }
+
+ mUnconfigureDrainer.beginDrain();
}
-
- // Slow path: #close was called explicitly on this session; unconfigure first
-
- try {
- mUnconfigureDrainer.taskStarted();
- mDeviceImpl.configureOutputsChecked(null); // begin transition to unconfigured
- } catch (CameraAccessException e) {
- // OK: do not throw checked exceptions.
- Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
-
- // TODO: call onError instead of onClosed if this happens
- }
-
- mUnconfigureDrainer.beginDrain();
}
}
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 2578093..ec450bd1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -60,7 +60,7 @@
private ICameraDeviceUser mRemoteDevice;
// Lock to synchronize cross-thread access to device public interface
- private final Object mInterfaceLock = new Object();
+ final Object mInterfaceLock = new Object(); // access from this class and Session only!
private final CameraDeviceCallbacks mCallbacks = new CameraDeviceCallbacks();
private final StateCallback mDeviceCallback;
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index e96c15f..89e2d98 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -73,6 +73,7 @@
void onError(int errorCode, RequestHolder holder);
void onConfiguring();
void onIdle();
+ void onBusy();
void onCaptureStarted(RequestHolder holder, long timestamp);
void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
}
@@ -217,6 +218,20 @@
}
Log.i(TAG, "Legacy camera service transitioning to state " + stateName);
}
+
+ // If we transitioned into a non-IDLE/non-ERROR state then mark the device as busy
+ if(newState != STATE_ERROR && newState != STATE_IDLE) {
+ if (mCurrentState != newState && mCurrentHandler != null &&
+ mCurrentListener != null) {
+ mCurrentHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCurrentListener.onBusy();
+ }
+ });
+ }
+ }
+
switch(newState) {
case STATE_ERROR:
if (mCurrentState != STATE_ERROR && mCurrentHandler != null &&
diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
index c8e0147..64c532b 100644
--- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
@@ -113,6 +113,9 @@
case MSG_ALLOW_FRAMES:
mDroppingFrames = false;
break;
+ case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
+ // OK: Ignore message.
+ break;
default:
Log.e(TAG, "Unhandled message " + msg.what + " on GLThread.");
break;
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 4587c6f..3a976ba 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -21,6 +21,7 @@
import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.impl.CameraDeviceImpl;
import android.hardware.camera2.impl.CaptureResultExtras;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.params.StreamConfiguration;
@@ -95,7 +96,25 @@
new CameraDeviceState.CameraDeviceStateListener() {
@Override
public void onError(final int errorCode, final RequestHolder holder) {
- mIdle.open();
+ if (DEBUG) {
+ Log.d(TAG, "onError called, errorCode = " + errorCode);
+ }
+ switch (errorCode) {
+ /*
+ * Only be considered idle if we hit a fatal error
+ * and no further requests can be processed.
+ */
+ case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED:
+ case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_SERVICE:
+ case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE: {
+ mIdle.open();
+
+ if (DEBUG) {
+ Log.d(TAG, "onError - opening idle");
+ }
+ }
+ }
+
final CaptureResultExtras extras = getExtrasFromRequest(holder);
mResultHandler.post(new Runnable() {
@Override
@@ -124,6 +143,10 @@
@Override
public void onIdle() {
+ if (DEBUG) {
+ Log.d(TAG, "onIdle called");
+ }
+
mIdle.open();
mResultHandler.post(new Runnable() {
@@ -143,6 +166,15 @@
}
@Override
+ public void onBusy() {
+ mIdle.close();
+
+ if (DEBUG) {
+ Log.d(TAG, "onBusy called");
+ }
+ }
+
+ @Override
public void onCaptureStarted(final RequestHolder holder, final long timestamp) {
final CaptureResultExtras extras = getExtrasFromRequest(holder);
diff --git a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
index 36cd907..0699ffb 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
@@ -23,6 +23,15 @@
import android.os.MessageQueue;
public class RequestHandlerThread extends HandlerThread {
+
+ /**
+ * Ensure that the MessageQueue's idle handler gets run by poking the message queue;
+ * normally if the message queue is already idle, the idle handler won't get invoked.
+ *
+ * <p>Users of this handler thread should ignore this message.</p>
+ */
+ public final static int MSG_POKE_IDLE_HANDLER = -1;
+
private final ConditionVariable mStarted = new ConditionVariable(false);
private final ConditionVariable mIdle = new ConditionVariable(true);
private Handler.Callback mCallback;
@@ -86,12 +95,15 @@
// Blocks until thread is idling
public void waitUntilIdle() {
- Looper looper = waitAndGetHandler().getLooper();
+ Handler handler = waitAndGetHandler();
+ Looper looper = handler.getLooper();
if (looper.isIdling()) {
return;
}
mIdle.close();
looper.getQueue().addIdleHandler(mIdleHandler);
+ // Ensure that the idle handler gets run even if the looper already went idle
+ handler.sendEmptyMessage(MSG_POKE_IDLE_HANDLER);
if (looper.isIdling()) {
return;
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index a7ea89c..17ce248 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -864,6 +864,9 @@
}
resetJpegSurfaceFormats(mCallbackOutputs);
break;
+ case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
+ // OK: Ignore message.
+ break;
default:
throw new AssertionError("Unhandled message " + msg.what +
" on RequestThread.");
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 300301b..b492deb 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -702,6 +702,20 @@
}
/**
+ * Disable NFC hardware.
+ * @hide
+ */
+ @SystemApi
+ public boolean disable(boolean persist) {
+ try {
+ return sService.disable(persist);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ return false;
+ }
+ }
+
+ /**
* Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout,
* use {@link #resumePolling()}.
* @hide
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4cdafe1..2785ee8 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -665,4 +665,12 @@
public static final int CRYPT_TYPE_PATTERN = 2;
/** @hide */
public static final int CRYPT_TYPE_PIN = 3;
+
+ // Constants for the data available via MountService.getField.
+ /** @hide */
+ public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
+ /** @hide */
+ public static final String OWNER_INFO_KEY = "OwnerInfo";
+ /** @hide */
+ public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
}
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 23b1e2c..04cd7d5 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -212,6 +212,9 @@
private Button mNextButton;
+ private int mPreferenceHeaderItemResId = 0;
+ private boolean mPreferenceHeaderRemoveEmptyIcon = false;
+
/**
* The starting request code given out to preference framework.
*/
@@ -258,10 +261,15 @@
}
private LayoutInflater mInflater;
+ private int mLayoutResId;
+ private boolean mRemoveIconIfEmpty;
- public HeaderAdapter(Context context, List<Header> objects) {
+ public HeaderAdapter(Context context, List<Header> objects, int layoutResId,
+ boolean removeIconBehavior) {
super(context, 0, objects);
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mLayoutResId = layoutResId;
+ mRemoveIconIfEmpty = removeIconBehavior;
}
@Override
@@ -270,8 +278,7 @@
View view;
if (convertView == null) {
- view = mInflater.inflate(com.android.internal.R.layout.preference_header_item,
- parent, false);
+ view = mInflater.inflate(mLayoutResId, parent, false);
holder = new HeaderViewHolder();
holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
@@ -284,7 +291,16 @@
// All view fields must be updated every time, because the view may be recycled
Header header = getItem(position);
- holder.icon.setImageResource(header.iconRes);
+ if (mRemoveIconIfEmpty) {
+ if (header.iconRes == 0) {
+ holder.icon.setVisibility(View.GONE);
+ } else {
+ holder.icon.setVisibility(View.VISIBLE);
+ holder.icon.setImageResource(header.iconRes);
+ }
+ } else {
+ holder.icon.setImageResource(header.iconRes);
+ }
holder.title.setText(header.getTitle(getContext().getResources()));
CharSequence summary = header.getSummary(getContext().getResources());
if (!TextUtils.isEmpty(summary)) {
@@ -512,7 +528,26 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(com.android.internal.R.layout.preference_list_content);
+ // Theming for the PreferenceActivity layout and for the Preference Header(s) layout
+ TypedArray sa = obtainStyledAttributes(null,
+ com.android.internal.R.styleable.PreferenceActivity,
+ com.android.internal.R.attr.preferenceActivityStyle,
+ 0);
+
+ final int layoutResId = sa.getResourceId(
+ com.android.internal.R.styleable.PreferenceActivity_layout,
+ com.android.internal.R.layout.preference_list_content);
+
+ mPreferenceHeaderItemResId = sa.getResourceId(
+ com.android.internal.R.styleable.PreferenceActivity_headerLayout,
+ com.android.internal.R.layout.preference_header_item);
+ mPreferenceHeaderRemoveEmptyIcon = sa.getBoolean(
+ com.android.internal.R.styleable.PreferenceActivity_headerRemoveIconIfEmpty,
+ false);
+
+ sa.recycle();
+
+ setContentView(layoutResId);
mListFooter = (FrameLayout)findViewById(com.android.internal.R.id.list_footer);
mPrefsContainer = (ViewGroup) findViewById(com.android.internal.R.id.prefs_frame);
@@ -582,7 +617,8 @@
showBreadCrumbs(initialTitleStr, initialShortTitleStr);
}
} else if (mHeaders.size() > 0) {
- setListAdapter(new HeaderAdapter(this, mHeaders));
+ setListAdapter(new HeaderAdapter(this, mHeaders, mPreferenceHeaderItemResId,
+ mPreferenceHeaderRemoveEmptyIcon));
if (!mSinglePane) {
// Multi-pane.
getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b1d3d45..81fc966 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6096,8 +6096,15 @@
if (source != null) {
AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
if (provider != null) {
- AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(
- AccessibilityNodeInfo.getVirtualDescendantId(sourceNodeId));
+ final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
+ sourceNodeId);
+ final AccessibilityNodeInfo node;
+ if (virtualNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ node = provider.createAccessibilityNodeInfo(
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+ } else {
+ node = provider.createAccessibilityNodeInfo(virtualNodeId);
+ }
setAccessibilityFocus(source, node);
}
}
@@ -6135,8 +6142,14 @@
if (provider != null) {
final int virtualChildId = AccessibilityNodeInfo.getVirtualDescendantId(
mAccessibilityFocusedVirtualView.getSourceNodeId());
- mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(
- virtualChildId);
+ if (virtualChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ mAccessibilityFocusedVirtualView = provider
+ .createAccessibilityNodeInfo(
+ AccessibilityNodeProvider.HOST_VIEW_ID);
+ } else {
+ mAccessibilityFocusedVirtualView = provider
+ .createAccessibilityNodeInfo(virtualChildId);
+ }
}
}
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 40965f0..55b3ecc 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -48,14 +48,8 @@
// Returns -1 if nothing could be computed.
long computeChargeTimeRemaining();
- void addIsolatedUid(int isolatedUid, int appUid);
- void removeIsolatedUid(int isolatedUid, int appUid);
-
void noteEvent(int code, String name, int uid);
- void noteProcessStart(String name, int uid);
- void noteProcessState(String name, int uid, int state);
- void noteProcessFinish(String name, int uid);
void noteSyncStart(String name, int uid);
void noteSyncFinish(String name, int uid);
void noteJobStart(String name, int uid);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 85b58aa..16fa88e 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -604,7 +604,7 @@
IMountService mountService = IMountService.Stub.asInterface(service);
try {
Log.d(TAG, "Setting owner info");
- mountService.setField("OwnerInfo", ownerInfo);
+ mountService.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
} catch (RemoteException e) {
Log.e(TAG, "Error changing user info", e);
}
@@ -1144,7 +1144,7 @@
IMountService mountService = IMountService.Stub.asInterface(service);
try {
- mountService.setField("PatternVisible", enabled ? "1" : "0");
+ mountService.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
} catch (RemoteException e) {
Log.e(TAG, "Error changing pattern visible state", e);
}
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 6796134..8ea28ec 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -478,7 +478,7 @@
NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
- int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
struct stat fdStat;
if (fstat(descriptor, &fdStat) == -1) {
@@ -486,22 +486,16 @@
return nullObjectReturn("fstat return -1");
}
- // Duplicate the descriptor here to prevent leaking memory. A leak occurs
- // if we only close the file descriptor and not the file object it is used to
- // create. If we don't explicitly clean up the file (which in turn closes the
- // descriptor) the buffers allocated internally by fseek will be leaked.
- int dupDescriptor = dup(descriptor);
+ // Restore the descriptor's offset on exiting this function.
+ AutoFDSeek autoRestore(descriptor);
- FILE* file = fdopen(dupDescriptor, "r");
+ FILE* file = fdopen(descriptor, "r");
if (file == NULL) {
- // cleanup the duplicated descriptor since it will not be closed when the
- // file is cleaned up (fclose).
- close(dupDescriptor);
return nullObjectReturn("Could not open file");
}
SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
- SkFILEStream::kCallerPasses_Ownership));
+ SkFILEStream::kCallerRetains_Ownership));
// Use a buffered stream. Although an SkFILEStream can be rewound, this
// ensures that SkImageDecoder::Factory never rewinds beyond the
diff --git a/core/res/res/layout-xlarge/breadcrumbs_in_fragment_material.xml b/core/res/res/layout-xlarge/breadcrumbs_in_fragment_material.xml
new file mode 100644
index 0000000..6fb6df5
--- /dev/null
+++ b/core/res/res/layout-xlarge/breadcrumbs_in_fragment_material.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+android:id/breadcrumb_section"
+ android:orientation="vertical"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginStart="@dimen/preference_breadcrumbs_padding_start_material"
+ android:layout_marginEnd="@dimen/preference_breadcrumbs_padding_end_material"
+ >
+ <android.app.FragmentBreadCrumbs
+ android:id="@android:id/title"
+ android:layout_height="72dip"
+ android:layout_width="match_parent"
+ android:paddingTop="16dip"
+ android:paddingBottom="8dip"
+ android:gravity="center_vertical|start"
+ />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/fragment_bread_crumb_item_material.xml b/core/res/res/layout/fragment_bread_crumb_item_material.xml
new file mode 100644
index 0000000..ee4344f
--- /dev/null
+++ b/core/res/res/layout/fragment_bread_crumb_item_material.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ >
+ <ImageView
+ android:id="@android:id/left_icon"
+ android:src="?attr/dividerVertical"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:scaleType="fitXY"
+ android:layout_marginTop="12dip"
+ android:layout_marginBottom="12dip"
+ />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingStart="8dip"
+ android:paddingEnd="8dip"
+ android:gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:background="?android:attr/selectableItemBackground"
+ />
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/preference_header_item_material.xml b/core/res/res/layout/preference_header_item_material.xml
new file mode 100644
index 0000000..594189f
--- /dev/null
+++ b/core/res/res/layout/preference_header_item_material.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.
+-->
+
+<!-- Layout of a header item in PreferenceActivity. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:gravity="center_vertical"
+ android:paddingStart="24dip"
+ android:paddingEnd="?android:attr/scrollbarSize">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="0dip"
+ android:layout_marginEnd="8dip"
+ android:layout_gravity="center" />
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="0dip"
+ android:layout_marginEnd="6dip"
+ android:layout_marginTop="6dip"
+ android:layout_marginBottom="6dip"
+ android:layout_weight="1">
+
+ <TextView android:id="@+android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView android:id="@+android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:ellipsize="end"
+ android:maxLines="2" />
+
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_list_content_material.xml b/core/res/res/layout/preference_list_content_material.xml
new file mode 100644
index 0000000..7856799
--- /dev/null
+++ b/core/res/res/layout/preference_list_content_material.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/layout/list_content.xml
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <LinearLayout
+ style="?attr/preferenceHeaderPanelStyle"
+ android:id="@+id/headers"
+ android:orientation="vertical"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="@integer/preferences_left_pane_weight"
+ android:background="?attr/windowBackground"
+ android:elevation="4dip" >
+
+ <ListView android:id="@android:id/list"
+ style="?attr/preferenceListStyle"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ android:clipToPadding="false"
+ android:drawSelectorOnTop="false"
+ android:cacheColorHint="@color/transparent"
+ android:listPreferredItemHeight="48dp"
+ android:scrollbarAlwaysDrawVerticalTrack="true" />
+
+ <FrameLayout android:id="@+id/list_footer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/prefs_frame"
+ style="?attr/preferencePanelStyle"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="@integer/preferences_right_pane_weight"
+ android:orientation="vertical"
+ android:visibility="gone" >
+
+ <!-- Breadcrumb inserted here, in certain screen sizes. In others, it will be an
+ empty layout or just padding, and PreferenceActivity will put the breadcrumbs in
+ the action bar. -->
+ <include layout="@layout/breadcrumbs_in_fragment_material" />
+
+ <android.preference.PreferenceFrameLayout android:id="@+id/prefs"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+ </LinearLayout>
+
+ <RelativeLayout android:id="@+id/button_bar"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_weight="0"
+ android:visibility="gone">
+
+ <Button android:id="@+id/back_button"
+ android:layout_width="150dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:layout_alignParentStart="true"
+ android:text="@string/back_button_label"
+ />
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true">
+
+ <Button android:id="@+id/skip_button"
+ android:layout_width="150dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:text="@string/skip_button_label"
+ android:visibility="gone"
+ />
+
+ <Button android:id="@+id/next_button"
+ android:layout_width="150dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:text="@string/next_button_label"
+ />
+ </LinearLayout>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 90217e5..8ea1814 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -836,6 +836,8 @@
<!-- Default style for PreferenceScreen. -->
<attr name="preferenceScreenStyle" format="reference" />
+ <!-- Default style for the PreferenceActivity. -->
+ <attr name="preferenceActivityStyle" format="reference" />
<!-- Default style for Headers pane in PreferenceActivity. -->
<attr name="preferenceFragmentStyle" format="reference" />
<!-- Default style for PreferenceCategory. -->
@@ -7265,10 +7267,21 @@
<!-- Base attributes available to PreferenceFragment. -->
<declare-styleable name="PreferenceFragment">
- <!-- The layout for the PreferenceFragment. This should rarely need to be changed -->
+ <!-- The layout for the PreferenceFragment. This should rarely need to be changed. -->
<attr name="layout" />
</declare-styleable>
+ <!-- Base attributes available to PreferenceActivity. -->
+ <declare-styleable name="PreferenceActivity">
+ <!-- The layout for the Preference Activity. This should rarely need to be changed. -->
+ <attr name="layout" />
+ <!-- The layout for the Preference Header. This should rarely need to be changed. -->
+ <attr name="headerLayout" format="reference" />
+ <!-- true if the Icon view will be removed when there is none and thus not showing
+ the fixed margins. -->
+ <attr name="headerRemoveIconIfEmpty" format="boolean" />
+ </declare-styleable>
+
<!-- Use <code>tts-engine</code> as the root tag of the XML resource that
describes a text to speech engine implemented as a subclass of
{@link android.speech.tts.TextToSpeechService}.
@@ -7370,6 +7383,8 @@
tags. -->
<declare-styleable name="FragmentBreadCrumbs">
<attr name="gravity" />
+ <attr name="itemLayout" format="reference" />
+ <attr name="itemColor" format="color|reference" />
</declare-styleable>
<declare-styleable name="MultiPaneChallengeLayout">
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 9836757..450658e 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -14,9 +14,22 @@
limitations under the License.
-->
<resources>
+ <!-- Preference activity, vertical padding for the header list -->
+ <dimen name="preference_screen_header_vertical_padding_material">8dp</dimen>
+
+ <!-- Preference activity side margins -->
+ <dimen name="preference_screen_side_margin_material">0dp</dimen>
+ <!-- Preference activity side margins negative-->
+ <dimen name="preference_screen_side_margin_negative_material">0dp</dimen>
<!-- Preference fragment padding, sides -->
- <dimen name="preference_fragment_padding_side_material">0dp</dimen>
+ <dimen name="preference_fragment_padding_side_material">8dp</dimen>
+
+ <!-- Preference breadcrumbs padding, start padding -->
+ <dimen name="preference_breadcrumbs_padding_start_material">12dp</dimen>
+
+ <!-- Preference breadcrumbs padding, end padding -->
+ <dimen name="preference_breadcrumbs_padding_end_material">24dp</dimen>
<dimen name="preference_screen_header_padding_side_material">0dp</dimen>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index c6d0b0b..ba15e9c 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -533,6 +533,8 @@
<style name="Widget.FragmentBreadCrumbs">
<item name="padding">4dp</item>
<item name="animateLayoutChanges">true</item>
+ <item name="itemLayout">@layout/fragment_bread_crumb_item</item>
+ <item name="itemColor">@null</item>
</style>
<style name="Widget.ImageWell">
@@ -954,6 +956,12 @@
<item name="paddingEnd">0dp</item>
</style>
+ <style name="PreferenceActivity">
+ <item name="layout">@layout/preference_list_content</item>
+ <item name="headerLayout">@layout/preference_header_item</item>
+ <item name="headerRemoveIconIfEmpty">false</item>
+ </style>
+
<style name="Preference.Information">
<item name="layout">@layout/preference_information</item>
<item name="enabled">false</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index e6e5cbb..f9fca00 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -42,6 +42,12 @@
<item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
</style>
+ <style name="PreferenceActivity.Material">
+ <item name="layout">@layout/preference_list_content_material</item>
+ <item name="headerLayout">@layout/preference_header_item_material</item>
+ <item name="headerRemoveIconIfEmpty">true</item>
+ </style>
+
<style name="Preference.Material.Information">
<item name="layout">@layout/preference_information_material</item>
<item name="enabled">false</item>
@@ -93,6 +99,8 @@
<!-- No margins or background by default. Could be different for x-large screens -->
<style name="PreferencePanel.Material">
+ <item name="layout_marginStart">0dip</item>
+ <item name="layout_marginEnd">0dip</item>
</style>
<!-- The attributes are overridden here because the x-large or large resources may have
@@ -106,10 +114,10 @@
</style>
<style name="PreferenceHeaderPanel.Material">
- <item name="layout_marginStart">@dimen/preference_screen_side_margin</item>
- <item name="layout_marginEnd">@dimen/preference_screen_side_margin_negative</item>
- <item name="paddingTop">@dimen/preference_screen_header_vertical_padding</item>
- <item name="paddingBottom">@dimen/preference_screen_header_vertical_padding</item>
+ <item name="layout_marginStart">@dimen/preference_screen_side_margin_material</item>
+ <item name="layout_marginEnd">@dimen/preference_screen_side_margin_negative_material</item>
+ <item name="paddingTop">@dimen/preference_screen_header_vertical_padding_material</item>
+ <item name="paddingBottom">@dimen/preference_screen_header_vertical_padding_material</item>
</style>
<style name="PreferenceHeaderList.Material">
@@ -585,6 +593,12 @@
</style>
<style name="Widget.Material.ExpandableListView.White"/>
+
+ <style name="Widget.Material.FragmentBreadCrumbs" parent="Widget.FragmentBreadCrumbs">
+ <item name="itemLayout">@layout/fragment_bread_crumb_item_material</item>
+ <item name="itemColor">@color/primary_text_default_material_light</item>
+ </style>
+
<style name="Widget.Material.Gallery" parent="Widget.Gallery"/>
<style name="Widget.Material.GestureOverlayView" parent="Widget.GestureOverlayView"/>
@@ -972,6 +986,9 @@
<style name="Widget.Material.Light.EditText" parent="Widget.Material.EditText"/>
<style name="Widget.Material.Light.ExpandableListView" parent="Widget.Material.ExpandableListView"/>
<style name="Widget.Material.Light.ExpandableListView.White" parent="Widget.Material.ExpandableListView.White"/>
+ <style name="Widget.Material.Light.FragmentBreadCrumbs" parent="Widget.Material.FragmentBreadCrumbs" >
+ <item name="itemColor">@color/primary_text_default_material_dark</item>
+ </style>
<style name="Widget.Material.Light.Gallery" parent="Widget.Material.Gallery"/>
<style name="Widget.Material.Light.GestureOverlayView" parent="Widget.Material.GestureOverlayView"/>
<style name="Widget.Material.Light.GridView" parent="Widget.Material.GridView"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 72f756a..f2b7d7b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2021,6 +2021,7 @@
<java-symbol type="style" name="TextAppearance.Material.TimePicker.TimeLabel" />
<java-symbol type="attr" name="seekBarPreferenceStyle" />
<java-symbol type="style" name="Theme.DeviceDefault.Resolver" />
+ <java-symbol type="attr" name="preferenceActivityStyle" />
<java-symbol type="attr" name="preferenceFragmentStyle" />
<java-symbol type="bool" name="skipHoldBeforeMerge" />
<java-symbol type="bool" name="imsServiceAllowTurnOff" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3a268a3..7a9e1d5 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -317,6 +317,7 @@
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.PreferenceScreen</item>
+ <item name="preferenceActivityStyle">@style/PreferenceActivity</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment</item>
<item name="preferenceCategoryStyle">@style/Preference.Category</item>
<item name="preferenceStyle">@style/Preference</item>
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index 208db97..9c1d0f3 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -308,6 +308,7 @@
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item>
+ <item name="preferenceActivityStyle">@style/PreferenceActivity</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Holo</item>
<item name="preferenceCategoryStyle">@style/Preference.Holo.Category</item>
<item name="preferenceStyle">@style/Preference.Holo</item>
@@ -643,6 +644,7 @@
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item>
+ <item name="preferenceActivityStyle">@style/PreferenceActivity</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Holo</item>
<item name="preferenceCategoryStyle">@style/Preference.Holo.Category</item>
<item name="preferenceStyle">@style/Preference.Holo</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 3c2e302..6420153 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -275,9 +275,11 @@
<item name="popupMenuStyle">@style/Widget.Material.PopupMenu</item>
<item name="stackViewStyle">@style/Widget.Material.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Material.ActivityChooserView</item>
+ <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
+ <item name="preferenceActivityStyle">@style/PreferenceActivity.Material</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
<item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
<item name="preferenceStyle">@style/Preference.Material</item>
@@ -622,9 +624,11 @@
<item name="popupMenuStyle">@style/Widget.Material.Light.PopupMenu</item>
<item name="stackViewStyle">@style/Widget.Material.Light.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Material.Light.ActivityChooserView</item>
+ <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
+ <item name="preferenceActivityStyle">@style/PreferenceActivity.Material</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Material</item>
<item name="preferenceCategoryStyle">@style/Preference.Material.Category</item>
<item name="preferenceStyle">@style/Preference.Material</item>
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 14aa570..f7584d8 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -492,7 +492,7 @@
@Override
public Drawable mutate() {
- if (!mMutated) {
+ if (!mMutated && super.mutate() == this) {
final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null);
setConstantState(newState);
mMutated = true;
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index df1b126..ad0b415 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -151,7 +151,7 @@
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
- mAnimatedVectorState = new AnimatedVectorDrawableState(mAnimatedVectorState);
+ mAnimatedVectorState.mVectorDrawable.mutate();
mMutated = true;
}
return this;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 4fd98b7..c7aa98e 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -114,7 +114,8 @@
/** Current dirty bounds, union of current and previous drawing bounds. */
private final Rect mDirtyBounds = new Rect();
- private final RippleState mState;
+ /** Mirrors mLayerState with some extra information. */
+ private RippleState mState;
/** The masking layer, e.g. the layer with id R.id.mask. */
private Drawable mMask;
@@ -885,18 +886,34 @@
return mState;
}
+ @Override
+ public Drawable mutate() {
+ super.mutate();
+
+ // LayerDrawable creates a new state using createConstantState, so
+ // this should always be a safe cast.
+ mState = (RippleState) mLayerState;
+ return this;
+ }
+
+ @Override
+ RippleState createConstantState(LayerState state, Resources res) {
+ return new RippleState(state, this, res);
+ }
+
static class RippleState extends LayerState {
int[] mTouchThemeAttrs;
ColorStateList mColor = ColorStateList.valueOf(Color.MAGENTA);
int mMaxRadius = RADIUS_AUTO;
- public RippleState(RippleState orig, RippleDrawable owner, Resources res) {
+ public RippleState(LayerState orig, RippleDrawable owner, Resources res) {
super(orig, owner, res);
- if (orig != null) {
- mTouchThemeAttrs = orig.mTouchThemeAttrs;
- mColor = orig.mColor;
- mMaxRadius = orig.mMaxRadius;
+ if (orig != null && orig instanceof RippleState) {
+ final RippleState origs = (RippleState) orig;
+ mTouchThemeAttrs = origs.mTouchThemeAttrs;
+ mColor = origs.mColor;
+ mMaxRadius = origs.mMaxRadius;
}
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index bbb0b50..8014837 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -507,9 +507,10 @@
pathRenderer.getAlpha());
pathRenderer.setAlpha(alphaInFloat);
- pathRenderer.mRootName = a.getString(R.styleable.VectorDrawable_name);
- if (pathRenderer.mRootName != null) {
- pathRenderer.mVGTargetsMap.put(pathRenderer.mRootName, pathRenderer);
+ final String name = a.getString(R.styleable.VectorDrawable_name);
+ if (name != null) {
+ pathRenderer.mRootName = name;
+ pathRenderer.mVGTargetsMap.put(name, pathRenderer);
}
}
@@ -1313,9 +1314,15 @@
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
- mPathName = a.getString(R.styleable.VectorDrawableClipPath_name);
- mNodes = PathParser.createNodesFromPathData(a.getString(
- R.styleable.VectorDrawableClipPath_pathData));
+ final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
+ if (pathName != null) {
+ mPathName = pathName;
+ }
+
+ final String pathData = a.getString(R.styleable.VectorDrawableClipPath_pathData);
+ if (pathData != null) {
+ mNodes = PathParser.createNodesFromPathData(pathData);
+ }
}
@Override
@@ -1415,9 +1422,15 @@
// Extract the theme attributes, if any.
mThemeAttrs = a.extractThemeAttrs();
- mPathName = a.getString(R.styleable.VectorDrawablePath_name);
- mNodes = PathParser.createNodesFromPathData(a.getString(
- R.styleable.VectorDrawablePath_pathData));
+ final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
+ if (pathName != null) {
+ mPathName = pathName;
+ }
+
+ final String pathData = a.getString(R.styleable.VectorDrawablePath_pathData);
+ if (pathData != null) {
+ mNodes = PathParser.createNodesFromPathData(pathData);
+ }
mFillColor = a.getColor(R.styleable.VectorDrawablePath_fillColor,
mFillColor);
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 95c2d61..bb59e5b 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -38,4 +38,7 @@
// This is for the system volume UI only
void setRemoteVolumeController(in IRemoteVolumeController rvc);
+
+ // For PhoneWindowManager to precheck media keys
+ boolean isGlobalPriorityActive();
}
\ No newline at end of file
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index 5ce7f9f..b37ee6e 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -232,6 +232,10 @@
}
}
+ public boolean isGlobalPriorityActive() {
+ return mSessionManager.isGlobalPriorityActive();
+ }
+
public void addRccListener(PendingIntent pi, MediaSession.Callback listener) {
if (pi == null) {
Log.w(TAG, "Pending intent was null, can't add rcc listener.");
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 185c6d8..b4fff8f 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -296,6 +296,21 @@
}
/**
+ * Check if the global priority session is currently active. This can be
+ * used to decide if media keys should be sent to the session or to the app.
+ *
+ * @hide
+ */
+ public boolean isGlobalPriorityActive() {
+ try {
+ return mService.isGlobalPriorityActive();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to check if the global priority is active.", e);
+ }
+ return false;
+ }
+
+ /**
* Listens for changes to the list of active sessions. This can be added
* using {@link #addOnActiveSessionsChangedListener}.
*/
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 48450dd..1a44c8c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -908,4 +908,7 @@
<!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
<string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
+
+ <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
+ <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 6cc890b..3afdc3d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -18,10 +18,12 @@
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.UiModeManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Configuration;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
@@ -61,12 +63,14 @@
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
private AlarmManager mAlarmManager;
+ private UiModeManager mUiModeManager;
private boolean mDreaming;
private boolean mPulsing;
private boolean mBroadcastReceiverRegistered;
private boolean mDisplayStateSupported;
private boolean mNotificationLightOn;
private boolean mPowerSaveActive;
+ private boolean mCarMode;
private long mNotificationPulseTime;
private int mScheduleResetsRemaining;
@@ -88,6 +92,7 @@
pw.print(" mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
pw.print(" mNotificationLightOn: "); pw.println(mNotificationLightOn);
pw.print(" mPowerSaveActive: "); pw.println(mPowerSaveActive);
+ pw.print(" mCarMode: "); pw.println(mCarMode);
pw.print(" mNotificationPulseTime: "); pw.println(mNotificationPulseTime);
pw.print(" mScheduleResetsRemaining: "); pw.println(mScheduleResetsRemaining);
mDozeParameters.dump(pw);
@@ -116,6 +121,7 @@
mWakeLock.setReferenceCounted(true);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mDisplayStateSupported = mDozeParameters.getDisplayStateSupported();
+ mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
turnDisplayOff();
}
@@ -135,12 +141,17 @@
}
mPowerSaveActive = mHost.isPowerSaveActive();
+ mCarMode = mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR;
if (DEBUG) Log.d(mTag, "onDreamingStarted canDoze=" + canDoze() + " mPowerSaveActive="
- + mPowerSaveActive);
+ + mPowerSaveActive + " mCarMode=" + mCarMode);
if (mPowerSaveActive) {
finishToSavePower();
return;
}
+ if (mCarMode) {
+ finishForCarMode();
+ return;
+ }
mDreaming = true;
listenForPulseSignals(true);
@@ -221,6 +232,11 @@
finish();
}
+ private void finishForCarMode() {
+ Log.w(mTag, "Exiting ambient mode, not allowed in car mode");
+ finish();
+ }
+
private void listenForPulseSignals(boolean listen) {
if (DEBUG) Log.d(mTag, "listenForPulseSignals: " + listen);
mSigMotionSensor.setListening(listen);
@@ -233,6 +249,7 @@
if (listen) {
final IntentFilter filter = new IntentFilter(PULSE_ACTION);
filter.addAction(NOTIFICATION_PULSE_ACTION);
+ filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
mContext.registerReceiver(mBroadcastReceiver, filter);
mBroadcastReceiverRegistered = true;
} else {
@@ -341,6 +358,12 @@
requestPulse();
rescheduleNotificationPulse(mNotificationLightOn);
}
+ if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
+ mCarMode = true;
+ if (mCarMode && mDreaming) {
+ finishForCarMode();
+ }
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index d4b403d..9d4fe66 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -177,16 +177,24 @@
if (t != null) {
Drawable cachedIcon = mApplicationIconCache.get(t.key);
Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
+
// Load the application icon if it is stale or we haven't cached one yet
if (cachedIcon == null) {
- ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
- t.key.userId);
- if (info != null) {
- cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+ cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
+ mContext.getResources());
+
+ if (cachedIcon == null) {
+ ActivityInfo info = ssp.getActivityInfo(t.key.baseIntent.getComponent(),
+ t.key.userId);
+ if (info != null) {
+ cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+ }
}
+
if (cachedIcon == null) {
cachedIcon = mDefaultApplicationIcon;
}
+
// At this point, even if we can't load the icon, we will set the default
// icon.
mApplicationIconCache.put(t.key, cachedIcon);
@@ -230,6 +238,17 @@
}
}
}
+
+ Drawable getTaskDescriptionIcon(Task.TaskKey taskKey, Bitmap iconBitmap, String iconFilename,
+ SystemServicesProxy ssp, Resources res) {
+ Bitmap tdIcon = iconBitmap != null
+ ? iconBitmap
+ : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename);
+ if (tdIcon != null) {
+ return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
+ }
+ return null;
+ }
}
/* Recents task loader
@@ -321,15 +340,20 @@
if (icon != null) {
return icon;
}
- // Return the task description icon if it exists
- if (td != null && td.getIcon() != null) {
- icon = ssp.getBadgedIcon(new BitmapDrawable(res, td.getIcon()), taskKey.userId);
- mApplicationIconCache.put(taskKey, icon);
- return icon;
- }
- // If we are preloading this task, continue to load the activity icon
+
+ // If we are preloading this task, continue to load the task description icon or the
+ // activity icon
if (preloadTask) {
- // All short paths failed, load the icon from the activity info and cache it
+
+ // Return and cache the task description icon if it exists
+ Drawable tdDrawable = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
+ td.getIconFilename(), ssp, res);
+ if (tdDrawable != null) {
+ mApplicationIconCache.put(taskKey, tdDrawable);
+ return tdDrawable;
+ }
+
+ // Load the icon from the activity info and cache it
if (infoHandle.info == null) {
infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
taskKey.userId);
@@ -453,10 +477,17 @@
activityInfoCache.put(cnKey, infoHandle);
}
+ Bitmap icon = t.taskDescription != null
+ ? t.taskDescription.getInMemoryIcon()
+ : null;
+ String iconFilename = t.taskDescription != null
+ ? t.taskDescription.getIconFilename()
+ : null;
+
// Add the task to the stack
Task task = new Task(taskKey, (t.id > -1), t.affiliatedTaskId, t.affiliatedTaskColor,
activityLabel, activityIcon, activityColor, (i == (taskCount - 1)),
- config.lockToAppEnabled);
+ config.lockToAppEnabled, icon, iconFilename);
if (preloadTask && loadTaskThumbnails) {
// Load the thumbnail from the cache if possible
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 406e03f..a7e2b0b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -124,7 +124,8 @@
public boolean isActive;
public boolean lockToThisTask;
public boolean lockToTaskEnabled;
-
+ public Bitmap icon;
+ public String iconFilename;
TaskCallbacks mCb;
public Task() {
@@ -133,7 +134,8 @@
public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor,
String activityTitle, Drawable activityIcon, int colorPrimary,
- boolean lockToThisTask, boolean lockToTaskEnabled) {
+ boolean lockToThisTask, boolean lockToTaskEnabled, Bitmap icon,
+ String iconFilename) {
boolean isInAffiliationGroup = (taskAffiliation != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
this.key = key;
@@ -147,6 +149,8 @@
this.isActive = isActive;
this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
this.lockToTaskEnabled = lockToTaskEnabled;
+ this.icon = icon;
+ this.iconFilename = iconFilename;
}
/** Copies the other task. */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Interaction.java b/packages/SystemUI/src/com/android/systemui/volume/Interaction.java
new file mode 100644
index 0000000..46eab36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/Interaction.java
@@ -0,0 +1,46 @@
+/*
+ * 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.systemui.volume;
+
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnGenericMotionListener;
+import android.view.View.OnTouchListener;
+
+public class Interaction {
+
+ public static void register(View v, final Callback callback) {
+ v.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ callback.onInteraction();
+ return false;
+ }
+ });
+ v.setOnGenericMotionListener(new OnGenericMotionListener() {
+ @Override
+ public boolean onGenericMotion(View v, MotionEvent event) {
+ callback.onInteraction();
+ return false;
+ }
+ });
+ }
+
+ public interface Callback {
+ void onInteraction();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index 66e1e15..f7f5047 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -80,6 +80,12 @@
addView(b);
b.setTag(value);
b.setOnClickListener(mClick);
+ Interaction.register(b, new Interaction.Callback() {
+ @Override
+ public void onInteraction() {
+ fireInteraction();
+ }
+ });
}
public void updateLocale() {
@@ -96,6 +102,12 @@
}
}
+ private void fireInteraction() {
+ if (mCallback != null) {
+ mCallback.onInteraction();
+ }
+ }
+
private final View.OnClickListener mClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -103,7 +115,7 @@
}
};
- public interface Callback {
+ public interface Callback extends Interaction.Callback {
void onSelected(Object value);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index fa43f32..40bdea2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -42,6 +42,7 @@
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.net.Uri;
+import android.os.Debug;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
@@ -400,11 +401,10 @@
| LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| LayoutParams.FLAG_HARDWARE_ACCELERATED);
mView = window.findViewById(R.id.content);
- mView.setOnTouchListener(new View.OnTouchListener() {
+ Interaction.register(mView, new Interaction.Callback() {
@Override
- public boolean onTouch(View v, MotionEvent event) {
+ public void onInteraction() {
resetTimeout();
- return false;
}
});
@@ -1382,9 +1382,10 @@
}
private void resetTimeout() {
+ final boolean touchExploration = mAccessibilityManager.isTouchExplorationEnabled();
if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis()
- + " delay=" + mTimeoutDelay);
- if (sSafetyWarning == null || !mAccessibilityManager.isTouchExplorationEnabled()) {
+ + " delay=" + mTimeoutDelay + " touchExploration=" + touchExploration);
+ if (sSafetyWarning == null || !touchExploration) {
removeMessages(MSG_TIMEOUT);
sendEmptyMessageDelayed(MSG_TIMEOUT, mTimeoutDelay);
removeMessages(MSG_USER_ACTIVITY);
@@ -1393,6 +1394,7 @@
}
private void forceTimeout(long delay) {
+ if (LOGD) Log.d(mTag, "forceTimeout delay=" + delay + " callers=" + Debug.getCallers(3));
removeMessages(MSG_TIMEOUT);
sendEmptyMessageDelayed(MSG_TIMEOUT, delay);
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index c1681c7..ea431ae 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -135,20 +135,21 @@
@Override
public void onClick(View v) {
setExpanded(true);
- fireInteraction();
}
});
+ Interaction.register(mZenSubheadCollapsed, mInteractionCallback);
mZenSubheadExpanded = (TextView) findViewById(R.id.zen_subhead_expanded);
+ Interaction.register(mZenSubheadExpanded, mInteractionCallback);
mMoreSettings = findViewById(R.id.zen_more_settings);
mMoreSettings.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fireMoreSettings();
- fireInteraction();
}
});
+ Interaction.register(mMoreSettings, mInteractionCallback);
mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
}
@@ -444,18 +445,22 @@
childTag.rb.setChecked(false);
}
select(tag.condition);
- fireInteraction();
+ announceConditionSelection(tag);
}
}
});
- final TextView title = (TextView) row.findViewById(android.R.id.title);
- if (condition == null) {
- title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever));
- } else {
- title.setText(condition.summary);
+
+ if (tag.title == null) {
+ tag.title = (TextView) row.findViewById(android.R.id.title);
}
- title.setEnabled(enabled);
- title.setAlpha(enabled ? 1 : .4f);
+ if (condition == null) {
+ tag.title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever));
+ } else {
+ tag.title.setText(condition.summary);
+ }
+ tag.title.setEnabled(enabled);
+ tag.title.setAlpha(enabled ? 1 : .4f);
+
final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
@@ -471,11 +476,10 @@
onClickTimeButton(row, tag, true /*up*/);
}
});
- title.setOnClickListener(new OnClickListener() {
+ tag.title.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tag.rb.setChecked(true);
- fireInteraction();
}
});
@@ -497,6 +501,30 @@
button1.setVisibility(View.GONE);
button2.setVisibility(View.GONE);
}
+ // wire up interaction callbacks for newly-added condition rows
+ if (convertView == null) {
+ Interaction.register(tag.rb, mInteractionCallback);
+ Interaction.register(tag.title, mInteractionCallback);
+ Interaction.register(button1, mInteractionCallback);
+ Interaction.register(button2, mInteractionCallback);
+ }
+ }
+
+ private void announceConditionSelection(ConditionTag tag) {
+ final int zen = getSelectedZen(Global.ZEN_MODE_OFF);
+ String modeText;
+ switch(zen) {
+ case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ modeText = mContext.getString(R.string.zen_important_interruptions);
+ break;
+ case Global.ZEN_MODE_NO_INTERRUPTIONS:
+ modeText = mContext.getString(R.string.zen_no_interruptions);
+ break;
+ default:
+ return;
+ }
+ announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText,
+ tag.title.getText()));
}
private void onClickTimeButton(View row, ConditionTag tag, boolean up) {
@@ -530,7 +558,7 @@
bind(mTimeCondition, row);
tag.rb.setChecked(true);
select(mTimeCondition);
- fireInteraction();
+ announceConditionSelection(tag);
}
private void select(Condition condition) {
@@ -611,6 +639,7 @@
// used as the view tag on condition rows
private static class ConditionTag {
RadioButton rb;
+ TextView title;
Condition condition;
}
@@ -691,5 +720,17 @@
mController.setZen((Integer) value);
}
}
+
+ @Override
+ public void onInteraction() {
+ fireInteraction();
+ }
+ };
+
+ private final Interaction.Callback mInteractionCallback = new Interaction.Callback() {
+ @Override
+ public void onInteraction() {
+ fireInteraction();
+ }
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java b/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java
index 96e2a8e..d887712 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenToast.java
@@ -31,6 +31,7 @@
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
@@ -110,6 +111,17 @@
message.setText(text);
final ImageView icon = (ImageView) mZenToast.findViewById(android.R.id.icon);
icon.setImageResource(iconRes);
+ mZenToast.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ // noop
+ }
+
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ mZenToast.announceForAccessibility(message.getText());
+ }
+ });
mWindowManager.addView(mZenToast, params);
final int animDuration = res.getInteger(R.integer.zen_toast_animation_duration);
final int visibleDuration = res.getInteger(R.integer.zen_toast_visible_duration);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 006f5db..f7ed364 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4093,6 +4093,7 @@
} else {
intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
}
+ mPowerManager.wakeUp(whenNanos / 1000000);
mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
}
mCameraLensCoverState = lensCoverState;
@@ -4247,8 +4248,8 @@
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey();
if (interactive || (isInjected && !isWakeKey)) {
- // When the device is interactive or the key is injected pass the key to the
- // application.
+ // When the device is interactive or the key is injected pass the
+ // key to the application.
result = ACTION_PASS_TO_USER;
isWakeKey = false;
} else if (!interactive && shouldDispatchInputWhenNonInteractive()) {
@@ -4448,16 +4449,6 @@
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- if (down) {
- TelecomManager telecomManager = getTelecommService();
- if (telecomManager != null) {
- if (telecomManager.isInCall()) {
- // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
- // to avoid music playback.
- break;
- }
- }
- }
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_MEDIA_STOP:
@@ -4467,6 +4458,11 @@
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+ if (MediaSessionLegacyHelper.getHelper(mContext).isGlobalPriorityActive()) {
+ // If the global session is active pass all media keys to it
+ // instead of the active window.
+ result &= ~ACTION_PASS_TO_USER;
+ }
if ((result & ACTION_PASS_TO_USER) == 0) {
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
@@ -5268,6 +5264,7 @@
@Override
public void systemBooted() {
if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.bindService(mContext);
mKeyguardDelegate.onBootCompleted();
}
synchronized (mLock) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index e9ca5c9..50fe7c7 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -102,9 +102,12 @@
};
public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
+ mScrim = createScrim(context);
+ }
+
+ public void bindService(Context context) {
Intent intent = new Intent();
intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
- mScrim = createScrim(context);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
@@ -250,7 +253,6 @@
if (mKeyguardService != null) {
mKeyguardService.onSystemReady();
} else {
- if (DEBUG) Log.v(TAG, "onSystemReady() called before keyguard service was ready");
mKeyguardState.systemIsReady = true;
}
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index ea24d7c..7f24d07 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
+import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -28,6 +29,7 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.ObbInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -94,6 +96,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;
@@ -821,6 +824,10 @@
*/
mConnectedSignal.countDown();
+ // On an encrypted device we can't see system properties yet, so pull
+ // the system locale out of the mount service.
+ copyLocaleFromMountService();
+
// Let package manager load internal ASECs.
mPms.scanAvailableAsecs();
@@ -830,6 +837,28 @@
}.start();
}
+ private void copyLocaleFromMountService() {
+ String systemLocale;
+ try {
+ systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
+ } catch (RemoteException e) {
+ return;
+ }
+ if (TextUtils.isEmpty(systemLocale)) {
+ return;
+ }
+
+ Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
+ Locale locale = Locale.forLanguageTag(systemLocale);
+ Configuration config = new Configuration();
+ config.setLocale(locale);
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(config);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error setting system locale from mount service", e);
+ }
+ }
+
/**
* Callback from NativeDaemonConnector
*/
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4d2fd4c..d0463b7 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -48,6 +48,8 @@
import android.graphics.Rect;
import android.os.BatteryStats;
import android.os.PersistableBundle;
+import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1192,6 +1194,7 @@
static final int ENTER_ANIMATION_COMPLETE_MSG = 44;
static final int ENABLE_SCREEN_AFTER_BOOT_MSG = 45;
static final int START_USER_SWITCH_MSG = 46;
+ static final int SEND_LOCALE_TO_MOUNT_DAEMON_MSG = 47;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1878,6 +1881,18 @@
enableScreenAfterBoot();
break;
}
+ case SEND_LOCALE_TO_MOUNT_DAEMON_MSG: {
+ try {
+ Locale l = (Locale) msg.obj;
+ IBinder service = ServiceManager.getService("mount");
+ IMountService mountService = IMountService.Stub.asInterface(service);
+ Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
+ mountService.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error storing locale for decryption UI", e);
+ }
+ break;
+ }
}
}
};
@@ -6316,7 +6331,12 @@
mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
// Tell anyone interested that we are done booting!
SystemProperties.set("sys.boot_completed", "1");
- SystemProperties.set("dev.bootcomplete", "1");
+
+ // And trigger dev.bootcomplete if we are not showing encryption progress
+ if (!"trigger_restart_min_framework".equals(SystemProperties.get("vold.decrypt"))
+ || "".equals(SystemProperties.get("vold.encrypt_progress"))) {
+ SystemProperties.set("dev.bootcomplete", "1");
+ }
for (int i=0; i<mStartedUsers.size(); i++) {
UserStartedState uss = mStartedUsers.valueAt(i);
if (uss.mState == UserStartedState.STATE_BOOTING) {
@@ -9542,7 +9562,13 @@
public void removeContentProviderExternal(String name, IBinder token) {
enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
"Do not have permission in call removeContentProviderExternal()");
- removeContentProviderExternalUnchecked(name, token, UserHandle.getCallingUserId());
+ int userId = UserHandle.getCallingUserId();
+ long ident = Binder.clearCallingIdentity();
+ try {
+ removeContentProviderExternalUnchecked(name, token, userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
private void removeContentProviderExternalUnchecked(String name, IBinder token, int userId) {
@@ -16247,6 +16273,8 @@
SystemProperties.set("persist.sys.language", l.getLanguage());
SystemProperties.set("persist.sys.country", l.getCountry());
SystemProperties.set("persist.sys.localevar", l.getVariant());
+
+ mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG, l));
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 786196f..a021919 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -123,6 +123,40 @@
return mStats;
}
+ // These are for direct use by the activity manager...
+
+ void addIsolatedUid(int isolatedUid, int appUid) {
+ synchronized (mStats) {
+ mStats.addIsolatedUidLocked(isolatedUid, appUid);
+ }
+ }
+
+ void removeIsolatedUid(int isolatedUid, int appUid) {
+ synchronized (mStats) {
+ mStats.removeIsolatedUidLocked(isolatedUid, appUid);
+ }
+ }
+
+ void noteProcessStart(String name, int uid) {
+ synchronized (mStats) {
+ mStats.noteProcessStartLocked(name, uid);
+ }
+ }
+
+ void noteProcessState(String name, int uid, int state) {
+ synchronized (mStats) {
+ mStats.noteProcessStateLocked(name, uid, state);
+ }
+ }
+
+ void noteProcessFinish(String name, int uid) {
+ synchronized (mStats) {
+ mStats.noteProcessFinishLocked(name, uid);
+ }
+ }
+
+ // Public interface...
+
public byte[] getStatistics() {
mContext.enforceCallingPermission(
android.Manifest.permission.BATTERY_STATS, null);
@@ -166,20 +200,6 @@
}
}
- public void addIsolatedUid(int isolatedUid, int appUid) {
- enforceCallingPermission();
- synchronized (mStats) {
- mStats.addIsolatedUidLocked(isolatedUid, appUid);
- }
- }
-
- public void removeIsolatedUid(int isolatedUid, int appUid) {
- enforceCallingPermission();
- synchronized (mStats) {
- mStats.removeIsolatedUidLocked(isolatedUid, appUid);
- }
- }
-
public void noteEvent(int code, String name, int uid) {
enforceCallingPermission();
synchronized (mStats) {
@@ -187,27 +207,6 @@
}
}
- public void noteProcessStart(String name, int uid) {
- enforceCallingPermission();
- synchronized (mStats) {
- mStats.noteProcessStartLocked(name, uid);
- }
- }
-
- public void noteProcessState(String name, int uid, int state) {
- enforceCallingPermission();
- synchronized (mStats) {
- mStats.noteProcessStateLocked(name, uid, state);
- }
- }
-
- public void noteProcessFinish(String name, int uid) {
- enforceCallingPermission();
- synchronized (mStats) {
- mStats.noteProcessFinishLocked(name, uid);
- }
- }
-
public void noteSyncStart(String name, int uid) {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index aaa29fc..02c9fcb5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -743,6 +743,11 @@
}
@Override
+ public boolean isGlobalPriorityActive() {
+ return mPriorityStack.isGlobalPriorityActive();
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index e464be7..c48a075 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -217,6 +217,10 @@
return null;
}
+ public boolean isGlobalPriorityActive() {
+ return mGlobalPrioritySession == null ? false : mGlobalPrioritySession.isActive();
+ }
+
public void dump(PrintWriter pw, String prefix) {
ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0,
UserHandle.USER_ALL);