Merge "Fix user switcher ripple emanation point" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index d3b8724..80c4dc8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7160,6 +7160,7 @@
public static final class ScanSettings.Builder {
ctor public ScanSettings.Builder();
method public android.bluetooth.le.ScanSettings build();
+ method public android.bluetooth.le.ScanSettings.Builder setCallbackType(int);
method public android.bluetooth.le.ScanSettings.Builder setMatchMode(int);
method public android.bluetooth.le.ScanSettings.Builder setNumOfMatches(int);
method public android.bluetooth.le.ScanSettings.Builder setReportDelay(long);
@@ -30323,6 +30324,7 @@
method public android.net.Uri getSubscriptionAddress();
method public java.util.List<java.lang.String> getSupportedUriSchemes();
method public boolean hasCapabilities(int);
+ method public boolean isEnabled();
method public boolean supportsUriScheme(java.lang.String);
method public android.telecom.PhoneAccount.Builder toBuilder();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1dc5325..6c4f278 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -32509,6 +32509,7 @@
method public android.net.Uri getSubscriptionAddress();
method public java.util.List<java.lang.String> getSupportedUriSchemes();
method public boolean hasCapabilities(int);
+ method public boolean isEnabled();
method public boolean supportsUriScheme(java.lang.String);
method public android.telecom.PhoneAccount.Builder toBuilder();
method public void writeToParcel(android.os.Parcel, int);
@@ -32650,6 +32651,7 @@
method public void cancelMissedCallsNotification();
method public deprecated void clearAccounts();
method public void clearPhoneAccounts();
+ method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
method public boolean endCall();
method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
@@ -32665,7 +32667,6 @@
method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(java.lang.String);
- method public java.util.List<android.telecom.PhoneAccountHandle> getRegisteredConnectionManagers();
method public android.telecom.PhoneAccountHandle getSimCallManager();
method public java.lang.String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
method public boolean handleMmi(java.lang.String);
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 4eeb577..d616624 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -249,9 +249,7 @@
*
* @param callbackType The callback type flags for the scan.
* @throws IllegalArgumentException If the {@code callbackType} is invalid.
- * @hide
*/
- @SystemApi
public Builder setCallbackType(int callbackType) {
if (!isValidCallbackType(callbackType)) {
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 9046e81..7f4a76c 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -67,8 +67,6 @@
private final TaskSingleDrainer mIdleDrainer;
/** Drain state transitions from BUSY -> IDLE */
private final TaskSingleDrainer mAbortDrainer;
- /** Drain the UNCONFIGURED state transition */
- private final TaskSingleDrainer mUnconfigureDrainer;
/** This session is closed; all further calls will throw ISE */
private boolean mClosed = false;
@@ -121,8 +119,6 @@
/*name*/"idle");
mAbortDrainer = new TaskSingleDrainer(mDeviceHandler, new AbortDrainListener(),
/*name*/"abort");
- mUnconfigureDrainer = new TaskSingleDrainer(mDeviceHandler, new UnconfigureDrainListener(),
- /*name*/"unconf");
// CameraDevice should call configureOutputs and have it finish before constructing us
@@ -572,26 +568,6 @@
@Override
public void onUnconfigured(CameraDevice camera) {
if (VERBOSE) Log.v(TAG, mIdString + "onUnconfigured");
- synchronized (session) {
- // Ignore #onUnconfigured before #close is called.
- //
- // Normally, this is reached when this session is closed and no immediate other
- // activity happens for the camera, in which case the camera is configured to
- // null streams by this session and the UnconfigureDrainer task is started.
- // However, we can also end up here if
- //
- // 1) Session is closed
- // 2) New session is created before this session finishes closing, setting
- // mSkipUnconfigure and therefore this session does not configure null or
- // start the UnconfigureDrainer task.
- // 3) And then the new session fails to be created, so onUnconfigured fires
- // _anyway_.
- // In this second case, need to not finish a task that was never started, so
- // guard with mSkipUnconfigure
- if (mClosed && mConfigureSuccess && !mSkipUnconfigure) {
- mUnconfigureDrainer.taskFinished();
- }
- }
}
@Override
@@ -656,6 +632,19 @@
* then the drain immediately finishes.
*/
if (VERBOSE) Log.v(TAG, mIdString + "onSequenceDrained");
+
+
+ // Fire session close as soon as all sequences are complete.
+ // We may still need to unconfigure the device, but a new session might be created
+ // past this point, and notifications would then stop to this instance.
+ mStateCallback.onClosed(CameraCaptureSessionImpl.this);
+
+ // Fast path: A new capture session has replaced this one; don't wait for abort/idle
+ // as we won't get state updates any more anyway.
+ if (mSkipUnconfigure) {
+ return;
+ }
+
mAbortDrainer.beginDrain();
}
}
@@ -673,6 +662,12 @@
*
* If the camera is already "IDLE", then the drain immediately finishes.
*/
+
+ // Fast path: A new capture session has replaced this one; don't wait for idle
+ // as we won't get state updates any more anyway.
+ if (mSkipUnconfigure) {
+ return;
+ }
mIdleDrainer.beginDrain();
}
}
@@ -691,7 +686,7 @@
* The device is now IDLE, and has settled. It will not transition to
* ACTIVE or BUSY again by itself.
*
- * It's now safe to unconfigure the outputs and after it's done invoke #onClosed.
+ * It's now safe to unconfigure the outputs.
*
* This operation is idempotent; a session will not be closed twice.
*/
@@ -699,45 +694,31 @@
Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " +
mSkipUnconfigure);
- // Fast path: A new capture session has replaced this one; don't unconfigure.
+ // Fast path: A new capture session has replaced this one; don't wait for idle
+ // as we won't get state updates any more anyway.
if (mSkipUnconfigure) {
- mStateCallback.onClosed(CameraCaptureSessionImpl.this);
return;
}
- // Slow path: #close was called explicitly on this session; unconfigure first
- mUnconfigureDrainer.taskStarted();
-
+ // Final slow path: unconfigure the camera, no session has replaced us and
+ // everything is idle.
try {
// begin transition to unconfigured
mDeviceImpl.configureStreamsChecked(null, null);
} catch (CameraAccessException e) {
// OK: do not throw checked exceptions.
- Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
+ Log.e(TAG, mIdString + "Exception while unconfiguring 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
+ // Camera is already closed, so nothing left to do
if (VERBOSE) Log.v(TAG, mIdString +
"Camera was already closed or busy, skipping unconfigure");
- mUnconfigureDrainer.taskFinished();
}
- mUnconfigureDrainer.beginDrain();
}
}
}
}
- private class UnconfigureDrainListener implements TaskDrainer.DrainListener {
- @Override
-
- public void onDrained() {
- if (VERBOSE) Log.v(TAG, mIdString + "onUnconfigureDrained");
- synchronized (CameraCaptureSessionImpl.this) {
- // The device has finished unconfiguring. It's now fully closed.
- mStateCallback.onClosed(CameraCaptureSessionImpl.this);
- }
- }
- }
}
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 9623695..04e54aa 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -50,6 +50,8 @@
public final int flags;
public long size;
public String label;
+ /** Hacky; don't rely on this count */
+ public int volumeCount;
public DiskInfo(String id, int flags) {
this.id = Preconditions.checkNotNull(id);
@@ -61,6 +63,7 @@
flags = parcel.readInt();
size = parcel.readLong();
label = parcel.readString();
+ volumeCount = parcel.readInt();
}
public @NonNull String getId() {
@@ -181,5 +184,6 @@
parcel.writeInt(this.flags);
parcel.writeLong(size);
parcel.writeString(label);
+ parcel.writeInt(volumeCount);
}
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index bd45007..f18b7ac 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -80,12 +80,18 @@
/**
* The interpolator of the underlying Animator object. By default, we don't set the interpolator
- * on the Animator and just use its default interpolator. If the interpolator is set to a
- * non-null value on this Animator, then we use the interpolator that it was set to.
+ * on the Animator and just use its default interpolator. If the interpolator is ever set on
+ * this Animator, then we use the interpolator that it was set to.
*/
private TimeInterpolator mInterpolator;
/**
+ * A flag indicating whether the interpolator has been set on this object. If not, we don't set
+ * the interpolator on the underlying Animator, but instead just use its default interpolator.
+ */
+ private boolean mInterpolatorSet = false;
+
+ /**
* Listener for the lifecycle events of the underlying ValueAnimator object.
*/
private Animator.AnimatorListener mListener = null;
@@ -332,6 +338,7 @@
* @return This object, allowing calls to methods in this class to be chained.
*/
public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
+ mInterpolatorSet = true;
mInterpolator = interpolator;
return this;
}
@@ -342,7 +349,7 @@
* @return The timing interpolator for this animation.
*/
public TimeInterpolator getInterpolator() {
- if (mInterpolator != null) {
+ if (mInterpolatorSet) {
return mInterpolator;
} else {
// Just return the default from ValueAnimator, since that's what we'd get if
@@ -890,7 +897,7 @@
if (mDurationSet) {
animator.setDuration(mDuration);
}
- if (mInterpolator != null) {
+ if (mInterpolatorSet) {
animator.setInterpolator(mInterpolator);
}
animator.start();
diff --git a/docs/html/preview/images/bugs.png b/docs/html/preview/images/bugs.png
deleted file mode 100644
index 46adf05..0000000
--- a/docs/html/preview/images/bugs.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/preview/images/dev-prev.png b/docs/html/preview/images/dev-prev.png
deleted file mode 100644
index eae6ede..0000000
--- a/docs/html/preview/images/dev-prev.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/preview/images/m-preview-timeline.png b/docs/html/preview/images/m-preview-timeline.png
index a065c21..bda0b46 100644
--- a/docs/html/preview/images/m-preview-timeline.png
+++ b/docs/html/preview/images/m-preview-timeline.png
Binary files differ
diff --git a/docs/html/preview/images/updates.png b/docs/html/preview/images/updates.png
deleted file mode 100644
index f165c5a..0000000
--- a/docs/html/preview/images/updates.png
+++ /dev/null
Binary files differ
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 4526839..0f1be6b 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -724,6 +725,26 @@
return USAGE_UNKNOWN;
}
}
+ /**
+ * @hide
+ * CANDIDATE FOR PUBLIC (or at least SYSTEM) API
+ * Returns the stream type matching the given attributes for volume control.
+ * Use this method to derive the stream type needed to configure the volume
+ * control slider in an {@link Activity} with {@link Activity#setVolumeControlStream(int)}.
+ * <BR>Do not use this method to set the stream type on an audio player object
+ * (e.g. {@link AudioTrack}, {@link MediaPlayer}), use <code>AudioAttributes</code> instead.
+ * @param aa non-null AudioAttributes.
+ * @return a valid stream type for <code>Activity</code> or stream volume control that matches
+ * the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
+ * match. Note that <code>USE_DEFAULT_STREAM_TYPE</code> is not a valid value
+ * for {@link AudioManager#setStreamVolume(int, int, int)}.
+ */
+ public static int getVolumeControlStream(@NonNull AudioAttributes aa) {
+ if (aa == null) {
+ throw new IllegalArgumentException("Invalid null audio attributes");
+ }
+ return toVolumeStreamType(true /*fromGetVolumeControlStream*/, aa);
+ }
/**
* @hide
@@ -732,13 +753,19 @@
* @param aa non-null AudioAttributes.
* @return a valid stream type for volume control that matches the attributes.
*/
- public static int toLegacyStreamType(AudioAttributes aa) {
+ public static int toLegacyStreamType(@NonNull AudioAttributes aa) {
+ return toVolumeStreamType(false /*fromGetVolumeControlStream*/, aa);
+ }
+
+ private static int toVolumeStreamType(boolean fromGetVolumeControlStream, AudioAttributes aa) {
// flags to stream type mapping
if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
- return AudioSystem.STREAM_SYSTEM_ENFORCED;
+ return fromGetVolumeControlStream ?
+ AudioSystem.STREAM_SYSTEM : AudioSystem.STREAM_SYSTEM_ENFORCED;
}
if ((aa.getFlags() & FLAG_SCO) == FLAG_SCO) {
- return AudioSystem.STREAM_BLUETOOTH_SCO;
+ return fromGetVolumeControlStream ?
+ AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_BLUETOOTH_SCO;
}
// usage to stream type mapping
@@ -753,7 +780,8 @@
case USAGE_VOICE_COMMUNICATION:
return AudioSystem.STREAM_VOICE_CALL;
case USAGE_VOICE_COMMUNICATION_SIGNALLING:
- return AudioSystem.STREAM_DTMF;
+ return fromGetVolumeControlStream ?
+ AudioSystem.STREAM_VOICE_CALL : AudioSystem.STREAM_DTMF;
case USAGE_ALARM:
return AudioSystem.STREAM_ALARM;
case USAGE_NOTIFICATION_RINGTONE:
@@ -765,8 +793,15 @@
case USAGE_NOTIFICATION_EVENT:
return AudioSystem.STREAM_NOTIFICATION;
case USAGE_UNKNOWN:
+ return fromGetVolumeControlStream ?
+ AudioManager.USE_DEFAULT_STREAM_TYPE : AudioSystem.STREAM_MUSIC;
default:
- return AudioSystem.STREAM_MUSIC;
+ if (fromGetVolumeControlStream) {
+ throw new IllegalArgumentException("Unknown usage value " + aa.getUsage() +
+ " in audio attributes");
+ } else {
+ return AudioSystem.STREAM_MUSIC;
+ }
}
}
diff --git a/packages/DocumentsUI/res/layout/fragment_pick.xml b/packages/DocumentsUI/res/layout/fragment_pick.xml
index 87dc4f8..40d4eb5 100644
--- a/packages/DocumentsUI/res/layout/fragment_pick.xml
+++ b/packages/DocumentsUI/res/layout/fragment_pick.xml
@@ -19,13 +19,13 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:baselineAligned="false"
- android:gravity="center_vertical"
+ android:gravity="end"
+ android:paddingEnd="8dp"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
<Button
android:id="@android:id/button2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"
android:text="@android:string/cancel"
android:visibility="gone"
style="?android:attr/buttonBarNegativeButtonStyle" />
@@ -33,7 +33,5 @@
android:id="@android:id/button1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"
- android:textAllCaps="false"
style="?android:attr/buttonBarPositiveButtonStyle" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 5281087..9794273 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -44,8 +44,6 @@
<string name="menu_share">Share</string>
<!-- Menu item title that deletes the selected documents [CHAR LIMIT=24] -->
<string name="menu_delete">Delete</string>
- <!-- Menu item title that selects the current directory [CHAR LIMIT=48] -->
- <string name="menu_select">Select \"<xliff:g id="directory" example="My Directory">^1</xliff:g>\"</string>
<!-- Menu item title that selects all documents in the current directory [CHAR LIMIT=24] -->
<string name="menu_select_all">Select All</string>
<!-- Menu item title that copies the selected documents [CHAR LIMIT=24] -->
@@ -65,7 +63,9 @@
<!-- Menu item that hides the sizes of displayed files [CHAR LIMIT=24] -->
<string name="menu_file_size_hide">Hide file size</string>
- <!-- Button label that copies files to the current directory [CHAR LIMIT=48] -->
+ <!-- Button label that select the current directory [CHAR LIMIT=24] -->
+ <string name="button_select">Select</string>
+ <!-- Button label that copies files to the current directory [CHAR LIMIT=24] -->
<string name="button_copy">Copy</string>
<!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index cded717..8482438 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -571,9 +571,7 @@
mState.action == ACTION_OPEN_COPY_DESTINATION) {
final PickFragment pick = PickFragment.get(fm);
if (pick != null) {
- final CharSequence displayName = (mState.stack.size() <= 1) ? root.title
- : cwd.displayName;
- pick.setPickTarget(mState.action, cwd, displayName);
+ pick.setPickTarget(mState.action, cwd);
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index e899379..d9b8568 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -38,15 +38,19 @@
public class PickFragment extends Fragment {
public static final String TAG = "PickFragment";
+ private int mAction;
private DocumentInfo mPickTarget;
-
private View mContainer;
private Button mPick;
private Button mCancel;
public static void show(FragmentManager fm) {
- final PickFragment fragment = new PickFragment();
+ // Fragment can be restored by FragmentManager automatically.
+ if (get(fm) != null) {
+ return;
+ }
+ final PickFragment fragment = new PickFragment();
final FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container_save, fragment, TAG);
ft.commitAllowingStateLoss();
@@ -67,8 +71,7 @@
mCancel = (Button) mContainer.findViewById(android.R.id.button2);
mCancel.setOnClickListener(mCancelListener);
- setPickTarget(0, null, null);
-
+ updateView();
return mContainer;
}
@@ -92,32 +95,38 @@
/**
* @param action Which action defined in BaseActivity.State is the picker shown for.
*/
- public void setPickTarget(int action,
- DocumentInfo pickTarget,
- CharSequence displayName) {
- if (mContainer != null) {
- if (pickTarget != null) {
- final Locale locale = getResources().getConfiguration().locale;
- switch (action) {
- case BaseActivity.State.ACTION_OPEN_TREE:
- final String raw = getString(R.string.menu_select).toUpperCase(locale);
- mPick.setText(TextUtils.expandTemplate(raw, displayName));
- mCancel.setVisibility(View.GONE);
- break;
- case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
- mPick.setText(getString(R.string.button_copy).toUpperCase(locale));
- mCancel.setVisibility(View.VISIBLE);
- break;
- default:
- throw new IllegalArgumentException("Illegal action for PickFragment.");
- }
- }
- if (pickTarget != null && pickTarget.isCreateSupported()) {
- mContainer.setVisibility(View.VISIBLE);
- } else {
- mContainer.setVisibility(View.GONE);
- }
- }
+ public void setPickTarget(int action, DocumentInfo pickTarget) {
+ mAction = action;
mPickTarget = pickTarget;
+ if (mContainer != null) {
+ updateView();
+ }
+ }
+
+ /**
+ * Applies the state of fragment to the view components.
+ */
+ private void updateView() {
+ switch (mAction) {
+ case BaseActivity.State.ACTION_OPEN_TREE:
+ mPick.setText(R.string.button_select);
+ mCancel.setVisibility(View.GONE);
+ break;
+ case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
+ mPick.setText(R.string.button_copy);
+ mCancel.setVisibility(View.VISIBLE);
+ break;
+ default:
+ mContainer.setVisibility(View.GONE);
+ return;
+ }
+
+ if (mPickTarget != null && (
+ mAction == BaseActivity.State.ACTION_OPEN_TREE ||
+ mPickTarget.isCreateSupported())) {
+ mContainer.setVisibility(View.VISIBLE);
+ } else {
+ mContainer.setVisibility(View.GONE);
+ }
}
}
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 9ef9211..c10be7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -117,6 +117,7 @@
* intercepted yet.
*/
private boolean mIntercepting;
+ private boolean mPanelExpanded;
private boolean mQsExpanded;
private boolean mQsExpandedWhenExpandingStarted;
private boolean mQsFullyExpanded;
@@ -1496,13 +1497,22 @@
updateHeader();
updateUnlockIcon();
updateNotificationTranslucency();
- mHeadsUpManager.setIsExpanded(!isFullyCollapsed());
+ updatePanelExpanded();
mNotificationStackScroller.setShadeExpanded(!isFullyCollapsed());
if (DEBUG) {
invalidate();
}
}
+ private void updatePanelExpanded() {
+ boolean isExpanded = !isFullyCollapsed();
+ if (mPanelExpanded != isExpanded) {
+ mHeadsUpManager.setIsExpanded(isExpanded);
+ mStatusBar.setPanelExpanded(isExpanded);
+ mPanelExpanded = isExpanded;
+ }
+ }
+
/**
* @return a temporary override of {@link #mQsMaxExpansionHeight}, which is needed when
* collapsing QS / the panel when QS was scrolled
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1361038..9fe591e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1967,6 +1967,10 @@
return !mUnlockMethodCache.isCurrentlyInsecure();
}
+ public void setPanelExpanded(boolean isExpanded) {
+ mStatusBarWindowManager.setPanelExpanded(isExpanded);
+ }
+
/**
* All changes to the status bar and notifications funnel through here and are batched.
*/
@@ -2027,7 +2031,7 @@
// Expand the window to encompass the full screen in anticipation of the drag.
// This is only possible to do atomically because the status bar is at the top of the screen!
- mStatusBarWindowManager.setStatusBarExpanded(true);
+ mStatusBarWindowManager.setPanelVisible(true);
mStatusBarView.setFocusable(false);
visibilityChanged(true);
@@ -2156,7 +2160,7 @@
visibilityChanged(false);
// Shrink the window to the size of the status bar only
- mStatusBarWindowManager.setStatusBarExpanded(false);
+ mStatusBarWindowManager.setPanelVisible(false);
mStatusBarWindowManager.setForceStatusBarVisible(false);
mStatusBarView.setFocusable(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 422d868..4f1c652 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -114,12 +114,12 @@
}
private void applyFocusableFlag(State state) {
+ boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
if (state.isKeyguardShowingAndNotOccluded() && state.keyguardNeedsInput
- && state.bouncerShowing
- || BaseStatusBar.ENABLE_REMOTE_INPUT && state.statusBarExpanded) {
+ && state.bouncerShowing || BaseStatusBar.ENABLE_REMOTE_INPUT && panelFocusable) {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- } else if (state.isKeyguardShowingAndNotOccluded() || state.statusBarFocusable) {
+ } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else {
@@ -130,7 +130,7 @@
private void applyHeight(State state) {
boolean expanded = !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded()
- || state.statusBarExpanded || state.keyguardFadingAway || state.bouncerShowing
+ || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing
|| state.headsUpShowing);
if (expanded) {
mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT;
@@ -213,9 +213,9 @@
apply(mCurrentState);
}
- public void setStatusBarExpanded(boolean expanded) {
- mCurrentState.statusBarExpanded = expanded;
- mCurrentState.statusBarFocusable = expanded;
+ public void setPanelVisible(boolean visible) {
+ mCurrentState.panelVisible = visible;
+ mCurrentState.statusBarFocusable = visible;
apply(mCurrentState);
}
@@ -267,11 +267,17 @@
apply(mCurrentState);
}
+ public void setPanelExpanded(boolean isExpanded) {
+ mCurrentState.panelExpanded = isExpanded;
+ apply(mCurrentState);
+ }
+
private static class State {
boolean keyguardShowing;
boolean keyguardOccluded;
boolean keyguardNeedsInput;
- boolean statusBarExpanded;
+ boolean panelVisible;
+ boolean panelExpanded;
boolean statusBarFocusable;
boolean bouncerShowing;
boolean keyguardFadingAway;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 23813d1..ad21555 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -148,6 +148,11 @@
android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
// Kick current state into place
+ final List<DiskInfo> disks = mStorageManager.getDisks();
+ for (DiskInfo disk : disks) {
+ onDiskScannedInternal(disk, disk.volumeCount);
+ }
+
final List<VolumeInfo> vols = mStorageManager.getVolumes();
for (VolumeInfo vol : vols) {
onVolumeStateChangedInternal(vol);
@@ -194,7 +199,7 @@
}
private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
- if (volumeCount == 0) {
+ if (volumeCount == 0 && disk.size > 0) {
// No supported volumes found, give user option to format
final CharSequence title = mContext.getString(
R.string.ext_media_unmountable_notification_title, disk.getDescription());
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 6c1023c..01cc2ca 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1725,28 +1725,68 @@
// At package-changed we only care about looking at new transport states
if (changed) {
try {
+ String[] components =
+ intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+
if (MORE_DEBUG) {
Slog.i(TAG, "Package " + pkgName + " changed; rechecking");
+ for (int i = 0; i < components.length; i++) {
+ Slog.i(TAG, " * " + components[i]);
+ }
}
- // unbind existing possibly-stale connections to that package's transports
+
+ // In general we need to try to bind any time we see a component enable
+ // state change, because that change may have made a transport available.
+ // However, because we currently only support a single transport component
+ // per package, we can skip the bind attempt if the change (a) affects a
+ // package known to host a transport, but (b) does not affect the known
+ // transport component itself.
+ //
+ // In addition, if the change *is* to a known transport component, we need
+ // to unbind it before retrying the binding.
+ boolean tryBind = true;
synchronized (mTransports) {
TransportConnection conn = mTransportConnections.get(pkgName);
if (conn != null) {
+ // We have a bound transport in this package; do we need to rebind it?
final ServiceInfo svc = conn.mTransport;
ComponentName svcName =
new ComponentName(svc.packageName, svc.name);
- String flatName = svcName.flattenToShortString();
- Slog.i(TAG, "Unbinding " + svcName);
-
- mContext.unbindService(conn);
- mTransportConnections.remove(pkgName);
- mTransports.remove(mTransportNames.get(flatName));
- mTransportNames.remove(flatName);
+ if (svc.packageName.equals(pkgName)) {
+ final String className = svcName.getClassName();
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Checking need to rebind " + className);
+ }
+ // See whether it's the transport component within this package
+ boolean isTransport = false;
+ for (int i = 0; i < components.length; i++) {
+ if (className.equals(components[i])) {
+ // Okay, it's an existing transport component.
+ final String flatName = svcName.flattenToShortString();
+ mContext.unbindService(conn);
+ mTransportConnections.remove(pkgName);
+ mTransports.remove(mTransportNames.get(flatName));
+ mTransportNames.remove(flatName);
+ isTransport = true;
+ break;
+ }
+ }
+ if (!isTransport) {
+ // A non-transport component within a package that is hosting
+ // a bound transport
+ tryBind = false;
+ }
+ }
}
}
- // and then (re)bind as appropriate
- PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
- checkForTransportAndBind(app);
+ // and now (re)bind as appropriate
+ if (tryBind) {
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Yes, need to recheck binding");
+ }
+ PackageInfo app = mPackageManager.getPackageInfo(pkgName, 0);
+ checkForTransportAndBind(app);
+ }
} catch (NameNotFoundException e) {
// Nope, can't find it - just ignore
if (MORE_DEBUG) {
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 7d427d6..79c66b9 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -408,11 +408,19 @@
}
}
if (repCbs != null) {
- for (int i=0; i<repCbs.size(); i++) {
- try {
- repCbs.get(i).mCallback.opChanged(code, packageName);
- } catch (RemoteException e) {
+ // There are components watching for mode changes such as window manager
+ // and location manager which are in our process. The callbacks in these
+ // components may require permissions our remote caller does not have.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ for (int i = 0; i < repCbs.size(); i++) {
+ try {
+ repCbs.get(i).mCallback.opChanged(code, packageName);
+ } catch (RemoteException e) {
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index e00cf5b..d48953d 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -973,6 +973,7 @@
}
}
+ disk.volumeCount = volumeCount;
mCallbacks.notifyDiskScanned(disk, volumeCount);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0ecdd61..28a786a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -369,11 +369,14 @@
/** Permission grant: grant the permission as an install permission. */
private static final int GRANT_INSTALL = 2;
+ /** Permission grant: grant the permission as an install permission for a legacy app. */
+ private static final int GRANT_INSTALL_LEGACY = 3;
+
/** Permission grant: grant the permission as a runtime one. */
- private static final int GRANT_RUNTIME = 3;
+ private static final int GRANT_RUNTIME = 4;
/** Permission grant: grant as runtime a permission that was granted as an install time one. */
- private static final int GRANT_UPGRADE = 4;
+ private static final int GRANT_UPGRADE = 5;
final ServiceThread mHandlerThread;
@@ -4133,6 +4136,7 @@
final int userId = UserHandle.getCallingUserId();
ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
+ ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
@@ -4155,27 +4159,22 @@
// Try to get the status from User settings first
int status = getDomainVerificationStatusLPr(ps, userId);
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
- result.add(info);
+ alwaysList.add(info);
} else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
neverList.add(info);
- } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED ||
+ status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK) {
undefinedList.add(info);
}
}
}
- // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
- result.addAll(undefinedList);
- // If there is nothing selected, add all candidates and remove the ones that the User
- // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state and
- // also remove Browser Apps ones.
- // If there is still none after this pass, add all Browser Apps and
- // let the User decide with the Disambiguation dialog if there are several ones.
- if (result.size() == 0) {
- result.addAll(candidates);
- }
- result.removeAll(neverList);
- result.removeAll(matchAllList);
- if (result.size() == 0) {
+ // First try to add the "always" if there is any
+ if (alwaysList.size() > 0) {
+ result.addAll(alwaysList);
+ } else {
+ // Add all undefined Apps as we want them to appear in the Disambiguation dialog.
+ result.addAll(undefinedList);
+ // Also add Browsers (all of them or only the default one)
if ((flags & MATCH_ALL) != 0) {
result.addAll(matchAllList);
} else {
@@ -4200,6 +4199,13 @@
result.addAll(matchAllList);
}
}
+
+ // If there is nothing selected, add all candidates and remove the ones that the User
+ // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state
+ if (result.size() == 0) {
+ result.addAll(candidates);
+ result.removeAll(neverList);
+ }
}
}
if (DEBUG_PREFERRED) {
@@ -7738,7 +7744,7 @@
case PermissionInfo.PROTECTION_DANGEROUS: {
if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1) {
// For legacy apps dangerous permissions are install time ones.
- grant = GRANT_INSTALL;
+ grant = GRANT_INSTALL_LEGACY;
} else if (ps.isSystem()) {
final int[] updatedUserIds = ps.getPermissionsUpdatedForUserIds();
if (origPermissions.hasInstallPermission(bp.name)) {
@@ -7798,6 +7804,28 @@
switch (grant) {
case GRANT_INSTALL: {
+ // Revoke this as runtime permission to handle the case of
+ // a runtime permssion being downgraded to an install one.
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ if (origPermissions.getRuntimePermissionState(
+ bp.name, userId) != null) {
+ // Revoke the runtime permission and clear the flags.
+ origPermissions.revokeRuntimePermission(bp, userId);
+ origPermissions.updatePermissionFlags(bp, userId,
+ PackageManager.MASK_PERMISSION_FLAGS, 0);
+ // If we revoked a permission permission, we have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
+ }
+ }
+ // Grant an install permission.
+ if (permissionsState.grantInstallPermission(bp) !=
+ PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ changedInstallPermission = true;
+ }
+ } break;
+
+ case GRANT_INSTALL_LEGACY: {
// Grant an install permission.
if (permissionsState.grantInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b84b506..d956d76 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3187,10 +3187,13 @@
}
}
if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
- // To change the format, we need to re-build the surface.
- winAnimator.destroySurfaceLocked();
- toBeDisplayed = true;
- surfaceChanged = true;
+ // If the format can be changed in place yaay!
+ // If not, fall back to a surface re-build
+ if (!winAnimator.tryChangeFormatInPlaceLocked()) {
+ winAnimator.destroySurfaceLocked();
+ toBeDisplayed = true;
+ surfaceChanged = true;
+ }
}
try {
if (!win.mHasSurface) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 424e2e2..e9023fd 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -146,6 +146,9 @@
boolean mKeyguardGoingAwayAnimation;
+ /** The pixel format of the underlying SurfaceControl */
+ int mSurfaceFormat;
+
/** This is set when there is no Surface */
static final int NO_SURFACE = 0;
/** This is set after the Surface has been created but before the window has been drawn. During
@@ -845,6 +848,7 @@
flags |= SurfaceControl.OPAQUE;
}
+ mSurfaceFormat = format;
if (DEBUG_SURFACE_TRACE) {
mSurfaceControl = new SurfaceTrace(
mSession.mSurfaceSession,
@@ -1610,6 +1614,28 @@
}
}
+ /**
+ * Try to change the pixel format without recreating the surface. This
+ * will be common in the case of changing from PixelFormat.OPAQUE to
+ * PixelFormat.TRANSLUCENT in the hardware-accelerated case as both
+ * requested formats resolve to the same underlying SurfaceControl format
+ * @return True if format was succesfully changed, false otherwise
+ */
+ boolean tryChangeFormatInPlaceLocked() {
+ if (mSurfaceControl == null) {
+ return false;
+ }
+ final LayoutParams attrs = mWin.getAttrs();
+ final boolean isHwAccelerated = (attrs.flags &
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+ final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+ if (format == mSurfaceFormat) {
+ setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format));
+ return true;
+ }
+ return false;
+ }
+
void setOpaqueLocked(boolean isOpaque) {
if (mSurfaceControl == null) {
return;
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index f05a1ef..a25d327 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -151,6 +151,7 @@
private final CharSequence mShortDescription;
private final List<String> mSupportedUriSchemes;
private final Icon mIcon;
+ private boolean mIsEnabled;
/**
* Helper class for creating a {@link PhoneAccount}.
@@ -165,6 +166,7 @@
private CharSequence mShortDescription;
private List<String> mSupportedUriSchemes = new ArrayList<String>();
private Icon mIcon;
+ private boolean mIsEnabled = false;
/**
* Creates a builder with the specified {@link PhoneAccountHandle} and label.
@@ -190,6 +192,7 @@
mShortDescription = phoneAccount.getShortDescription();
mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
mIcon = phoneAccount.getIcon();
+ mIsEnabled = phoneAccount.isEnabled();
}
/**
@@ -288,6 +291,18 @@
}
/**
+ * Sets the enabled state of the phone account.
+ *
+ * @param isEnabled The enabled state.
+ * @return The builder.
+ * @hide
+ */
+ public Builder setIsEnabled(boolean isEnabled) {
+ mIsEnabled = isEnabled;
+ return this;
+ }
+
+ /**
* Creates an instance of a {@link PhoneAccount} based on the current builder settings.
*
* @return The {@link PhoneAccount}.
@@ -307,7 +322,8 @@
mHighlightColor,
mLabel,
mShortDescription,
- mSupportedUriSchemes);
+ mSupportedUriSchemes,
+ mIsEnabled);
}
}
@@ -320,7 +336,8 @@
int highlightColor,
CharSequence label,
CharSequence shortDescription,
- List<String> supportedUriSchemes) {
+ List<String> supportedUriSchemes,
+ boolean isEnabled) {
mAccountHandle = account;
mAddress = address;
mSubscriptionAddress = subscriptionAddress;
@@ -330,6 +347,7 @@
mLabel = label;
mShortDescription = shortDescription;
mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
+ mIsEnabled = isEnabled;
}
public static Builder builder(
@@ -437,6 +455,15 @@
}
/**
+ * Indicates whether the user has enabled this phone account or not {@code PhoneAccounts}.
+ *
+ * @return The {@code true} if the account is enabled by the user, {@code false} otherwise.
+ */
+ public boolean isEnabled() {
+ return mIsEnabled;
+ }
+
+ /**
* Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
* scheme.
*
@@ -466,6 +493,14 @@
return mHighlightColor;
}
+ /**
+ * Sets the enabled state of the phone account.
+ * @hide
+ */
+ public void setIsEnabled(boolean isEnabled) {
+ mIsEnabled = isEnabled;
+ }
+
//
// Parcelable implementation
//
@@ -500,12 +535,14 @@
out.writeCharSequence(mLabel);
out.writeCharSequence(mShortDescription);
out.writeStringList(mSupportedUriSchemes);
+
if (mIcon == null) {
out.writeInt(0);
} else {
out.writeInt(1);
mIcon.writeToParcel(out, flags);
}
+ out.writeByte((byte) (mIsEnabled ? 1 : 0));
}
public static final Creator<PhoneAccount> CREATOR
@@ -547,11 +584,14 @@
} else {
mIcon = null;
}
+ mIsEnabled = in.readByte() == 1;
}
@Override
public String toString() {
- StringBuilder sb = new StringBuilder().append("[PhoneAccount: ")
+ StringBuilder sb = new StringBuilder().append("[[")
+ .append(mIsEnabled ? 'X' : ' ')
+ .append("] PhoneAccount: ")
.append(mAccountHandle)
.append(" Capabilities: ")
.append(mCapabilities)
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index c8ed2b0..308c204 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -377,15 +377,23 @@
}
/**
- * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
- * calls with a specified URI scheme.
+ * Return the {@link PhoneAccount} which will be used to place outgoing calls to addresses with
+ * the specified {@code uriScheme}. This {@link PhoneAccount} will always be a member of the
+ * list which is returned from invoking {@link #getCallCapablePhoneAccounts()}. The specific
+ * account returned depends on the following priorities:
+ * <ul>
+ * <li> If the user-selected default {@link PhoneAccount} supports the specified scheme, it will
+ * be returned.
+ * </li>
+ * <li> If there exists only one {@link PhoneAccount} that supports the specified scheme, it
+ * will be returned.
+ * </li>
+ * </ul>
* <p>
- * Apps must be prepared for this method to return {@code null}, indicating that there currently
- * exists no user-chosen default {@code PhoneAccount}.
- * <p>
+ * If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}.
+ *
* @param uriScheme The URI scheme.
- * @return The {@link PhoneAccountHandle} corresponding to the user-chosen default for outgoing
- * phone calls for a specified URI scheme.
+ * @return The {@link PhoneAccountHandle} corresponding to the account to be used.
*/
public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
try {
@@ -403,7 +411,7 @@
* Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
* calls. This {@code PhoneAccount} will always be a member of the list which is returned from
* calling {@link #getCallCapablePhoneAccounts()}
- *
+ * <p>
* Apps must be prepared for this method to return {@code null}, indicating that there currently
* exists no user-chosen default {@code PhoneAccount}.
*
@@ -422,7 +430,7 @@
}
/**
- * Sets the default account for making outgoing phone calls.
+ * Sets the user-chosen default for making outgoing phone calls.
* @hide
*/
public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
@@ -439,6 +447,7 @@
* Returns the current SIM call manager. Apps must be prepared for this method to return
* {@code null}, indicating that there currently exists no user-chosen default
* {@code PhoneAccount}.
+ *
* @return The phone account handle of the current sim call manager.
*/
public PhoneAccountHandle getSimCallManager() {
@@ -454,6 +463,7 @@
/**
* Sets the SIM call manager to the specified phone account.
+ *
* @param accountHandle The phone account handle of the account to set as the sim call manager.
* @hide
*/
@@ -469,6 +479,7 @@
/**
* Returns the list of registered SIM call managers.
+ *
* @return List of registered SIM call managers.
* @hide
*/
@@ -497,16 +508,6 @@
}
/**
- * Returns the list of registered SIM call managers.
- * @return List of registered SIM call managers.
- * @hide
- */
- @SystemApi
- public List<PhoneAccountHandle> getRegisteredConnectionManagers() {
- return getSimCallManagers();
- }
-
- /**
* Returns a list of the {@link PhoneAccountHandle}s which can be used to make and receive phone
* calls which support the specified URI scheme.
* <P>
@@ -534,20 +535,33 @@
/**
- * Return a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
- * calls.
+ * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
+ * calls. The returned list includes only those accounts which have been explicitly enabled
+ * by the user.
*
* @see #EXTRA_PHONE_ACCOUNT_HANDLE
* @return A list of {@code PhoneAccountHandle} objects.
- *
*/
public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
+ return getCallCapablePhoneAccounts(false);
+ }
+
+ /**
+ * Returns a list of {@link PhoneAccountHandle}s including those which have not been enabled
+ * by the user.
+ *
+ * @return A list of {@code PhoneAccountHandle} objects.
+ * @hide
+ */
+ public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) {
try {
if (isServiceConnected()) {
- return getTelecomService().getCallCapablePhoneAccounts(mContext.getOpPackageName());
+ return getTelecomService().getCallCapablePhoneAccounts(
+ includeDisabledAccounts, mContext.getOpPackageName());
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts", e);
+ Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" +
+ includeDisabledAccounts + ")", e);
}
return new ArrayList<>();
}
@@ -1163,6 +1177,25 @@
}
}
+ /**
+ * Enables and disables specified phone account.
+ *
+ * @param handle Handle to the phone account.
+ * @param isEnabled Enable state of the phone account.
+ * @hide
+ */
+ @SystemApi
+ public void enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled) {
+ ITelecomService service = getTelecomService();
+ if (service != null) {
+ try {
+ service.enablePhoneAccount(handle, isEnabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error enablePhoneAbbount", e);
+ }
+ }
+ }
+
private ITelecomService getTelecomService() {
return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index bc76f06..aa02021 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -53,7 +53,8 @@
/**
* @see TelecomServiceImpl#getCallCapablePhoneAccounts
*/
- List<PhoneAccountHandle> getCallCapablePhoneAccounts(String callingPackage);
+ List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+ boolean includeDisabledAccounts, String callingPackage);
/**
* @see TelecomManager#getPhoneAccountsSupportingScheme
@@ -226,4 +227,9 @@
* @see TelecomServiceImpl#placeCall
*/
void placeCall(in Uri handle, in Bundle extras, String callingPackage);
+
+ /**
+ * @see TelecomServiceImpl#enablePhoneAccount
+ */
+ void enablePhoneAccount(in PhoneAccountHandle accountHandle, boolean isEnabled);
}
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 572fdc9..771cf57 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -444,7 +444,7 @@
@Override
public int getDimensionPixelSize(int index, int defValue) {
try {
- return getDimension(index);
+ return getDimension(index, null);
} catch (RuntimeException e) {
String s = getString(index);
@@ -474,12 +474,12 @@
@Override
public int getLayoutDimension(int index, String name) {
try {
- // this will throw an exception
- return getDimension(index);
+ // this will throw an exception if not found.
+ return getDimension(index, name);
} catch (RuntimeException e) {
if (LayoutInflater_Delegate.sIsInInclude) {
- throw new RuntimeException();
+ throw new RuntimeException("Layout Dimension '" + name + "' not found.");
}
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
@@ -494,9 +494,13 @@
return getDimensionPixelSize(index, defValue);
}
- private int getDimension(int index) {
+ /** @param name attribute name, used for error reporting. */
+ private int getDimension(int index, @Nullable String name) {
String s = getString(index);
if (s == null) {
+ if (name != null) {
+ throw new RuntimeException("Attribute '" + name + "' not found");
+ }
throw new RuntimeException();
}
// Check if the value is a magic constant that doesn't require a unit.
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 4072302..27b406a 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -181,7 +181,8 @@
// ---- END CHANGES
params = group.generateLayoutParams(attrs);
-
+ } catch (RuntimeException ignored) {
+ // Ignore, just fail over to child attrs.
} finally {
// ---- START CHANGES
sIsInInclude = false;