Merge "Don't print error log if phone account icon is missing" into lmp-mr1-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/content/Context.java b/core/java/android/content/Context.java
index 158a40c..4e2aca0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2883,12 +2883,14 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.service.persistentdata.PersistentDataBlockManager} instance retrieving
- * a file descriptor for a persistent data block.
+ * android.service.persistentdata.PersistentDataBlockManager} instance
+ * for interacting with a storage device that lives across factory resets.
+ *
* @see #getSystemService
* @see android.service.persistentdata.PersistentDataBlockManager
* @hide
*/
+ @SystemApi
public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index b9507d7..5bc7f71 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,36 @@
*
* 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 {
+ // Slow path: #close was called explicitly on this session; unconfigure first
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
+ try {
+ 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
+ } catch (IllegalStateException e) {
+ // Camera is already closed, so go straight to the close callback
+ if (VERBOSE) Log.v(TAG, mIdString +
+ "Camera was already closed or busy, skipping unconfigure");
+ mUnconfigureDrainer.taskFinished();
+ }
+
+ mUnconfigureDrainer.beginDrain();
}
-
- 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 e96c15f7..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..fd95901 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -207,11 +207,18 @@
Log.i(TAG, "Producing jpeg buffer...");
int totalSize = data.length + LegacyCameraDevice.nativeGetJpegFooterSize();
- totalSize += ((totalSize - 1) & ~0x3) + 4; // align to next octonibble
+ totalSize = (totalSize + 3) & ~0x3; // round up to nearest octonibble
+ if (USE_BLOB_FORMAT_OVERRIDE) {
+ // Override to RGBA_8888 format.
+ LegacyCameraDevice.setSurfaceFormat(s,
+ LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888);
+ // divide by 4 if using RGBA format (width is in pixels, not bytes).
+ totalSize >>= 2;
+ }
LegacyCameraDevice.setSurfaceDimens(s, totalSize, /*height*/1);
LegacyCameraDevice.setNextTimestamp(s, timestamp);
- LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1,
+ LegacyCameraDevice.produceFrame(s, data, totalSize, /*height*/1,
CameraMetadataNative.NATIVE_JPEG_FORMAT);
}
} catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
@@ -864,6 +871,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/Binder.java b/core/java/android/os/Binder.java
index 362afba..cb5a31c 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -387,10 +387,26 @@
}
}
- static void checkParcel(Parcel parcel, String msg) {
+ static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
if (parcel.dataSize() >= 800*1024) {
// Trying to send > 800k, this is way too much
- Slog.wtfStack(TAG, msg + parcel.dataSize());
+ StringBuilder sb = new StringBuilder();
+ sb.append(msg);
+ sb.append(": on ");
+ sb.append(obj);
+ sb.append(" calling ");
+ sb.append(code);
+ sb.append(" size ");
+ sb.append(parcel.dataSize());
+ sb.append(" (data: ");
+ parcel.setDataPosition(0);
+ sb.append(parcel.readInt());
+ sb.append(", ");
+ sb.append(parcel.readInt());
+ sb.append(", ");
+ sb.append(parcel.readInt());
+ sb.append(")");
+ Slog.wtfStack(TAG, sb.toString());
}
}
@@ -432,7 +448,7 @@
reply.writeException(re);
res = true;
}
- checkParcel(reply, "Unreasonably large binder reply buffer: ");
+ checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
reply.recycle();
data.recycle();
return res;
@@ -448,7 +464,7 @@
}
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
- Binder.checkParcel(data, "Unreasonably large binder buffer: ");
+ Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
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/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index f64177d..3592687 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -276,13 +276,19 @@
// Do not check this word if the user is currently editing it
final boolean isEditing;
+
+ // Defer spell check when typing a word with an interior apostrophe.
+ // TODO: a better solution to this would be to make the word
+ // iterator locale-sensitive and include the apostrophe in
+ // languages that use it (such as English).
+ final boolean apostrophe = (selectionStart == end + 1 && editable.charAt(end) == '\'');
if (mIsSentenceSpellCheckSupported) {
// Allow the overlap of the cursor and the first boundary of the spell check span
// no to skip the spell check of the following word because the
// following word will never be spell-checked even if the user finishes composing
- isEditing = selectionEnd <= start || selectionStart > end;
+ isEditing = !apostrophe && (selectionEnd <= start || selectionStart > end);
} else {
- isEditing = selectionEnd < start || selectionStart > end;
+ isEditing = !apostrophe && (selectionEnd < start || selectionStart > end);
}
if (start >= 0 && end > start && isEditing) {
spellCheckSpan.setSpellCheckInProgress(true);
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 8b97329..a8980849 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -208,7 +208,13 @@
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
+ if (mThumbDrawable != null) {
+ mThumbDrawable.setCallback(this);
+ }
mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_track);
+ if (mTrackDrawable != null) {
+ mTrackDrawable.setCallback(this);
+ }
mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
mShowText = a.getBoolean(com.android.internal.R.styleable.Switch_showText, true);
@@ -433,7 +439,13 @@
* @attr ref android.R.styleable#Switch_track
*/
public void setTrackDrawable(Drawable track) {
+ if (mTrackDrawable != null) {
+ mTrackDrawable.setCallback(null);
+ }
mTrackDrawable = track;
+ if (track != null) {
+ track.setCallback(this);
+ }
requestLayout();
}
@@ -468,7 +480,13 @@
* @attr ref android.R.styleable#Switch_thumb
*/
public void setThumbDrawable(Drawable thumb) {
+ if (mThumbDrawable != null) {
+ mThumbDrawable.setCallback(null);
+ }
mThumbDrawable = thumb;
+ if (thumb != null) {
+ thumb.setCallback(this);
+ }
requestLayout();
}
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/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index ee00161..b90e493 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -52,15 +52,15 @@
* Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for
* digital RGB with K_b = 0.114, and K_r = 0.299.
*/
-static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, uint8_t* yPlane,
+static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, uint8_t* yPlane,
uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
uint8_t R, G, B;
size_t index = 0;
- int32_t cStrideDiff = chromaStride - width;
+ size_t cStrideDiff = chromaStride - width;
- for (int32_t j = 0; j < height; j++) {
- for (int32_t i = 0; i < width; i++) {
+ for (size_t j = 0; j < height; j++) {
+ for (size_t i = 0; i < width; i++) {
R = rgbBuf[index++];
G = rgbBuf[index++];
B = rgbBuf[index++];
@@ -83,7 +83,7 @@
}
}
-static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, android_ycbcr* ycbcr) {
+static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, android_ycbcr* ycbcr) {
size_t cStep = ycbcr->chroma_step;
size_t cStride = ycbcr->cstride;
size_t yStride = ycbcr->ystride;
@@ -157,15 +157,15 @@
*/
static status_t produceFrame(const sp<ANativeWindow>& anw,
uint8_t* pixelBuffer,
- int32_t width, // Width of the pixelBuffer
- int32_t height, // Height of the pixelBuffer
+ int32_t bufWidth, // Width of the pixelBuffer
+ int32_t bufHeight, // Height of the pixelBuffer
int32_t pixelFmt, // Format of the pixelBuffer
int32_t bufSize) {
ATRACE_CALL();
status_t err = NO_ERROR;
ANativeWindowBuffer* anb;
ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)",
- __FUNCTION__, anw.get(), width, height, pixelFmt, bufSize);
+ __FUNCTION__, anw.get(), bufWidth, bufHeight, pixelFmt, bufSize);
if (anw == 0) {
ALOGE("%s: anw must not be NULL", __FUNCTION__);
@@ -173,10 +173,10 @@
} else if (pixelBuffer == NULL) {
ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__);
return BAD_VALUE;
- } else if (width < 0) {
+ } else if (bufWidth < 0) {
ALOGE("%s: width must be non-negative", __FUNCTION__);
return BAD_VALUE;
- } else if (height < 0) {
+ } else if (bufHeight < 0) {
ALOGE("%s: height must be non-negative", __FUNCTION__);
return BAD_VALUE;
} else if (bufSize < 0) {
@@ -184,24 +184,56 @@
return BAD_VALUE;
}
- if (width < 0 || height < 0 || bufSize < 0) {
- ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__);
- return BAD_VALUE;
- }
+ size_t width = static_cast<size_t>(bufWidth);
+ size_t height = static_cast<size_t>(bufHeight);
+ size_t bufferLength = static_cast<size_t>(bufSize);
// TODO: Switch to using Surface::lock and Surface::unlockAndPost
err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
if (err != NO_ERROR) return err;
- // TODO: check anb is large enough to store the results
-
sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false));
+ uint32_t gBufWidth = buf->getWidth();
+ uint32_t gBufHeight = buf->getHeight();
+ if (gBufWidth != width || gBufHeight != height) {
+ ALOGE("%s: Received gralloc buffer with bad dimensions %" PRIu32 "x%" PRIu32
+ ", expecting dimensions %zu x %zu", __FUNCTION__, gBufWidth, gBufHeight,
+ width, height);
+ return BAD_VALUE;
+ }
+
+ int32_t bufFmt = 0;
+ err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &bufFmt);
+ if (err != NO_ERROR) {
+ ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
+ strerror(-err), err);
+ return err;
+ }
+
+ uint64_t tmpSize = width * height;
+ if (bufFmt != pixelFmt) {
+ if (bufFmt == HAL_PIXEL_FORMAT_RGBA_8888 && pixelFmt == HAL_PIXEL_FORMAT_BLOB) {
+ ALOGV("%s: Using BLOB to RGBA format override.", __FUNCTION__);
+ tmpSize *= 4;
+ } else {
+ ALOGW("%s: Format mismatch in produceFrame: expecting format %#" PRIx32
+ ", but received buffer with format %#" PRIx32, __FUNCTION__, pixelFmt, bufFmt);
+ }
+ }
+
+ if (tmpSize > SIZE_MAX) {
+ ALOGE("%s: Overflow calculating size, buffer with dimens %zu x %zu is absurdly large...",
+ __FUNCTION__, width, height);
+ return BAD_VALUE;
+ }
+
+ size_t totalSizeBytes = tmpSize;
switch(pixelFmt) {
case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
- if (bufSize < width * height * 4) {
- ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
- __FUNCTION__, bufSize);
+ if (bufferLength < totalSizeBytes) {
+ ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
+ __FUNCTION__, bufferLength);
return BAD_VALUE;
}
uint8_t* img = NULL;
@@ -221,14 +253,14 @@
break;
}
case HAL_PIXEL_FORMAT_YV12: {
- if (bufSize < width * height * 4) {
- ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
- __FUNCTION__, bufSize);
+ if (bufferLength < totalSizeBytes) {
+ ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
+ __FUNCTION__, bufferLength);
return BAD_VALUE;
}
if ((width & 1) || (height & 1)) {
- ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height);
+ ALOGE("%s: Dimens %zu x %zu are not divisible by 2.", __FUNCTION__, width, height);
return BAD_VALUE;
}
@@ -258,9 +290,9 @@
case HAL_PIXEL_FORMAT_YCbCr_420_888: {
// Software writes with YCbCr_420_888 format are unsupported
// by the gralloc module for now
- if (bufSize < width * height * 4) {
- ALOGE("%s: PixelBuffer size %" PRId32 " too small for given dimensions",
- __FUNCTION__, bufSize);
+ if (bufferLength < totalSizeBytes) {
+ ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
+ __FUNCTION__, bufferLength);
return BAD_VALUE;
}
android_ycbcr ycbcr = android_ycbcr();
@@ -276,34 +308,35 @@
break;
}
case HAL_PIXEL_FORMAT_BLOB: {
- if (bufSize != width || height != 1) {
- ALOGE("%s: Incorrect pixelBuffer size: %" PRId32, __FUNCTION__, bufSize);
- return BAD_VALUE;
- }
int8_t* img = NULL;
struct camera3_jpeg_blob footer = {
jpeg_blob_id: CAMERA3_JPEG_BLOB_ID,
jpeg_size: (uint32_t)width
};
- size_t totalSize = static_cast<size_t>(width) + sizeof(footer);
- size_t padding = ((totalSize - 1) & ~0x3) + 4; // align to next octonibble
- totalSize += padding;
- if (anb->width != totalSize) {
- ALOGE("%s: gralloc buffer wrong size to hold jpeg, failed to produce buffer.");
+ size_t totalJpegSize = bufferLength + sizeof(footer);
+ totalJpegSize = (totalJpegSize + 3) & ~0x3; // round up to nearest octonibble
+
+ if (height != 1) {
+ ALOGE("%s: Invalid height set for JPEG buffer output, %zu", __FUNCTION__, height);
return BAD_VALUE;
}
- ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
+ if (totalJpegSize > totalSizeBytes) {
+ ALOGE("%s: Pixel buffer needs size %zu, cannot fit in gralloc buffer of size %zu",
+ __FUNCTION__, totalJpegSize, totalSizeBytes);
+ return BAD_VALUE;
+ }
+
err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
if (err != NO_ERROR) {
ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err),
err);
return err;
}
- memcpy(img, pixelBuffer, width);
- memset(img + width, 0, padding);
- memcpy(img + totalSize - sizeof(footer), &footer, sizeof(footer));
+
+ memcpy(img, pixelBuffer, bufferLength);
+ memcpy(img + totalSizeBytes - sizeof(footer), &footer, sizeof(footer));
break;
}
default: {
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-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml
index b89a311..3c03814 100644
--- a/core/res/res/values-mcc204-mnc04/config.xml
+++ b/core/res/res/values-mcc204-mnc04/config.xml
@@ -29,5 +29,6 @@
<!-- [dialstring],[replacement][,optional gid] -->
<string-array translatable="false" name="dial_string_replace">
<item>"*611:+19085594899,BAE0000000000000"</item>
+ <item>"*86:+1MDN,BAE0000000000000"</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index d01d9f8..c2be340 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -47,5 +47,6 @@
<!-- service number convert map in roaming network. -->
<string-array translatable="false" name="dial_string_replace">
<item>"*611:+19085594899,"</item>
+ <item>"*86:+1MDN,"</item>
</string-array>
</resources>
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 d5e4395..3f82de9d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2022,6 +2022,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/docs/html/distribute/googleplay/about.jd b/docs/html/distribute/googleplay/about.jd
index c7c91ac..c25a9cf 100644
--- a/docs/html/distribute/googleplay/about.jd
+++ b/docs/html/distribute/googleplay/about.jd
@@ -25,7 +25,7 @@
<p>
Google Play is the premier store for distributing Android apps. When you
publish on Google Play, you put your apps in front of Android's huge base of
- active customers, in more than 130 countries and territories across the
+ active customers, in more than 190 countries and territories across the
world.
</p>
diff --git a/docs/html/distribute/monetize/ecommerce.jd b/docs/html/distribute/monetize/ecommerce.jd
index 65e2b20..dc56d46 100644
--- a/docs/html/distribute/monetize/ecommerce.jd
+++ b/docs/html/distribute/monetize/ecommerce.jd
@@ -16,7 +16,7 @@
physical goods and services, such as clothing or movie tickets, through your
apps using <a href=
"https://developers.google.com/wallet/instant-buy/">Instant Buy for
- Android</a> in the US.
+ Android</a> <strong>(US Only)</strong>.
</p>
<p>
diff --git a/docs/html/distribute/stories/games.jd b/docs/html/distribute/stories/games.jd
index 1a482b1..2351eed 100644
--- a/docs/html/distribute/stories/games.jd
+++ b/docs/html/distribute/stories/games.jd
@@ -1,246 +1,28 @@
page.title=Developer Stories: Google Play Game Services
-meta.tags="google play, developer story, games, global"
+meta.tags="google play, story, stories, games, global"
page.image=/images/distribute/glu-ew-gpgames.jpg
-page.metaDescription=How gaming studios are using Google Play game services to deliver new gaming experiences for their users.
+page.metaDescription=How game studios are using Google Play game services to deliver new gaming experiences for their users.
@jd:body
-<p>One of the goals of <a href="https://developers.google.com/games/">Google
-Play game services</a> is to allow developers to focus on what they’re good at
-as game developers — creating great gaming experiences for their users, by
-building on top of what Google is good at: mobile and cloud services. Integral
-to that is an easy integration process, one that provides a whole host of
-features with little engineering work required.</p>
+<p>
+ <a href="https://developers.google.com/games/">Google Play game services</a>
+ lets you add great social features to your games quickly, without having to
+ build them yourself. You can add multiplayer, game invites, quests, and a
+ variety of other features — all from within your app. Google provides
+ cross-platform game and player infrastructure for you, as well as insights
+ and analytics to help you understand the activities of users in your games.
+</p>
-<p>The gaming studios below understood the opportunity that Google Play game
-services unlocked, and are starting to see real results following their
-successful integrations. </p>
+<p>
+ The case study presentations below highlight how top game studios are taking
+ advantage of Google Play game services — the features they've added and
+ the results they are seeing. Each deck (PDF) is focused on a single game and
+ how it uses a specific Google Play gemes feature.
+</p>
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Concrete Software — Straightforward, easy to implement</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;"
- src="http://lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
-
-<div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the developer</h5>
- <ul>
- <li><a href="https://play.google.com/store/apps/developer?id=Concrete%20Software%2C%20Inc.">Concrete Software</a>,
- makers of <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">PBA
- Bowling Challenge</a></li>
- <li>Added support for multiplayer, leaderboards and achievements through Google Play game
- services</li>
- </ul>
-
- <h5>Results</h5>
- <ul>
- <li>Session lengths have increased more than 15%</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">
- <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
- </a>
- </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Concrete Software added several
-features from Google Play game services into one of their top titles,
-<a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket">PBA
-Bowling Challenge</a>, including support for multiplayer, leaderboards, and
-achievements.</p>
-
-<p>So far, their users have loved the new additions: average session length
-is up more than 15%. Keith Pichelman, CEO of Concrete Software, explains: </p>
-
-<p>"The Google Play game services were straightforward and easy to implement. We
-had been researching options for multiplayer services, so when Google Play game
-services came out, it was an easy decision for us. Not only were they easy to
-integrate, but the features have worked flawlessly. </p>
-
-<p>"PBA Bowling Challenge now has real-time multiplayer which our users instantly
-were thrilled with; you can see in the reviews how people immediately raved about
-the new game experience. </p>
-
-<p>"We also included achievements, leaderboards, and most recently cloud
-synchronization from the Google Play game services as well. Using the game
-services in PBA Bowling Challenge was a huge success, enough so that we are now
-going back to our other titles, adding the features to them as well."</p>
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/concrete-pbc-gpgames.jpg">
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">Session lengths up:</span>
- After adding support for multiplayer with Google Play game services, Concrete
- Software saw an increase in session lengths of more than 15% for PBA Bowling
- Challenge.</p>
- </div>
-</div>
-</div> <!-- END STORY -->
-
-<div style="margin:3em auto"><!-- START STORY -->
-
-<h3>Glu: It’s a must-have for all titles</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 30px 20px;"
- src="http://lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
-
-<div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the developer</h5>
- <ul>
- <li><a href="https://play.google.com/store/apps/developer?id=Glu+Mobile">Glu
- Mobile</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
- Warriors 2</a></li>
- <li>Has already integrated 5 titles with Google Play game services</li>
- </ul>
-
- <h5>Results</h5>
- <ul>
- <li>In Eternity Warriors 2, 7-day user retention is up 40%</li>
- <li>20% increase in play sessions per day as well</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">
- <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
- </a>
- </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Glu was one of the first developers
-to integrate Google Play game services, with
-<a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">Eternity
-Warriors 2</a>. Based on this first success, Glu has integrated game services
-into several more games, including Samurai vs. Zombies 2, Frontline Commando:
-D-Day, Contract Killer 2, and Zombies Ate My Friends.</p>
-
-<p>Already supported in Eternity Warriors 2, they’ve seen a 40% increase in 7-day
-user retention and a 20% increase in play sessions per day. Sourabh Ahuja, Glu's
-Vice President of Android Development, explains:</p>
-
-<p>“Multiplayer, leaderboards, achievements — these are all things that we
-had to build individually for our titles. The availability of these features in
-Google Play game services helps us make our games stickier, and it’s awesome that
-it comes directly from Google. </p>
-
-<p>"It’s flexible enough that we were able to make it interoperable with our
-in-house systems. We look forward to utilizing game services extensively across
-our portfolio."</p>
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/glu-ew-gpgames.jpg"></a>
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">User retention up:</span>
- Glu saw a 40% increase in 7-day user retention for Eternity Warriors 2 after
- integrating with Google Play game services.</p>
- </div>
-</div>
-</div> <!-- END STORY -->
-
-
-<div style="margin-bottom:2em;"><!-- START STORY -->
-
-<h3>Vector-Unit: An awesome multiplayer experience</h3>
-
-<img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px height:78px;
- width: 78px;
- float: left;
- margin: 12px 20px 9px 20px;" src=
- "http://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
-
-<div style="list-style: none;height:100%;
- float: right;
- border-top: 1px solid #9C0;
- width: 220px;
- margin: 4px 20px;padding: .5em;">
-
- <h5>About the developer</h5>
- <ul>
- <li><a href="https://play.google.com/store/apps/developer?id=Vector+Unit">Vector
- Unit</a>, creators of <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
- GP2</a></li>
- <li>Added multiplayer to Riptide GP2 through Google Play game services </li>
- </ul>
-
- <h5>Results</h5>
- <ul>
- <li>With an easy multiplayer solution, they were able to focus on the
- gameplay</li>
- <li>Early reviews of Riptide GP2 called multiplayer “one of the sweetest
- cherries on top!”</li>
- </ul>
-
- <div style="padding:.5em 0 0 1em;">
- <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">
- <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
- </a>
- </div>
-</div>
-
-<div style="line-height:1.4em;">
-<p style="margin-top:0;margin-bottom:12px;">Vector Unit just launched their
-latest title, <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">Riptide
-GP2</a>, with Google Play game services integration, and it has one of the strongest
-integrations of multiplayer yet. Early reviews call multiplayer “one of the sweetest
-cherries on top!”.</p>
-
-<p>Ralf Knoesel, CTO of Vector Unit, tells more about how they've used Google Play game
-services:</p>
-
-<p>“We wanted to provide a really compelling multiplayer experience for our users, and
-Google Play game services allowed us to do just that. With multiplayer, you can show off
-your skills and your custom-tuned hydro jet in 4-way online battles with friends and
-players around the world. </p>
-
-<p>"By providing an easy way to power this multiplayer experience, we were able to focus
-on making the gameplay come alive — like the stunts, which are more daring and
-slicker than ever (with more of them to master), or the realistic detail of the water
-splashing against the camera lens.”</p>
-
-</div>
-
-<div style="clear:both;margin-top:40px;width:auto;">
-
- <img src="{@docRoot}images/distribute/vector-unit-rt-gpgames.jpg"></a>
-
- <div style="width:600px;margin-top:0px;padding:0 90px;">
- <p class="image-caption"><span style="font-weight:500;">Multiplayer and more:</span>
- Google Play game services helped Vector Unit pack an awesome multiplayer experience
- into Riptide GP 2, so they could focus on building a great gaming experience.</p>
- </div>
-</div>
-</div> <!-- END STORY -->
-
-
-
+<div class="resource-widget resource-flow-layout col-13"
+ data-query="collection:distribute/stories/games"
+ data-sortOrder="-timestamp"
+ data-cardSizes="18x12"
+ data-maxResults="32"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/tools/localization-checklist.jd b/docs/html/distribute/tools/localization-checklist.jd
index 08a8143..e640243 100644
--- a/docs/html/distribute/tools/localization-checklist.jd
+++ b/docs/html/distribute/tools/localization-checklist.jd
@@ -529,21 +529,6 @@
<strong>Purchase professional translations through Google Play</strong>
</h4>
-<div class="sidebox-wrapper">
- <div class="sidebox">
- <h2>
- App Translations Service
- </h2>
-
- <p>
- To make it easy to export your app's strings and import the finished
- translations into your project, try the <a href=
- "{@docRoot}sdk/installing/installing-adt.html#tmgr">ADT Translation
- Manager Plugin</a>.
- </p>
- </div>
-</div>
-
<p>
Google Play App Translation Service can help you quickly find and purchase
translations of your app. In the Developer Console, you can browse a list of
diff --git a/docs/html/distribute/users/build-buzz.jd b/docs/html/distribute/users/build-buzz.jd
index 412589f..bfdc095 100644
--- a/docs/html/distribute/users/build-buzz.jd
+++ b/docs/html/distribute/users/build-buzz.jd
@@ -126,7 +126,7 @@
also easy to make and available in multiple languages.
</p>
-<div class="headerLine">
+<div class="headerLine" style="clear:both">
<h2 id="cross-promote-from-your-other-apps">
Cross-Promote from Your Other Apps
</h2>
@@ -262,7 +262,7 @@
Sign up for an AdMob account</a> to get started.
</p>
-<div class="headerLine">
+<div class="headerLine" style="clear:both">
<h2 id="maximize-your-marketing-spend">
Maximize your Marketing Spend
</h2>
@@ -285,7 +285,7 @@
platforms simultaneously helps you maximize your return on investment.
</p>
-<div class="headerLine">
+<div class="headerLine" style="clear:both">
<h2 id="related-resources">
Related Resources
</h2>
diff --git a/docs/html/distribute/users/your-listing.jd b/docs/html/distribute/users/your-listing.jd
index f869950..5d2f885 100644
--- a/docs/html/distribute/users/your-listing.jd
+++ b/docs/html/distribute/users/your-listing.jd
@@ -87,11 +87,10 @@
<p>
Choosing the right featured image is important, it needs to convey as much
about the features of your apps and what makes them special as possible,
- without being cluttered and confusing. Check out the <a href=
- "http://android-developers.blogspot.com/">Android Developers blog</a> post
- for more <a href=
- "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">
- Featured-Image Guidelines</a>.
+ without being cluttered and confusing. To get started with the featured
+ image specs, read the <a
+ href="https://support.google.com/googleplay/android-developer/answer/1078870">featured
+ image guidelines</a> in the Help Center.
</p>
<div class="headerLine">
diff --git a/docs/html/images/gp-build-buzz-uplift-1.png b/docs/html/images/gp-build-buzz-uplift-1.png
new file mode 100644
index 0000000..4319b5b
--- /dev/null
+++ b/docs/html/images/gp-build-buzz-uplift-1.png
Binary files differ
diff --git a/docs/html/images/gp-build-buzz-uplift-2.png b/docs/html/images/gp-build-buzz-uplift-2.png
new file mode 100644
index 0000000..fd6d1f5
--- /dev/null
+++ b/docs/html/images/gp-build-buzz-uplift-2.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 852db1f..15564e0 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -743,4 +743,19 @@
"https://support.google.com/googleplay/answer/2651410"
]
},
+ "distribute/stories/games": {
+ "title": "",
+ "resources": [
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
+ "http://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
+ ]
+ }
}
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
index 62d18d6..89d9761 100644
--- a/docs/html/jd_extras.js
+++ b/docs/html/jd_extras.js
@@ -1264,5 +1264,135 @@
"keywords": [],
"type": "",
"titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_Deerhunter2014_gpgs.png",
+ "title": "Deer Hunter 2014 by Glu — Sign-in",
+ "summary": "Glu finds that Google Play Game Services helps improve the user experience which leads to increased player happiness. They also find that Play Games Services signed in users tend to play longer and have a higher lifetime value.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/ConcreteSoftware_PBABowling_gpgs.png",
+ "title": "PBA® Bowling Challenge by Concrete Software — Quests",
+ "summary": "Concrete Software finds that Google Play Game Services' quests are a great way to create new content for users that leads to higher engagement.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Dragonplay_DragonplaySlots_gpgs.png",
+ "title": "Dragonplay Slots by Dragonplay — Sign-in",
+ "summary": "Dragonplay finds that players who sign in with Google Play Games services tend to be high quality users who were highly engaged. They also tend to be easier to convert to paying users.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Gameloft_Asphalt8_gpgs.png",
+ "title": "Asphalt 8 by Gameloft — Friends invitations",
+ "summary": "Gameloft finds that Google Play Game Services users are more engaged than the average Android user and more likely to convert to paying players.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Glu_EternityWarriors3_gpgs.png",
+ "title": "Eternity Warriors 3 by Glu — Gifting",
+ "summary": "Glu finds that Google Play Game Services gifting outperforms other implementations (including those with incentives) because of its seamless flow and consistent performance.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/HotheadGames_RivalsatWar_gpgs.jpg",
+ "title": "Rivals at War: Firefight by Hothead Games — Leaderboards",
+ "summary": "Hothead Games is planning to include Google Play Game Services features in all their games going forwards after seeing that players that signed in with Play Games Services tend to show higher retention and a higher average revenue.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/TMSOFT_Compulsive_gpgs.png",
+ "title": "Compulsive by TMSOFT — Cross-platform",
+ "summary": "TMSOFT finds that users who authenticate with Play Games Services on Android and iOS play Compulsive twice as much and purchase in-app products over four times as much.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Noodlecake_SuperStickmanGolf2_gpgs.png",
+ "title": "Super Stickman Golf 2 by Noodlecake Studios — Multiplayer",
+ "summary": "Noodlecake Studios finds that Google Play Game Services’ multiplayer feature helps reduce attrition.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebel_DoctorWhoLegacy_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/TinyRebelGames_DrWhoLegacy_pgps.png",
+ "title": "Dr. Doctor Who: Legacy by Tiny Rebel Games — Achievements",
+ "summary": "After integrating achievements and cloud services from Google Play Game Services, Tiny Rebel Games saw a dramatic increase in daily revenues as a result of an increase in daily installs and an increase in the average revenue per install.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
+ },
+ {
+ "lang": "en",
+ "group": "",
+ "tags": [],
+ "url": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf",
+ "timestamp": null,
+ "image": "http://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.png",
+ "title": "Leo’s Fortune by 1337 & Senri — Saved games",
+ "summary": "1337 + Senri finds that Google Play Game Services is easy to integrate and provides essential game functions like cloud saved games, achievements and leaderboards which have a very large adoption rate amongst players.",
+ "keywords": ["stories"],
+ "type": "Case Study Deck",
+ "titleFriendly": ""
}
]);
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 14aa570..d78138bc 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -91,7 +91,8 @@
if (visible) {
mTransition.start();
} else {
- mTransition.stop();
+ // Ensure we're showing the correct state when visible.
+ jumpToCurrentState();
}
}
@@ -140,7 +141,11 @@
protected boolean onStateChange(int[] stateSet) {
final int keyframeIndex = mState.indexOfKeyframe(stateSet);
if (keyframeIndex == getCurrentIndex()) {
- // No transition needed.
+ // Propagate state change to current keyframe.
+ final Drawable current = getCurrent();
+ if (current != null) {
+ return current.setState(stateSet);
+ }
return false;
}
@@ -492,7 +497,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/AudioService.java b/media/java/android/media/AudioService.java
index 71a05ab..5c2abc53 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -4174,6 +4174,14 @@
AudioSystem.DEVICE_STATE_UNAVAILABLE,
address);
mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ synchronized (mCurAudioRoutes) {
+ // Remove A2DP routes as well
+ if (mCurAudioRoutes.mBluetoothName != null) {
+ mCurAudioRoutes.mBluetoothName = null;
+ sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
+ SENDMSG_NOOP, 0, 0, null, 0);
+ }
+ }
}
// must be called synchronized on mConnectedDevices
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 3e5919f..d260b05 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -143,9 +143,7 @@
boolean bound = false;
try {
- if (mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
- bound = true;
- }
+ bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
} catch (Exception ex) {
Log.e(TAG, "Failed binding to service " + mServiceComponent);
}
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 06e40c5..b37ee6e 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -49,7 +49,7 @@
*/
public class MediaSessionLegacyHelper {
private static final String TAG = "MediaSessionHelper";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final Object sLock = new Object();
private static MediaSessionLegacyHelper sInstance;
@@ -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/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index fce3fd0..1921f47 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -39,6 +39,7 @@
import android.view.WindowManager;
import java.io.File;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
@@ -300,8 +301,27 @@
return false;
}
+ // returns true if the path is in the storage root
+ private boolean inStorageRoot(String path) {
+ try {
+ File f = new File(path);
+ String canonical = f.getCanonicalPath();
+ if (canonical.startsWith(mMediaStoragePath)) {
+ return true;
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ return false;
+ }
+
private int beginSendObject(String path, int format, int parent,
int storageId, long size, long modified) {
+ // if the path is outside of the storage root, do not allow access
+ if (!inStorageRoot(path)) {
+ Log.e(TAG, "attempt to put file outside of storage area: " + path);
+ return -1;
+ }
// if mSubDirectories is not null, do not allow copying files to any other locations
if (!inStorageSubDirectory(path)) return -1;
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a7347745..f4eb459 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -286,13 +286,17 @@
return format;
}
-static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer)
+static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride)
{
ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
uint32_t size = 0;
uint32_t width = buffer->width;
uint8_t* jpegBuffer = buffer->data;
+ if (usingRGBAOverride) {
+ width *= 4;
+ }
+
// First check for JPEG transport header at the end of the buffer
uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
@@ -317,11 +321,15 @@
return size;
}
+static bool usingRGBAToJpegOverride(int32_t bufferFormat, int32_t readerCtxFormat) {
+ return readerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888;
+}
+
static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t readerCtxFormat)
{
// Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
// write limitations for some platforms (b/17379185).
- if (readerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888) {
+ if (usingRGBAToJpegOverride(bufferFormat, readerCtxFormat)) {
return HAL_PIXEL_FORMAT_BLOB;
}
return bufferFormat;
@@ -345,6 +353,7 @@
dataSize = ySize = cSize = cStride = 0;
int32_t fmt = buffer->format;
+ bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, readerFormat);
fmt = applyFormatOverrides(fmt, readerFormat);
switch (fmt) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
@@ -416,7 +425,7 @@
ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height);
pData = buffer->data;
- dataSize = Image_getJpegSize(buffer);
+ dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
break;
case HAL_PIXEL_FORMAT_RAW_SENSOR:
// Single plane 16bpp bayer data.
@@ -912,7 +921,7 @@
if (size > static_cast<uint32_t>(INT32_MAX)) {
// Byte buffer have 'int capacity', so check the range
jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Size too large for bytebuffer capacity " PRIu32, size);
+ "Size too large for bytebuffer capacity %" PRIu32, size);
return NULL;
}
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/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 8e603ba..0d393bf 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -412,7 +412,7 @@
if (mCurrView != null) {
float delta = getPos(ev) - mInitialTouchPos;
float absDelta = Math.abs(delta);
- if (absDelta >= mFalsingThreshold) {
+ if (absDelta >= getFalsingThreshold()) {
mTouchAboveFalsingThreshold = true;
}
// don't let items that can't be dismissed be dragged more than
@@ -466,6 +466,11 @@
return true;
}
+ private int getFalsingThreshold() {
+ float factor = mCallback.getFalsingThresholdFactor();
+ return (int) (mFalsingThreshold * factor);
+ }
+
public interface Callback {
View getChildAtPosition(MotionEvent ev);
@@ -489,6 +494,11 @@
* @return if true, prevents the default alpha fading.
*/
boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress);
+
+ /**
+ * @return The factor the falsing threshold should be multiplied with
+ */
+ float getFalsingThresholdFactor();
}
/**
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/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index bdb0ad3..330333a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -196,6 +196,11 @@
return false;
}
+ @Override
+ public float getFalsingThresholdFactor() {
+ return 1.0f;
+ }
+
public void dismissChild(View v) {
mSwipeHelper.dismissChild(v, 0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 47c096f..1e247be 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -204,6 +204,11 @@
return false;
}
+ @Override
+ public float getFalsingThresholdFactor() {
+ return 1.0f;
+ }
+
public void dismissChild(View v) {
mSwipeHelper.dismissChild(v, 0);
}
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/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index c869ba4..0d5ebe7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -256,6 +256,9 @@
}
private void startActivateAnimation(boolean reverse) {
+ if (!isAttachedToWindow()) {
+ return;
+ }
int widthHalf = mBackgroundNormal.getWidth()/2;
int heightHalf = mBackgroundNormal.getActualHeight()/2;
float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index a9c701a..6653254 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -303,8 +303,12 @@
}
private boolean isBelowFalsingThreshold() {
- return Math.abs(mTranslation) < Math.abs(mTranslationOnDown)
- + mMinTranslationAmount;
+ return Math.abs(mTranslation) < Math.abs(mTranslationOnDown) + getMinTranslationAmount();
+ }
+
+ private int getMinTranslationAmount() {
+ float factor = mCallback.getAffordanceFalsingFactor();
+ return (int) (mMinTranslationAmount * factor);
}
private void fling(float vel, final boolean snapBack) {
@@ -339,14 +343,14 @@
translation = rightSwipePossible() ? translation : Math.max(0, translation);
translation = leftSwipePossible() ? translation : Math.min(0, translation);
float absTranslation = Math.abs(translation);
- if (absTranslation > Math.abs(mTranslationOnDown) + mMinTranslationAmount ||
+ if (absTranslation > Math.abs(mTranslationOnDown) + getMinTranslationAmount() ||
mMotionPerformedByUser) {
mMotionPerformedByUser = true;
}
if (translation != mTranslation || isReset) {
KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
- float alpha = absTranslation / mMinTranslationAmount;
+ float alpha = absTranslation / getMinTranslationAmount();
// We interpolate the alpha of the other icons to 0
float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
@@ -482,5 +486,10 @@
View getLeftPreview();
View getRightPreview();
+
+ /**
+ * @return The factor the minimum swipe amount should be multiplied with.
+ */
+ float getAffordanceFalsingFactor();
}
}
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 80e9663..b9efb22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -706,7 +706,7 @@
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
setQsExpansion(h + mInitialHeightOnTouch);
- if (h >= mQsFalsingThreshold) {
+ if (h >= getFalsingThreshold()) {
mQsTouchAboveFalsingThreshold = true;
}
trackMovement(event);
@@ -732,6 +732,11 @@
}
}
+ private int getFalsingThreshold() {
+ float factor = mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+ return (int) (mQsFalsingThreshold * factor);
+ }
+
@Override
public void onOverscrolled(float lastTouchX, float lastTouchY, int amount) {
if (mIntercepting && shouldQuickSettingsIntercept(lastTouchX, lastTouchY,
@@ -1453,8 +1458,7 @@
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
mAfforanceHelper.animateHideLeftRightIcon();
- }
- if (mQsExpanded) {
+ } else if (mQsExpanded) {
mTwoFingerQsExpand = true;
}
}
@@ -1633,6 +1637,11 @@
}
@Override
+ public float getAffordanceFalsingFactor() {
+ return mStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+ }
+
+ @Override
protected float getPeekHeight() {
if (mNotificationStackScroller.getNotGoneChildCount() > 0) {
return mNotificationStackScroller.getPeekHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index 7f155a1d..84216a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -316,6 +316,11 @@
}
@Override
+ public float getFalsingThresholdFactor() {
+ return 1.0f;
+ }
+
+ @Override
public void onChildDismissed(View v) {
Log.v(TAG, "User swiped heads up to dismiss");
mBar.onHeadsUpDismissed();
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 67ba8d20..4a20406 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -547,6 +547,11 @@
return false;
}
+ @Override
+ public float getFalsingThresholdFactor() {
+ return mPhoneStatusBar.isScreenOnComingFromTouch() ? 1.5f : 1.0f;
+ }
+
public void onBeginDrag(View v) {
setSwipingInProgress(true);
mAmbientState.onBeginDrag(v);
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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 164a4f7..b3337bb 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -154,6 +154,10 @@
private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
+ private long mDefaultSubId = SubscriptionManager.INVALID_SUB_ID;
+
+ private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_ID;
+
private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -195,8 +199,27 @@
}
break;
}
- case MSG_UPDATE_DEFAULT_SUB: {// do nothing
- if (VDBG) log(TAG + "MSG_UPDATE_DEFAULT_SUB");
+ case MSG_UPDATE_DEFAULT_SUB: {
+ int newDefaultPhoneId = msg.arg1;
+ long newDefaultSubId = (Long)(msg.obj);
+ if (VDBG) {
+ log("MSG_UPDATE_DEFAULT_SUB:current mDefaultSubId=" + mDefaultSubId
+ + " current mDefaultPhoneId=" + mDefaultPhoneId + " newDefaultSubId= "
+ + newDefaultSubId + " newDefaultPhoneId=" + newDefaultPhoneId);
+ }
+
+ //Due to possible risk condition,(notify call back using the new
+ //defaultSubId comes before new defaultSubId update) we need to recall all
+ //possible missed notify callback
+ synchronized (mRecords) {
+ for (Record r : mRecords) {
+ if(r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+ checkPossibleMissNotify(r, newDefaultPhoneId);
+ }
+ }
+ }
+ mDefaultSubId = newDefaultSubId;
+ mDefaultPhoneId = newDefaultPhoneId;
}
}
}
@@ -212,10 +235,21 @@
if (DBG) log("onReceive: userHandle=" + userHandle);
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, userHandle, 0));
} else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
+ Long newDefaultSubIdObj = new Long(intent.getLongExtra(
+ PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.getDefaultSubId()));
+ int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
+ SubscriptionManager.getPhoneId(mDefaultSubId));
if (DBG) {
- log(TAG + "onReceive: ACTION_DEFAULT_SUBSCRIPTION_CHANGED");
+ log("onReceive:current mDefaultSubId=" + mDefaultSubId
+ + " current mDefaultPhoneId=" + mDefaultPhoneId + " newDefaultSubId= "
+ + newDefaultSubIdObj + " newDefaultPhoneId=" + newDefaultPhoneId);
}
- mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
+
+ if(validatePhoneId(newDefaultPhoneId) && (newDefaultSubIdObj.equals(mDefaultSubId)
+ || (newDefaultPhoneId != mDefaultPhoneId))) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB,
+ newDefaultPhoneId, 0, newDefaultSubIdObj));
+ }
}
}
};
@@ -560,8 +594,7 @@
+ " phoneId=" + phoneId + " state=" + state);
}
if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)) {
try {
if (DBG) {
log("notifyServiceStateForSubscriber: callback.onSSC r=" + r
@@ -606,8 +639,7 @@
+ " phoneId=" + phoneId + " ss=" + signalStrength);
}
if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)) {
try {
if (DBG) {
log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
@@ -620,8 +652,7 @@
}
}
if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)){
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
@@ -663,8 +694,7 @@
mCellInfo.set(phoneId, cellInfo);
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)) {
try {
if (DBG_LOC) {
log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
@@ -719,8 +749,7 @@
mMessageWaiting[phoneId] = mwi;
for (Record r : mRecords) {
if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)) {
try {
r.callback.onMessageWaitingIndicatorChanged(mwi);
} catch (RemoteException ex) {
@@ -751,8 +780,7 @@
mCallForwarding[phoneId] = cfi;
for (Record r : mRecords) {
if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)) {
try {
r.callback.onCallForwardingIndicatorChanged(cfi);
} catch (RemoteException ex) {
@@ -849,8 +877,7 @@
}
for (Record r : mRecords) {
if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)) {
try {
log("Notify data connection state changed on sub: " +
subId);
@@ -936,8 +963,7 @@
mCellLocation[phoneId] = cellLocation;
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
- ((r.subId == subId) ||
- (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ subIdMatch(r.subId, subId)) {
try {
if (DBG_LOC) {
log("notifyCellLocation: cellLocation=" + cellLocation
@@ -1068,6 +1094,30 @@
}
}
+ public void notifyOemHookRawEventForSubscriber(long subId, byte[] rawData) {
+ if (!checkNotifyPermission("notifyOemHookRawEventForSubscriber")) {
+ return;
+ }
+
+ synchronized (mRecords) {
+ for (Record r : mRecords) {
+ if (VDBG) {
+ log("notifyOemHookRawEventForSubscriber: r=" + r + " subId=" + subId);
+ }
+ if (((r.events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) &&
+ ((r.subId == subId) ||
+ (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) {
+ try {
+ r.callback.onOemHookRawEvent(rawData);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -1277,6 +1327,11 @@
android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
}
+
+ if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+ }
}
private void handleRemoveListLocked() {
@@ -1371,4 +1426,117 @@
log(prompt + ": ----------------");
}
}
+
+ boolean subIdMatch(long rSubId, long subId) {
+ if(rSubId == SubscriptionManager.DEFAULT_SUB_ID) {
+ return (subId == mDefaultSubId);
+ } else {
+ return (rSubId == subId);
+ }
+ }
+
+ private void checkPossibleMissNotify(Record r, int phoneId) {
+ int events = r.events;
+
+ if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
+ try {
+ if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
+ mServiceState[phoneId]);
+ r.callback.onServiceStateChanged(
+ new ServiceState(mServiceState[phoneId]));
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+
+ if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+ try {
+ SignalStrength signalStrength = mSignalStrength[phoneId];
+ if (DBG) {
+ log("checkPossibleMissNotify: onSignalStrengthsChanged SS=" + signalStrength);
+ }
+ r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+
+ if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
+ try {
+ int gsmSignalStrength = mSignalStrength[phoneId]
+ .getGsmSignalStrength();
+ if (DBG) {
+ log("checkPossibleMissNotify: onSignalStrengthChanged SS=" +
+ gsmSignalStrength);
+ }
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
+ try {
+ if (DBG_LOC) {
+ log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
+ + mCellInfo.get(phoneId));
+ }
+ r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+
+ if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
+ try {
+ if (VDBG) {
+ log("checkPossibleMissNotify: onMessageWaitingIndicatorChanged phoneId="
+ + phoneId + " mwi=" + mMessageWaiting[phoneId]);
+ }
+ r.callback.onMessageWaitingIndicatorChanged(
+ mMessageWaiting[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+
+ if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
+ try {
+ if (VDBG) {
+ log("checkPossibleMissNotify: onCallForwardingIndicatorChanged phoneId="
+ + phoneId + " cfi=" + mCallForwarding[phoneId]);
+ }
+ r.callback.onCallForwardingIndicatorChanged(
+ mCallForwarding[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
+ try {
+ if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = "
+ + mCellLocation[phoneId]);
+ r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId]));
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+
+ if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+ try {
+ if (DBG) {
+ log("checkPossibleMissNotify: onDataConnectionStateChanged(mDataConnectionState"
+ + "=" + mDataConnectionState[phoneId]
+ + ", mDataConnectionNetworkType=" + mDataConnectionNetworkType[phoneId]
+ + ")");
+ }
+ r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+ mDataConnectionNetworkType[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+ }
}
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);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a61d621..27184390 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10444,9 +10444,21 @@
IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
try {
- if (dpm != null && (dpm.packageHasActiveAdmins(packageName, userId)
- || dpm.isDeviceOwner(packageName))) {
- return true;
+ if (dpm != null) {
+ if (dpm.isDeviceOwner(packageName)) {
+ return true;
+ }
+ int[] users;
+ if (userId == UserHandle.USER_ALL) {
+ users = sUserManager.getUserIds();
+ } else {
+ users = new int[]{userId};
+ }
+ for (int i = 0; i < users.length; ++i) {
+ if (dpm.packageHasActiveAdmins(packageName, users[i])) {
+ return true;
+ }
+ }
}
} catch (RemoteException e) {
}
@@ -10471,7 +10483,10 @@
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
- if (isPackageDeviceAdmin(packageName, userId)) {
+ final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
+ ? UserHandle.ALL : new UserHandle(userId);
+
+ if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
@@ -10494,9 +10509,7 @@
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
- res = deletePackageLI(packageName,
- (flags & PackageManager.DELETE_ALL_USERS) != 0
- ? UserHandle.ALL : new UserHandle(userId),
+ res = deletePackageLI(packageName, removeForUser,
true, allUsers, perUserInstalled,
flags | REMOVE_CHATTY, info, true);
systemUpdate = info.isRemovedPackageSystemUpdate;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index b1b63df..ec34ce8 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -214,6 +214,14 @@
*/
public static final int LISTEN_VOLTE_STATE = 0x00004000;
+ /**
+ * Listen for OEM hook raw event
+ *
+ * @see #onOemHookRawEvent
+ * @hide
+ */
+ public static final int LISTEN_OEM_HOOK_RAW_EVENT = 0x00008000;
+
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -229,7 +237,7 @@
* own non-null looper use PhoneStateListener(Looper looper) below.
*/
public PhoneStateListener() {
- this(SubscriptionManager.getDefaultSubId(), Looper.myLooper());
+ this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper());
}
/**
@@ -314,6 +322,10 @@
case LISTEN_VOLTE_STATE:
PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
break;
+ case LISTEN_OEM_HOOK_RAW_EVENT:
+ PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
+ break;
+
}
}
};
@@ -482,6 +494,16 @@
}
/**
+ * Callback invoked when OEM hook raw event is received. Requires
+ * the READ_PRIVILEGED_PHONE_STATE permission.
+ * @param rawData is the byte array of the OEM hook raw data.
+ * @hide
+ */
+ public void onOemHookRawEvent(byte[] rawData) {
+ // default implementation empty
+ }
+
+ /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
*/
@@ -553,6 +575,10 @@
public void onVoLteServiceStateChanged(VoLteServiceState lteState) {
Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget();
}
+
+ public void onOemHookRawEvent(byte[] rawData) {
+ Message.obtain(mHandler, LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData).sendToTarget();
+ }
};
private void log(String s) {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 1ee390f..ce89538 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -861,4 +861,23 @@
|| radioTechnology == RIL_RADIO_TECHNOLOGY_EVDO_B
|| radioTechnology == RIL_RADIO_TECHNOLOGY_EHRPD;
}
+
+ /**
+ * Returns a merged ServiceState consisting of the base SS with voice settings from the
+ * voice SS. The voice SS is only used if it is IN_SERVICE (otherwise the base SS is returned).
+ * @hide
+ * */
+ public static ServiceState mergeServiceStates(ServiceState baseSs, ServiceState voiceSs) {
+ if (voiceSs.mVoiceRegState != STATE_IN_SERVICE) {
+ return baseSs;
+ }
+
+ ServiceState newSs = new ServiceState(baseSs);
+
+ // voice overrides
+ newSs.mVoiceRegState = voiceSs.mVoiceRegState;
+ newSs.mIsEmergencyOnly = false; // only get here if voice is IN_SERVICE
+
+ return newSs;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index a95336e..cea62ba 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -43,5 +43,6 @@
void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
void onVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void onOemHookRawEvent(in byte[] rawData);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index ea5fa27..39defcf 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -62,4 +62,5 @@
void notifyCellInfoForSubscriber(in long subId, in List<CellInfo> cellInfo);
void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void notifyOemHookRawEventForSubscriber(in long subId, in byte[] rawData);
}