Merge "Remove focusablilty of the status bar." into mnc-dev
diff --git a/Android.mk b/Android.mk
index 1de3625..121bc8e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -668,7 +668,8 @@
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
dirs_to_document := \
$(dirs_to_check_apis) \
- $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS))
+ $(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS)) \
+ $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS)) \
# These are relative to frameworks/base
html_dirs := \
diff --git a/api/current.txt b/api/current.txt
index ea33eaf..4a7dc82 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4772,9 +4772,9 @@
field public int flags;
field public android.app.PendingIntent fullScreenIntent;
field public android.widget.RemoteViews headsUpContentView;
- field public int icon;
+ field public deprecated int icon;
field public int iconLevel;
- field public android.graphics.Bitmap largeIcon;
+ field public deprecated android.graphics.Bitmap largeIcon;
field public int ledARGB;
field public int ledOffMS;
field public int ledOnMS;
@@ -4790,20 +4790,22 @@
}
public static class Notification.Action implements android.os.Parcelable {
- ctor public Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public deprecated Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Action clone();
method public int describeContents();
method public android.os.Bundle getExtras();
+ method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
field public android.app.PendingIntent actionIntent;
- field public int icon;
+ field public deprecated int icon;
field public java.lang.CharSequence title;
}
public static final class Notification.Action.Builder {
- ctor public Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public deprecated Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public Notification.Action.Builder(android.graphics.drawable.Icon, java.lang.CharSequence, android.app.PendingIntent);
ctor public Notification.Action.Builder(android.app.Notification.Action);
method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
@@ -4851,7 +4853,7 @@
public static class Notification.Builder {
ctor public Notification.Builder(android.content.Context);
- method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+ method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Builder addAction(android.app.Notification.Action);
method public android.app.Notification.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Builder addPerson(java.lang.String);
@@ -28534,14 +28536,13 @@
package android.service.chooser {
public final class ChooserTarget implements android.os.Parcelable {
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.app.PendingIntent);
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.IntentSender);
+ ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.ComponentName, android.os.Bundle);
method public int describeContents();
+ method public android.content.ComponentName getComponentName();
method public android.graphics.drawable.Icon getIcon();
- method public android.content.IntentSender getIntentSender();
+ method public android.os.Bundle getIntentExtras();
method public float getScore();
method public java.lang.CharSequence getTitle();
- method public boolean sendIntent(android.content.Context, android.content.Intent);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index cbb1bb2..e83f8c6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -104,6 +104,7 @@
field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
field public static final java.lang.String HDMI_CEC = "android.permission.HDMI_CEC";
field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
+ field public static final java.lang.String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
field public static final java.lang.String INSTALL_PACKAGES = "android.permission.INSTALL_PACKAGES";
field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
@@ -181,6 +182,7 @@
field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
+ field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
@@ -4888,9 +4890,9 @@
field public int flags;
field public android.app.PendingIntent fullScreenIntent;
field public android.widget.RemoteViews headsUpContentView;
- field public int icon;
+ field public deprecated int icon;
field public int iconLevel;
- field public android.graphics.Bitmap largeIcon;
+ field public deprecated android.graphics.Bitmap largeIcon;
field public int ledARGB;
field public int ledOffMS;
field public int ledOnMS;
@@ -4906,20 +4908,22 @@
}
public static class Notification.Action implements android.os.Parcelable {
- ctor public Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public deprecated Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Action clone();
method public int describeContents();
method public android.os.Bundle getExtras();
+ method public android.graphics.drawable.Icon getIcon();
method public android.app.RemoteInput[] getRemoteInputs();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR;
field public android.app.PendingIntent actionIntent;
- field public int icon;
+ field public deprecated int icon;
field public java.lang.CharSequence title;
}
public static final class Notification.Action.Builder {
- ctor public Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public deprecated Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+ ctor public Notification.Action.Builder(android.graphics.drawable.Icon, java.lang.CharSequence, android.app.PendingIntent);
ctor public Notification.Action.Builder(android.app.Notification.Action);
method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
@@ -4967,7 +4971,7 @@
public static class Notification.Builder {
ctor public Notification.Builder(android.content.Context);
- method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+ method public deprecated android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Builder addAction(android.app.Notification.Action);
method public android.app.Notification.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Builder addPerson(java.lang.String);
@@ -9436,6 +9440,7 @@
method public void setAppIcon(android.graphics.Bitmap);
method public void setAppLabel(java.lang.CharSequence);
method public void setAppPackageName(java.lang.String);
+ method public void setGrantedRuntimePermissions(java.lang.String[]);
method public void setInstallLocation(int);
method public void setOriginatingUri(android.net.Uri);
method public void setReferrerUri(android.net.Uri);
@@ -30591,14 +30596,13 @@
package android.service.chooser {
public final class ChooserTarget implements android.os.Parcelable {
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.app.PendingIntent);
- ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.IntentSender);
+ ctor public ChooserTarget(java.lang.CharSequence, android.graphics.drawable.Icon, float, android.content.ComponentName, android.os.Bundle);
method public int describeContents();
+ method public android.content.ComponentName getComponentName();
method public android.graphics.drawable.Icon getIcon();
- method public android.content.IntentSender getIntentSender();
+ method public android.os.Bundle getIntentExtras();
method public float getScore();
method public java.lang.CharSequence getTitle();
- method public boolean sendIntent(android.content.Context, android.content.Intent);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.chooser.ChooserTarget> CREATOR;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7572799..e782fb8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3771,6 +3771,11 @@
/**
* Callback for the result from requesting permissions. This method
* is invoked for every call on {@link #requestPermissions(String[], int)}.
+ * <p>
+ * <strong>Note:</strong> It is possible that the permissions request interaction
+ * with the user is interrupted. In this case you will receive empty permissions
+ * and results arrays which should be treated as a cancellation.
+ * </p>
*
* @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
* @param permissions The requested permissions. Never null.
@@ -3977,16 +3982,24 @@
* as intermediaries that dispatch their intent to the target the user selects -- to
* do this, they must perform all security checks including permission grants as if
* their launch had come from the original activity.
+ * @param intent The Intent to start.
+ * @param options ActivityOptions or null.
+ * @param ignoreTargetSecurity If true, the activity manager will not check whether the
+ * caller it is doing the start is, is actually allowed to start the target activity.
+ * If you set this to true, you must set an explicit component in the Intent and do any
+ * appropriate security checks yourself.
+ * @param userId The user the new activity should run as.
* @hide
*/
- public void startActivityAsCaller(Intent intent, @Nullable Bundle options, int userId) {
+ public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
+ boolean ignoreTargetSecurity, int userId) {
if (mParent != null) {
throw new RuntimeException("Can't be called from a child");
}
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivityAsCaller(
this, mMainThread.getApplicationThread(), mToken, this,
- intent, -1, options, userId);
+ intent, -1, options, ignoreTargetSecurity, userId);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, -1, ar.getResultCode(),
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index fc408a8..bfb92c4 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -206,9 +206,11 @@
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
+ boolean ignoreTargetSecurity = data.readInt() != 0;
int userId = data.readInt();
int result = startActivityAsCaller(app, callingPackage, intent, resolvedType,
- resultTo, resultWho, requestCode, startFlags, profilerInfo, options, userId);
+ resultTo, resultWho, requestCode, startFlags, profilerInfo, options,
+ ignoreTargetSecurity, userId);
reply.writeNoException();
reply.writeInt(result);
return true;
@@ -2675,7 +2677,8 @@
}
public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException {
+ int startFlags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity,
+ int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -2699,6 +2702,7 @@
} else {
data.writeInt(0);
}
+ data.writeInt(ignoreTargetSecurity ? 1 : 0);
data.writeInt(userId);
mRemote.transact(START_ACTIVITY_AS_CALLER_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ad104a4..7fbb99a 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -25,6 +25,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -238,8 +239,12 @@
if (decorView != null && decorView.getBackground() == null) {
getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
}
+ final boolean targetsM = decorView == null || decorView.getContext()
+ .getApplicationInfo().targetSdkVersion >= VERSION_CODES.MNC;
+ ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames :
+ mAllSharedElementNames;
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
- mSharedElementNames, resultCode, data);
+ sharedElementNames, resultCode, data);
mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
@Override
public void onTranslucentConversionComplete(boolean drawComplete) {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 5490fe7..82206ea 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1213,6 +1213,11 @@
/**
* Callback for the result from requesting permissions. This method
* is invoked for every call on {@link #requestPermissions(String[], int)}.
+ * <p>
+ * <strong>Note:</strong> It is possible that the permissions request interaction
+ * with the user is interrupted. In this case you will receive empty permissions
+ * and results arrays which should be treated as a cancellation.
+ * </p>
*
* @param requestCode The request code passed in {@link #requestPermissions(String[], int)}.
* @param permissions The requested permissions. Never null.
@@ -1249,7 +1254,8 @@
*/
public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
if (mHost != null) {
- mHost.getContext().getPackageManager().shouldShowRequestPermissionRationale(permission);
+ return mHost.getContext().getPackageManager()
+ .shouldShowRequestPermissionRationale(permission);
}
return false;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 1d87d77..5eb3961 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -72,7 +72,8 @@
ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException;
public int startActivityAsCaller(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int flags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException;
+ int flags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity,
+ int userId) throws RemoteException;
public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho,
int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 653f1b6..c2d901d 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1701,7 +1701,8 @@
*/
public ActivityResult execStartActivityAsCaller(
Context who, IBinder contextThread, IBinder token, Activity target,
- Intent intent, int requestCode, Bundle options, int userId) {
+ Intent intent, int requestCode, Bundle options, boolean ignoreTargetSecurity,
+ int userId) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
@@ -1725,7 +1726,7 @@
.startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
- requestCode, 0, null, options, userId);
+ requestCode, 0, null, options, ignoreTargetSecurity, userId);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c3dece8..b0d8541 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -166,8 +166,10 @@
/**
* The resource id of a drawable to use as the icon in the status bar.
- * This is required; notifications with an invalid icon resource will not be shown.
+ *
+ * @deprecated Use {@link Builder#setSmallIcon(Icon)} instead.
*/
+ @Deprecated
@DrawableRes
public int icon;
@@ -269,8 +271,11 @@
public RemoteViews headsUpContentView;
/**
- * The bitmap that may escape the bounds of the panel and bar.
+ * A large bitmap to be shown in the notification content area.
+ *
+ * @deprecated Use {@link Builder#setLargeIcon(Icon)} instead.
*/
+ @Deprecated
public Bitmap largeIcon;
/**
@@ -900,11 +905,15 @@
*/
public static class Action implements Parcelable {
private final Bundle mExtras;
+ private Icon mIcon;
private final RemoteInput[] mRemoteInputs;
/**
* Small icon representing the action.
+ *
+ * @deprecated Use {@link Action#getIcon()} instead.
*/
+ @Deprecated
public int icon;
/**
@@ -919,7 +928,12 @@
public PendingIntent actionIntent;
private Action(Parcel in) {
- icon = in.readInt();
+ if (in.readInt() != 0) {
+ mIcon = Icon.CREATOR.createFromParcel(in);
+ }
+ if (mIcon.getType() == Icon.TYPE_RESOURCE) {
+ icon = mIcon.getResId();
+ }
title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
if (in.readInt() == 1) {
actionIntent = PendingIntent.CREATOR.createFromParcel(in);
@@ -929,15 +943,16 @@
}
/**
- * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}.
+ * @deprecated Use {@link android.app.Notification.Action.Builder}.
*/
+ @Deprecated
public Action(int icon, CharSequence title, PendingIntent intent) {
- this(icon, title, intent, new Bundle(), null);
+ this(Icon.createWithResource("", icon), title, intent, new Bundle(), null);
}
- private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras,
+ private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
RemoteInput[] remoteInputs) {
- this.icon = icon;
+ this.mIcon = icon;
this.title = title;
this.actionIntent = intent;
this.mExtras = extras != null ? extras : new Bundle();
@@ -945,6 +960,17 @@
}
/**
+ * Return an icon representing the action.
+ */
+ public Icon getIcon() {
+ if (mIcon == null && icon != 0) {
+ // you snuck an icon in here without using the builder; let's try to keep it
+ mIcon = Icon.createWithResource("", icon);
+ }
+ return mIcon;
+ }
+
+ /**
* Get additional metadata carried around with this Action.
*/
public Bundle getExtras() {
@@ -963,7 +989,7 @@
* Builder class for {@link Action} objects.
*/
public static final class Builder {
- private final int mIcon;
+ private final Icon mIcon;
private final CharSequence mTitle;
private final PendingIntent mIntent;
private final Bundle mExtras;
@@ -975,7 +1001,18 @@
* @param title the title of the action
* @param intent the {@link PendingIntent} to fire when users trigger this action
*/
+ @Deprecated
public Builder(int icon, CharSequence title, PendingIntent intent) {
+ this(Icon.createWithResource("", icon), title, intent, new Bundle(), null);
+ }
+
+ /**
+ * Construct a new builder for {@link Action} object.
+ * @param icon icon to show for this action
+ * @param title the title of the action
+ * @param intent the {@link PendingIntent} to fire when users trigger this action
+ */
+ public Builder(Icon icon, CharSequence title, PendingIntent intent) {
this(icon, title, intent, new Bundle(), null);
}
@@ -985,11 +1022,11 @@
* @param action the action to read fields from.
*/
public Builder(Action action) {
- this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras),
+ this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras),
action.getRemoteInputs());
}
- private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras,
+ private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
RemoteInput[] remoteInputs) {
mIcon = icon;
mTitle = title;
@@ -1063,7 +1100,7 @@
@Override
public Action clone() {
return new Action(
- icon,
+ getIcon(),
title,
actionIntent, // safe to alias
new Bundle(mExtras),
@@ -1075,7 +1112,13 @@
}
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeInt(icon);
+ final Icon ic = getIcon();
+ if (ic != null) {
+ out.writeInt(1);
+ ic.writeToParcel(out, 0);
+ } else {
+ out.writeInt(0);
+ }
TextUtils.writeToParcel(title, out, flags);
if (actionIntent != null) {
out.writeInt(1);
@@ -2725,7 +2768,10 @@
* @param icon Resource ID of a drawable that represents the action.
* @param title Text describing the action.
* @param intent PendingIntent to be fired when the action is invoked.
+ *
+ * @deprecated Use {@link #addAction(Action)} instead.
*/
+ @Deprecated
public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
mActions.add(new Action(icon, safeCharSequence(title), intent));
return this;
@@ -3122,7 +3168,7 @@
private RemoteViews generateActionButton(Action action) {
final boolean tombstone = (action.actionIntent == null);
- RemoteViews button = new RemoteViews(mContext.getPackageName(),
+ RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(),
tombstone ? getActionTombstoneLayoutResource()
: getActionLayoutResource());
button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0);
@@ -4265,7 +4311,7 @@
*
* In the expanded form, {@link Notification#bigContentView}, up to 5
* {@link Notification.Action}s specified with
- * {@link Notification.Builder#addAction(int, CharSequence, PendingIntent) addAction} will be
+ * {@link Notification.Builder#addAction(Action) addAction} will be
* shown as icon-only pushbuttons, suitable for transport controls. The Bitmap given to
* {@link Notification.Builder#setLargeIcon(android.graphics.Bitmap) setLargeIcon()} will be
* treated as album artwork.
@@ -4391,7 +4437,7 @@
private RemoteViews generateMediaActionButton(Action action) {
final boolean tombstone = (action.actionIntent == null);
- RemoteViews button = new RemoteViews(mBuilder.mContext.getPackageName(),
+ RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(),
R.layout.notification_material_media_action);
button.setImageViewResource(R.id.action0, action.icon);
button.setDrawableParameters(R.id.action0, false, -1,
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 5571662..f786d2f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1023,7 +1023,7 @@
*
* <p>Note: if you app targets {@link android.os.Build.VERSION_CODES#MNC MNC}
* and above and declares as using the {@link android.Manifest.permission#CALL_PHONE}
- * permission which is not granted, then atempting to use this action will
+ * permission which is not granted, then attempting to use this action will
* result in a {@link java.lang.SecurityException}.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index b7ee82d..9341be1 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -18,8 +18,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -889,6 +891,8 @@
public String abiOverride;
/** {@hide} */
public String volumeUuid;
+ /** {@hide} */
+ public String[] grantedRuntimePermissions;
/**
* Construct parameters for a new package install session.
@@ -914,6 +918,7 @@
referrerUri = source.readParcelable(null);
abiOverride = source.readString();
volumeUuid = source.readString();
+ grantedRuntimePermissions = source.readStringArray();
}
/**
@@ -987,6 +992,23 @@
this.referrerUri = referrerUri;
}
+ /**
+ * Sets which runtime permissions to be granted to the package at installation.
+ * Using this API requires holding {@link android.Manifest.permission
+ * #INSTALL_GRANT_RUNTIME_PERMISSIONS}
+ *
+ * @param permissions The permissions to grant or null to grant all runtime
+ * permissions.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS)
+ public void setGrantedRuntimePermissions(String[] permissions) {
+ installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
+ this.grantedRuntimePermissions = permissions;
+ }
+
/** {@hide} */
public void setInstallFlagsInternal() {
installFlags |= PackageManager.INSTALL_INTERNAL;
@@ -1012,6 +1034,7 @@
pw.printPair("referrerUri", referrerUri);
pw.printPair("abiOverride", abiOverride);
pw.printPair("volumeUuid", volumeUuid);
+ pw.printPair("grantedRuntimePermissions", grantedRuntimePermissions);
pw.println();
}
@@ -1033,6 +1056,7 @@
dest.writeParcelable(referrerUri, flags);
dest.writeString(abiOverride);
dest.writeString(volumeUuid);
+ dest.writeStringArray(grantedRuntimePermissions);
}
public static final Parcelable.Creator<SessionParams>
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 46cafad..46ffe36 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -138,6 +138,45 @@
*/
public abstract void prepare(@NonNull Surface surface) throws CameraAccessException;
+
+ /**
+ * <p>Free all buffers allocated for an output Surface.</p>
+ *
+ * <p>Normally, once allocated, the image buffers for a given output Surface remain allocated
+ * for the lifetime of the capture session, to minimize latency of captures and to reduce
+ * memory allocation overhead.</p>
+ *
+ * <p>However, in some cases, it may be desirable for allocated buffers to be freed to reduce
+ * the application's memory consumption, if the particular output Surface will not be used by
+ * the application for some time.</p>
+ *
+ * <p>The tearDown() method can be used to perform this operation. After the call finishes, all
+ * unfilled image buffers will have been freed. Any future use of the target Surface may require
+ * allocation of additional buffers, as if the session had just been created. Buffers being
+ * held by the application (either explicitly as Image objects from ImageReader, or implicitly
+ * as the current texture in a SurfaceTexture or the current contents of a RS Allocation, will
+ * remain valid and allocated even when tearDown is invoked.</p>
+ *
+ * <p>A Surface that has had tearDown() called on it is eligible to have prepare() invoked on it
+ * again even if it was used as a request target before the tearDown() call, as long as it
+ * doesn't get used as a target of a request between the tearDown() and prepare() calls.</p>
+ *
+ * @param surface the output Surface for which buffers should be freed. Must be one of the
+ * the output Surfaces used to create this session.
+ *
+ * @throws CameraAccessException if the camera device is no longer connected or has
+ * encountered a fatal error.
+ * @throws IllegalStateException if this session is no longer active, either because the session
+ * was explicitly closed, a new session has been created
+ * or the camera device has been closed.
+ * @throws IllegalArgumentException if the Surface is invalid, not part of this Session, or has
+ * already been used as a target of a CaptureRequest in this
+ * session or immediately prior sessions.
+ *
+ * @hide
+ */
+ public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;
+
/**
* <p>Submit a request for an image to be captured by the camera device.</p>
*
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index c36683b..af1367c 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1994,8 +1994,9 @@
public static final int EDGE_MODE_OFF = 0;
/**
- * <p>Apply edge enhancement at a quality level that does not slow down frame rate relative to sensor
- * output</p>
+ * <p>Apply edge enhancement at a quality level that does not slow down frame rate
+ * relative to sensor output. It may be the same as OFF if edge enhancement will
+ * slow down frame rate relative to sensor.</p>
* @see CaptureRequest#EDGE_MODE
*/
public static final int EDGE_MODE_FAST = 1;
@@ -2117,7 +2118,8 @@
/**
* <p>Noise reduction is applied without reducing frame rate relative to sensor
- * output.</p>
+ * output. It may be the same as OFF if noise reduction will reduce frame rate
+ * relative to sensor.</p>
* @see CaptureRequest#NOISE_REDUCTION_MODE
*/
public static final int NOISE_REDUCTION_MODE_FAST = 1;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index a136d0f..e965d65 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1584,8 +1584,9 @@
* will be applied. HIGH_QUALITY mode indicates that the
* camera device will use the highest-quality enhancement algorithms,
* even if it slows down capture rate. FAST means the camera device will
- * not slow down capture rate when applying edge enhancement. Every output stream will
- * have a similar amount of enhancement applied.</p>
+ * not slow down capture rate when applying edge enhancement. FAST may be the same as OFF if
+ * edge enhancement will slow down capture rate. Every output stream will have a similar
+ * amount of enhancement applied.</p>
* <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular
* buffer of high-resolution images during preview and reprocess image(s) from that buffer
* into a final capture when triggered by the user. In this mode, the camera device applies
@@ -1594,7 +1595,7 @@
* since those will be reprocessed later if necessary.</p>
* <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera
* device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
- * The camera device may adjust its internal noise reduction parameters for best
+ * The camera device may adjust its internal edge enhancement parameters for best
* image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
* <p><b>Possible values:</b>
* <ul>
@@ -2003,8 +2004,9 @@
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
* even if it slows down capture rate. FAST means the camera device will not
- * slow down capture rate when applying noise filtering. Every output stream will
- * have a similar amount of enhancement applied.</p>
+ * slow down capture rate when applying noise filtering. FAST may be the same as MINIMAL if
+ * MINIMAL is listed, or the same as OFF if any noise filtering will slow down capture rate.
+ * Every output stream will have a similar amount of enhancement applied.</p>
* <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular
* buffer of high-resolution images during preview and reprocess image(s) from that buffer
* into a final capture when triggered by the user. In this mode, the camera device applies
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index f7cf1850..d5511c1 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2095,8 +2095,9 @@
* will be applied. HIGH_QUALITY mode indicates that the
* camera device will use the highest-quality enhancement algorithms,
* even if it slows down capture rate. FAST means the camera device will
- * not slow down capture rate when applying edge enhancement. Every output stream will
- * have a similar amount of enhancement applied.</p>
+ * not slow down capture rate when applying edge enhancement. FAST may be the same as OFF if
+ * edge enhancement will slow down capture rate. Every output stream will have a similar
+ * amount of enhancement applied.</p>
* <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular
* buffer of high-resolution images during preview and reprocess image(s) from that buffer
* into a final capture when triggered by the user. In this mode, the camera device applies
@@ -2105,7 +2106,7 @@
* since those will be reprocessed later if necessary.</p>
* <p>For YUV_REPROCESSING, these FAST/HIGH_QUALITY modes both mean that the camera
* device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
- * The camera device may adjust its internal noise reduction parameters for best
+ * The camera device may adjust its internal edge enhancement parameters for best
* image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
* <p><b>Possible values:</b>
* <ul>
@@ -2786,8 +2787,9 @@
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
* even if it slows down capture rate. FAST means the camera device will not
- * slow down capture rate when applying noise filtering. Every output stream will
- * have a similar amount of enhancement applied.</p>
+ * slow down capture rate when applying noise filtering. FAST may be the same as MINIMAL if
+ * MINIMAL is listed, or the same as OFF if any noise filtering will slow down capture rate.
+ * Every output stream will have a similar amount of enhancement applied.</p>
* <p>ZERO_SHUTTER_LAG is meant to be used by applications that maintain a continuous circular
* buffer of high-resolution images during preview and reprocess image(s) from that buffer
* into a final capture when triggered by the user. In this mode, the camera device applies
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 1574f93..7cb3673 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -100,4 +100,6 @@
int flush(out LongParcelable lastFrameNumber);
int prepare(int streamId);
+
+ int tearDown(int streamId);
}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 3c19cd2..d325c77 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -146,6 +146,11 @@
}
@Override
+ public void tearDown(Surface surface) throws CameraAccessException {
+ mDeviceImpl.tearDown(surface);
+ }
+
+ @Override
public synchronized int capture(CaptureRequest request, CaptureCallback callback,
Handler handler) throws CameraAccessException {
if (request == null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index d732535..a920e2b 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -169,6 +169,11 @@
}
@Override
+ public void tearDown(Surface surface) throws CameraAccessException {
+ mSessionImpl.tearDown(surface);
+ }
+
+ @Override
public int capture(CaptureRequest request, CaptureCallback listener, Handler handler)
throws CameraAccessException {
throw new UnsupportedOperationException("Constrained high speed session doesn't support"
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index c594228..91d623e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -679,6 +679,31 @@
}
}
+ public void tearDown(Surface surface) throws CameraAccessException {
+ if (surface == null) throw new IllegalArgumentException("Surface is null");
+
+ synchronized(mInterfaceLock) {
+ int streamId = -1;
+ for (int i = 0; i < mConfiguredOutputs.size(); i++) {
+ if (surface == mConfiguredOutputs.valueAt(i).getSurface()) {
+ streamId = mConfiguredOutputs.keyAt(i);
+ break;
+ }
+ }
+ if (streamId == -1) {
+ throw new IllegalArgumentException("Surface is not part of this session");
+ }
+ try {
+ mRemoteDevice.tearDown(streamId);
+ } catch (CameraRuntimeException e) {
+ throw e.asChecked();
+ } catch (RemoteException e) {
+ // impossible
+ return;
+ }
+ }
+ }
+
public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
throws CameraAccessException {
if (DEBUG) {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index f5314da..e20eaa7 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -636,6 +636,20 @@
return CameraBinderDecorator.NO_ERROR;
}
+ public int tearDown(int streamId) {
+ if (DEBUG) {
+ Log.d(TAG, "tearDown called.");
+ }
+ if (mLegacyDevice.isClosed()) {
+ Log.e(TAG, "Cannot tear down stream, device has been closed.");
+ return CameraBinderDecorator.ENODEV;
+ }
+
+ // LEGACY doesn't support actual teardown, so just a no-op
+
+ return CameraBinderDecorator.NO_ERROR;
+ }
+
@Override
public IBinder asBinder() {
// This is solely intended to be used for in-process binding.
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index d743484..aa22041 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -2393,7 +2393,7 @@
intent.setData(ContentUris.withAppendedId(CalendarContract.CONTENT_URI, alarmTime));
intent.putExtra(ALARM_TIME, alarmTime);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
- manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pi);
+ manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pi);
}
/**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d547a60..8ce1cbf 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -5957,9 +5957,7 @@
*/
public static final CharSequence getTypeLabel(Resources res, int type,
CharSequence label) {
- if (type == TYPE_CUSTOM) {
- return (label != null ? label : "");
- } else if (type == TYPE_ASSISTANT && !TextUtils.isEmpty(label)) {
+ if ((type == TYPE_CUSTOM || type == TYPE_ASSISTANT) && !TextUtils.isEmpty(label)) {
return label;
} else {
final int labelRes = getTypeLabelResource(type);
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index e1b5a6d..76eaea9 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -314,11 +314,16 @@
contentValues.put(Voicemails.IS_READ, voicemail.isRead() ? 1 : 0);
PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount();
- if (voicemail.getPhoneAccount() != null) {
+ if (phoneAccount != null) {
contentValues.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME,
phoneAccount.getComponentName().flattenToString());
contentValues.put(Voicemails.PHONE_ACCOUNT_ID, phoneAccount.getId());
}
+
+ if (voicemail.getTranscription() != null) {
+ contentValues.put(Voicemails.TRANSCRIPTION, voicemail.getTranscription());
+ }
+
return contentValues;
}
}
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
index 50c435a..c2f70cc 100644
--- a/core/java/android/service/chooser/ChooserTarget.java
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -17,20 +17,14 @@
package android.service.chooser;
-import android.app.Activity;
-import android.app.PendingIntent;
+import android.annotation.Nullable;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
-import android.util.Log;
/**
* A ChooserTarget represents a deep-link into an application as returned by a
@@ -62,11 +56,16 @@
private Icon mIcon;
/**
- * The IntentSender that will be used to deliver the intent to the target.
- * It will be {@link android.content.Intent#fillIn(android.content.Intent, int)} filled in}
- * by the real intent sent by the application.
+ * The ComponentName of the Activity to be invoked. Must be part of the target creator's
+ * own package or an Activity exported by its package.
*/
- private IntentSender mIntentSender;
+ private ComponentName mComponentName;
+
+ /**
+ * A Bundle to merge with the extras of the intent sent to this target.
+ * Any extras here will override the extras from the original intent.
+ */
+ private Bundle mIntentExtras;
/**
* The score given to this item. It can be normalized.
@@ -86,61 +85,23 @@
* Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).
* Scores for a set of targets do not need to sum to 1.</p>
*
- * <p>Before being sent, the PendingIntent supplied will be
- * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
- * to the chooser. When constructing a PendingIntent for use in a ChooserTarget, make sure
- * that you permit the relevant fields to be filled in using the appropriate flags such as
- * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
- * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
- * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
- * for {@link Intent#ACTION_SEND} intents.</p>
+ * <p>The ComponentName must be the name of an Activity component in the creator's own
+ * package, or an exported component from any other package. You may provide an optional
+ * Bundle of extras that will be merged into the final intent before it is sent to the
+ * target Activity; use this to add any additional data about the deep link that the target
+ * activity will read. e.g. conversation IDs, email addresses, etc.</p>
*
* <p>Take care not to place custom {@link android.os.Parcelable} types into
- * the PendingIntent as extras, as the system will not be able to unparcel it to merge
- * additional extras.</p>
+ * the extras bundle, as the system will not be able to unparcel them to merge them.</p>
*
* @param title title of this target that will be shown to a user
* @param icon icon to represent this target
* @param score ranking score for this target between 0.0f and 1.0f, inclusive
- * @param pendingIntent PendingIntent to fill in and send if the user chooses this target
+ * @param componentName Name of the component to be launched if this target is chosen
+ * @param intentExtras Bundle of extras to merge with the extras of the launched intent
*/
public ChooserTarget(CharSequence title, Icon icon, float score,
- PendingIntent pendingIntent) {
- this(title, icon, score, pendingIntent.getIntentSender());
- }
-
- /**
- * Construct a deep link target for presentation by a chooser UI.
- *
- * <p>A target is composed of a title and an icon for presentation to the user.
- * The UI presenting this target may truncate the title if it is too long to be presented
- * in the available space, as well as crop, resize or overlay the supplied icon.</p>
- *
- * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
- * to the other targets supplied by the same
- * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
- * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).
- * Scores for a set of targets do not need to sum to 1.</p>
- *
- * <p>Before being sent, the IntentSender supplied will be
- * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
- * to the chooser. When constructing an IntentSender for use in a ChooserTarget, make sure
- * that you permit the relevant fields to be filled in using the appropriate flags such as
- * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
- * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
- * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
- * for {@link Intent#ACTION_SEND} intents.</p>
- *
- * <p>Take care not to place custom {@link android.os.Parcelable} types into
- * the IntentSender as extras, as the system will not be able to unparcel it to merge
- * additional extras.</p>
- *
- * @param title title of this target that will be shown to a user
- * @param icon icon to represent this target
- * @param score ranking score for this target between 0.0f and 1.0f, inclusive
- * @param intentSender IntentSender to fill in and send if the user chooses this target
- */
- public ChooserTarget(CharSequence title, Icon icon, float score, IntentSender intentSender) {
+ ComponentName componentName, @Nullable Bundle intentExtras) {
mTitle = title;
mIcon = icon;
if (score > 1.f || score < 0.f) {
@@ -148,7 +109,8 @@
+ "must be between 0.0f and 1.0f");
}
mScore = score;
- mIntentSender = intentSender;
+ mComponentName = componentName;
+ mIntentExtras = intentExtras;
}
ChooserTarget(Parcel in) {
@@ -159,7 +121,8 @@
mIcon = null;
}
mScore = in.readFloat();
- mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
+ mComponentName = ComponentName.readFromParcel(in);
+ mIntentExtras = in.readBundle();
}
/**
@@ -194,49 +157,29 @@
}
/**
- * Returns the raw IntentSender supplied by the ChooserTarget's creator.
- * This may be null if the creator specified a regular Intent instead.
+ * Returns the ComponentName of the Activity that should be launched for this ChooserTarget.
*
- * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
- *
- * @return the IntentSender supplied by the ChooserTarget's creator
+ * @return the name of the target Activity to launch
*/
- public IntentSender getIntentSender() {
- return mIntentSender;
+ public ComponentName getComponentName() {
+ return mComponentName;
}
/**
- * Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
+ * Returns the Bundle of extras to be added to an intent launched to this target.
*
- * @param context the sending Context; generally the Activity presenting the chooser UI
- * @param fillInIntent the Intent provided to the Chooser to be sent to a selected target
- * @return true if sending the Intent was successful
+ * @return the extras to merge with the extras of the intent being launched
*/
- public boolean sendIntent(Context context, Intent fillInIntent) {
- if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
- fillInIntent.prepareToLeaveProcess();
- }
- if (mIntentSender != null) {
- try {
- mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
- return true;
- } catch (IntentSender.SendIntentException e) {
- Log.e(TAG, "sendIntent " + this + " failed", e);
- return false;
- }
- } else {
- Log.e(TAG, "sendIntent " + this + " failed - no IntentSender to send");
- return false;
- }
+ public Bundle getIntentExtras() {
+ return mIntentExtras;
}
@Override
public String toString() {
return "ChooserTarget{"
- + (mIntentSender != null ? mIntentSender.getCreatorPackage() : null)
- + ", "
- + "'" + mTitle
+ + mComponentName
+ + ", " + mIntentExtras
+ + ", '" + mTitle
+ "', " + mScore + "}";
}
@@ -255,7 +198,8 @@
dest.writeInt(0);
}
dest.writeFloat(mScore);
- IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
+ ComponentName.writeToParcel(mComponentName, dest);
+ dest.writeBundle(mIntentExtras);
}
public static final Creator<ChooserTarget> CREATOR
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
index a3bfece..e054185 100644
--- a/core/java/android/service/chooser/ChooserTargetService.java
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -105,9 +105,8 @@
* can handle an intent.
*
* <p>The returned list should be sorted such that the most relevant targets appear first.
- * Any PendingIntents used to construct the resulting ChooserTargets should always be prepared
- * to have the relevant data fields filled in by the sender. See
- * {@link ChooserTarget#ChooserTarget(CharSequence, android.graphics.drawable.Icon, float, android.app.PendingIntent) ChooserTarget}.</p>
+ * The score for each ChooserTarget will be combined with the system's score for the original
+ * target Activity to sort and filter targets presented to the user.</p>
*
* <p><em>Important:</em> Calls to this method from other applications will occur on
* a binder thread, not on your app's main thread. Make sure that access to relevant data
diff --git a/core/java/android/service/chooser/IChooserTargetResult.aidl b/core/java/android/service/chooser/IChooserTargetResult.aidl
index dbd7cbd..6c648a2 100644
--- a/core/java/android/service/chooser/IChooserTargetResult.aidl
+++ b/core/java/android/service/chooser/IChooserTargetResult.aidl
@@ -21,7 +21,7 @@
/**
* @hide
*/
-interface IChooserTargetResult
+oneway interface IChooserTargetResult
{
void sendResult(in List<ChooserTarget> targets);
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index c4f57c7..6af2e8b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -471,6 +471,36 @@
return false;
}
+ void filterServiceTargets(String packageName, List<ChooserTarget> targets) {
+ if (targets == null) {
+ return;
+ }
+
+ final PackageManager pm = getPackageManager();
+ for (int i = targets.size() - 1; i >= 0; i--) {
+ final ChooserTarget target = targets.get(i);
+ final ComponentName targetName = target.getComponentName();
+ if (packageName != null && packageName.equals(targetName.getPackageName())) {
+ // Anything from the original target's package is fine.
+ continue;
+ }
+
+ boolean remove;
+ try {
+ final ActivityInfo ai = pm.getActivityInfo(targetName, 0);
+ remove = !ai.exported || ai.permission != null;
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Target " + target + " returned by " + packageName
+ + " component not found");
+ remove = true;
+ }
+
+ if (remove) {
+ targets.remove(i);
+ }
+ }
+ }
+
@Override
ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
@@ -554,11 +584,11 @@
return null;
}
- private Intent getFillInIntent() {
+ private Intent getBaseIntentToSend() {
Intent result = mSourceInfo != null
? mSourceInfo.getResolvedIntent() : getTargetIntent();
if (result == null) {
- Log.e(TAG, "ChooserTargetInfo#getFillInIntent: no fillIn intent available");
+ Log.e(TAG, "ChooserTargetInfo: no base intent available to send");
} else {
result = new Intent(result);
if (mFillInIntent != null) {
@@ -571,31 +601,24 @@
@Override
public boolean start(Activity activity, Bundle options) {
- final Intent intent = getFillInIntent();
- if (intent == null) {
- return false;
- }
- return mChooserTarget.sendIntent(activity, intent);
+ throw new RuntimeException("ChooserTargets should be started as caller.");
}
@Override
public boolean startAsCaller(Activity activity, Bundle options, int userId) {
- final Intent intent = getFillInIntent();
+ final Intent intent = getBaseIntentToSend();
if (intent == null) {
return false;
}
- // ChooserTargets will launch with their IntentSender's identity
- return mChooserTarget.sendIntent(activity, intent);
+ intent.setComponent(mChooserTarget.getComponentName());
+ intent.putExtras(mChooserTarget.getIntentExtras());
+ activity.startActivityAsCaller(intent, options, true, userId);
+ return true;
}
@Override
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
- final Intent intent = getFillInIntent();
- if (intent == null) {
- return false;
- }
- // ChooserTargets will launch with their IntentSender's identity
- return mChooserTarget.sendIntent(activity, intent);
+ throw new RuntimeException("ChooserTargets should be started as caller.");
}
@Override
@@ -998,6 +1021,8 @@
private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() {
@Override
public void sendResult(List<ChooserTarget> targets) throws RemoteException {
+ filterServiceTargets(mOriginalTarget.getResolveInfo().activityInfo.packageName,
+ targets);
final Message msg = Message.obtain();
msg.what = CHOOSER_TARGET_SERVICE_RESULT;
msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 233bee3..39b66aa 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -103,7 +103,7 @@
|| ChooserActivity.class.getName().equals(ri.activityInfo.name));
try {
- startActivityAsCaller(newIntent, null, targetUserId);
+ startActivityAsCaller(newIntent, null, false, targetUserId);
} catch (RuntimeException e) {
int launchedFromUid = -1;
String launchedFromPackage = "?";
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 7bc18f3..ba19131 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -973,7 +973,7 @@
@Override
public boolean startAsCaller(Activity activity, Bundle options, int userId) {
- activity.startActivityAsCaller(mResolvedIntent, options, userId);
+ activity.startActivityAsCaller(mResolvedIntent, options, false, userId);
return true;
}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 32746c2..6393fba 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -20,6 +20,7 @@
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Base64;
import android.util.Xml;
@@ -45,6 +46,8 @@
/** {@hide} */
public class XmlUtils {
+ private static final String STRING_ARRAY_SEPARATOR = ":";
+
public static void skipCurrentTag(XmlPullParser parser)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 062ae27..0c0ba7f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2052,10 +2052,24 @@
<permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
android:protectionLevel="signature|privileged" />
- <!-- @hide Allows an application to grant or revoke specific permissions. -->
- <permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS"
+ <!-- Allows an application to grant specific permissions.
+ @hide -->
+ <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS"
android:protectionLevel="signature|installer" />
+ <!-- Allows an app that has this permission and the permissions to install packages
+ to request certain runtime permissions to be granted at installation.
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature|installer|verifier" />
+
+ <!-- Allows an application to revoke specific permissions.
+ @hide
+ @SystemApi -->
+ <permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature|installer|verifier" />
+
<!-- @hide Allows an application to observe permission changes. -->
<permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
android:protectionLevel="signature|privileged" />
@@ -2539,12 +2553,6 @@
<permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"
android:protectionLevel="signature" />
- <!-- Allows an app that has this permission and a permissions to install packages
- to request all runtime permissions to be granted at installation.
- @hide -->
- <permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
- android:protectionLevel="signature" />
-
<!-- The system process that is allowed to bind to services in carrier apps will
have this permission. Carrier apps should use this permission to protect
their services that only the system is allowed to bind to.
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index 6ee0af0..5c8ef41 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -373,7 +373,7 @@
<h2 id="behavior-afw">Android for Work Changes</h2>
<p>This preview includes the following behavior changes for Android for Work:</p>
<ul>
-<li><strong>Work contacts in personal contexts.</strong> The Google Dialer
+ <li><strong>Work contacts in personal contexts.</strong> The Google Dialer
Call Log now displays work contacts when the user views past calls.
Setting
{@link android.app.admin.DevicePolicyManager#setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean) setCrossProfileCallerIdDisabled()}
@@ -381,21 +381,19 @@
displayed along with personal contacts to devices over Bluetooth only if
you set {@code DevicePolicyManager.setBluetoothContactSharingDisabled()} to {@code false}. By
default, it is set to {@code true}.
-</li>
-<li><strong>WiFi configuration removal:</strong> WiFi configurations added by a Profile Owner
+ </li>
+ <li><strong>WiFi configuration removal:</strong> WiFi configurations added by a Profile Owner
(for example, through calls to the
{@link android.net.wifi.WifiManager#addNetwork(android.net.wifi.WifiConfiguration)
-addNetwork()} method) are now removed if that work profile is deleted.</li>
-
-<li><strong>WiFi configuration lockdown:</strong> Any WiFi configuration created by
+addNetwork()} method) are now removed if that work profile is deleted.
+ </li>
+ <li><strong>WiFi configuration lockdown:</strong> Any WiFi configuration created by
an active Device Owner can no longer be modified or deleted by the user if
<code>Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN</code> is non-zero.
The user can still create and modify their own WiFi configurations. Active Device
Owners have the privilege of editing/removing any WiFi configurations, including
those not created by them.
-</li>
-
-</li>
+ </li>
<li><strong>Download Work Policy Controller via Google account addition:</strong> When a Google
account that requires management via a Work Policy Controller (WPC) app is added to a device
outside of a managed context, the add account flow now prompts the user to install the
@@ -408,7 +406,7 @@
affect camera apps running on the primary user. </li>
<li>In addition, the
{@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures(android.content.ComponentName,int) setKeyguardDisabledFeatures()}
- method is now available for Profile Owners, in addition to Device Owners. </li>
+ method is now available for Profile Owners, as well as to Device Owners. </li>
<li>A Profile Owner can set these keyguard restrictions:
<ul>
<li>{@link android.app.admin.DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} and
@@ -422,9 +420,19 @@
<li>The {@link android.app.admin.DevicePolicyManager#setScreenCaptureDisabled(android.content.ComponentName, boolean) setScreenCaptureDisabled()} method now also blocks the assist structure when an app of the given user is in the foreground. </li>
<li><code>EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM</code> now defaults to SHA-256. SHA-1 is still supported for backwards compatibility but will be removed in future. <code>EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM</code> now only accepts SHA-256.</li>
<li>Device initializer APIs which existed in the MNC preview are now removed. They will not appear in the final M release.</li>
- <li>Android for Work APIs are optimized for M runtime permissions, including Work profiles, assist layer, and others. New DevicePolicyManager permission APIs don't affect pre-M apps.</li>
- </ul>
- <li><strong>Changes to global settings</strong> — the settings below can no longer be set via {@link android.app.admin.DevicePolicyManager#setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String) setGlobalSettings()}</code>:
+ <li><code>EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS</code> is removed so NFC bump provisioning cannot programmatically unlock a factory reset protected device.</li>
+ <li>Android for Work APIs are optimized for M runtime permissions, including Work profiles, assist layer, and others. New <code>DevicePolicyManager</code> permission APIs don't affect pre-M apps.</li>
+ </ul></li>
+
+<li><strong>Changes to other APIs</strong>:
+<ul>
+ <li>Data Usage: The {@code android.app.usage.NetworkUsageStats} class has been renamed {@code android.app.usage.NetworkStats}.</li>
+</ul>
+ </li>
+
+ <li><strong>Changes to global settings</strong>:
+ <ul>
+ <li>These settings can no longer be set via {@link android.app.admin.DevicePolicyManager#setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String) setGlobalSettings()}</code>:
<ul>
<li><code>BLUETOOTH_ON</code></li>
<li><code>DEVELOPMENT_SETTINGS_ENABLED</code></li>
@@ -433,4 +441,10 @@
<li><code>WIFI_ON</code></li>
</ul>
</li>
+ <li>These global settings can now be set via <code><a href="/reference/android/app/admin/DevicePolicyManager.html#setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String)">setGlobalSettings()</a></code>:
+ <ul>
+ <li><code>WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN</code></li>
+ </ul>
+ </li>
+ </ul>
</ul>
diff --git a/docs/html/training/tv/start/hardware.jd b/docs/html/training/tv/start/hardware.jd
index 57651e6..5747b56 100644
--- a/docs/html/training/tv/start/hardware.jd
+++ b/docs/html/training/tv/start/hardware.jd
@@ -163,7 +163,7 @@
android:required="false"/>
<uses-feature android:name="android.hardware.nfc"
android:required="false"/>
-<uses-feature android:name="android.hardware.gps"
+<uses-feature android:name="android.hardware.location.gps"
android:required="false"/>
<uses-feature android:name="android.hardware.microphone"
android:required="false"/>
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 6a7930a..fd014eb 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -197,48 +197,36 @@
}
}
}
- if (spec.isDigestsSpecified()) {
- // Digest(s) explicitly specified in the spec
- mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
- if (mKeymasterDigest != -1) {
- // Key algorithm implies a digest -- ensure it's specified in the spec as
- // first digest.
- if (!com.android.internal.util.ArrayUtils.contains(
- mKeymasterDigests, mKeymasterDigest)) {
+
+ if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+ // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
+ // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
+ // one digest, we don't let algorithm parameter spec override the digest implied
+ // by the key. If the spec specifies digests at all, it must specify only one
+ // digest, the only implied by key algorithm.
+ mKeymasterDigests = new int[] {mKeymasterDigest};
+ if (spec.isDigestsSpecified()) {
+ // Digest(s) explicitly specified in the spec. Check that the list
+ // consists of exactly one digest, the one implied by key algorithm.
+ int[] keymasterDigestsFromSpec =
+ KeyProperties.Digest.allToKeymaster(spec.getDigests());
+ if ((keymasterDigestsFromSpec.length != 1)
+ || (keymasterDigestsFromSpec[0] != mKeymasterDigest)) {
throw new InvalidAlgorithmParameterException(
- "Digests specified in algorithm parameters ("
- + Arrays.asList(spec.getDigests()) + ") must include "
- + " the digest "
+ "Unsupported digests specification: "
+ + Arrays.asList(spec.getDigests()) + ". Only "
+ KeyProperties.Digest.fromKeymaster(mKeymasterDigest)
- + " implied by key algorithm");
- }
- if (mKeymasterDigests[0] != mKeymasterDigest) {
- // The first digest is not the one implied by the key algorithm.
- // Swap the implied digest with the first one.
- for (int i = 0; i < mKeymasterDigests.length; i++) {
- if (mKeymasterDigests[i] == mKeymasterDigest) {
- mKeymasterDigests[i] = mKeymasterDigests[0];
- mKeymasterDigests[0] = mKeymasterDigest;
- break;
- }
- }
+ + " supported for this HMAC key algorithm");
}
}
} else {
- // No digest specified in the spec
- if (mKeymasterDigest != -1) {
- // Key algorithm implies a digest -- use that digest
- mKeymasterDigests = new int[] {mKeymasterDigest};
+ // Key algorithm does not imply a digest.
+ if (spec.isDigestsSpecified()) {
+ mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
} else {
mKeymasterDigests = EmptyArray.INT;
}
}
- if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- if (mKeymasterDigests.length == 0) {
- throw new InvalidAlgorithmParameterException(
- "At least one digest algorithm must be specified");
- }
- }
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index e9f19cd..88858de 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -41,6 +41,7 @@
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.ProviderException;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
@@ -605,50 +606,43 @@
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
int[] keymasterDigests;
- int keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
- if (params.isDigestsSpecified()) {
- // Digest(s) specified in parameters
- keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
- if (keymasterDigest != -1) {
- // Digest also specified in the JCA key algorithm name.
- if (!com.android.internal.util.ArrayUtils.contains(
- keymasterDigests, keymasterDigest)) {
- throw new KeyStoreException("Digest specified in key algorithm "
- + key.getAlgorithm() + " not specified in protection parameters: "
- + Arrays.asList(params.getDigests()));
- }
- // When the key is read back from keystore we reconstruct the JCA key algorithm
- // name from the KM_TAG_ALGORITHM and the first KM_TAG_DIGEST. Thus we need to
- // ensure that the digest reflected in the JCA key algorithm name is the first
- // KM_TAG_DIGEST tag.
- if (keymasterDigests[0] != keymasterDigest) {
- // The first digest is not the one implied by the JCA key algorithm name.
- // Swap the implied digest with the first one.
- for (int i = 0; i < keymasterDigests.length; i++) {
- if (keymasterDigests[i] == keymasterDigest) {
- keymasterDigests[i] = keymasterDigests[0];
- keymasterDigests[0] = keymasterDigest;
- break;
- }
- }
+ if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+ // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
+ // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
+ // digest, we don't let import parameters override the digest implied by the key.
+ // If the parameters specify digests at all, they must specify only one digest, the
+ // only implied by key algorithm.
+ int keymasterImpliedDigest =
+ KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
+ if (keymasterImpliedDigest == -1) {
+ throw new ProviderException(
+ "HMAC key algorithm digest unknown for key algorithm "
+ + key.getAlgorithm());
+ }
+ keymasterDigests = new int[] {keymasterImpliedDigest};
+ if (params.isDigestsSpecified()) {
+ // Digest(s) explicitly specified in params -- check that the list consists of
+ // exactly one digest, the one implied by key algorithm.
+ int[] keymasterDigestsFromParams =
+ KeyProperties.Digest.allToKeymaster(params.getDigests());
+ if ((keymasterDigestsFromParams.length != 1)
+ || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
+ throw new KeyStoreException(
+ "Unsupported digests specification: "
+ + Arrays.asList(params.getDigests()) + ". Only "
+ + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest)
+ + " supported for HMAC key algorithm " + key.getAlgorithm());
}
}
} else {
- // No digest specified in parameters
- if (keymasterDigest != -1) {
- // Digest specified in the JCA key algorithm name.
- keymasterDigests = new int[] {keymasterDigest};
+ // Key algorithm does not imply a digest.
+ if (params.isDigestsSpecified()) {
+ keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
} else {
keymasterDigests = EmptyArray.INT;
}
}
args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
- if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- if (keymasterDigests.length == 0) {
- throw new KeyStoreException("At least one digest algorithm must be specified"
- + " for key algorithm " + key.getAlgorithm());
- }
- }
@KeyProperties.PurposeEnum int purposes = params.getPurposes();
int[] keymasterBlockModes =
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 919dd48..faaa1a6 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -642,7 +642,8 @@
* <p>This must be specified for signing/verification keys and RSA encryption/decryption
* keys used with RSA OAEP padding scheme because these operations involve a digest. For
* HMAC keys, the default is the digest associated with the key algorithm (e.g.,
- * {@code SHA-256} for key algorithm {@code HmacSHA256}).
+ * {@code SHA-256} for key algorithm {@code HmacSHA256}). HMAC keys cannot be authorized
+ * for more than one digest.
*
* <p>For private keys used for TLS/SSL client or server authentication it is usually
* necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 5b4b3e7..ec0ef24 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -423,7 +423,8 @@
* <p>This must be specified for signing/verification keys and RSA encryption/decryption
* keys used with RSA OAEP padding scheme because these operations involve a digest. For
* HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()} (e.g.,
- * {@code SHA-256} for key algorithm {@code HmacSHA256}).
+ * {@code SHA-256} for key algorithm {@code HmacSHA256}). HMAC keys cannot be authorized
+ * for more than one digest.
*
* <p>For private keys used for TLS/SSL client or server authentication it is usually
* necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index eb520b4..b1a6844 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -263,10 +263,11 @@
bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
- // TODO: we should be able to handle kReplace_Op efficiently without
- // going through RegionMode and later falling back into RectangleMode.
-
- if (op != SkRegion::kIntersect_Op) {
+ if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
+ mClipRect = r;
+ transform->mapRect(mClipRect);
+ return true;
+ } else if (op != SkRegion::kIntersect_Op) {
enterRegionMode();
return regionModeClipRectWithTransform(r, transform, op);
}
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index e284af0..51ef27b 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -153,6 +153,8 @@
}
void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
+ // TODO: this should not mask every path to the viewport - this makes it impossible to use
+ // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op)
pathAsRegion.setPath(path, createViewportRegion());
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 260fb6f..09f93b8 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -145,7 +145,11 @@
void CanvasContext::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
// In the meantime this matches the behavior of GLRenderer, so it is not a regression
- mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface);
+ EGLint error = 0;
+ mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface, &error);
+ if (error) {
+ setSurface(nullptr);
+ }
}
void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index cb34e00..eb332d5 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -217,7 +217,7 @@
mCurrentSurface = EGL_NO_SURFACE;
}
-bool EglManager::makeCurrent(EGLSurface surface) {
+bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
if (isCurrent(surface)) return false;
if (surface == EGL_NO_SURFACE) {
@@ -225,8 +225,14 @@
surface = mPBufferSurface;
}
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
- LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
- (void*)surface, egl_error_str());
+ if (errOut) {
+ *errOut = eglGetError();
+ ALOGW("Failed to make current on surface %p, error=%s",
+ (void*)surface, egl_error_str(*errOut));
+ } else {
+ LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
+ (void*)surface, egl_error_str());
+ }
}
mCurrentSurface = surface;
return true;
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 8881de6..0a8cfd3 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -44,7 +44,7 @@
bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
// Returns true if the current surface changed, false if it was already current
- bool makeCurrent(EGLSurface surface);
+ bool makeCurrent(EGLSurface surface, EGLint* errOut = nullptr);
void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
bool swapBuffers(EGLSurface surface, const SkRect& dirty, EGLint width, EGLint height);
diff --git a/libs/hwui/unit_tests/ClipAreaTests.cpp b/libs/hwui/unit_tests/ClipAreaTests.cpp
index 166d5b6..0c5e5e7 100644
--- a/libs/hwui/unit_tests/ClipAreaTests.cpp
+++ b/libs/hwui/unit_tests/ClipAreaTests.cpp
@@ -112,5 +112,16 @@
regionBounds.set(skRect);
EXPECT_EQ(expected, regionBounds);
}
+
+TEST(ClipArea, replaceNegative) {
+ ClipArea area(createClipArea());
+ area.setClip(0, 0, 100, 100);
+
+ Matrix4 transform;
+ transform.loadIdentity();
+ Rect expected(-50, -50, 50, 50);
+ area.clipRectWithTransform(expected, &transform, SkRegion::kReplace_Op);
+ EXPECT_EQ(expected, area.getClipRect());
+}
}
}
diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java
index b07931d..b37e02c 100644
--- a/media/java/android/media/MediaSync.java
+++ b/media/java/android/media/MediaSync.java
@@ -24,6 +24,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.util.Log;
import android.view.Surface;
import java.lang.annotation.Retention;
@@ -82,7 +83,7 @@
* codec.releaseOutputBuffer(bufferId, 1000 * info.presentationTime);
* } else {
* ByteBuffer audioByteBuffer = codec.getOutputBuffer(bufferId);
- * sync.queueByteBuffer(audioByteBuffer, bufferId, info.size, info.presentationTime);
+ * sync.queueAudio(audioByteBuffer, bufferId, info.presentationTime);
* }
* // ...
* }
@@ -427,6 +428,11 @@
/**
* Flushes all buffers from the sync object.
* <p>
+ * All pending unprocessed audio and video buffers are discarded. If an audio track was
+ * configured, it is flushed and stopped. If a video output surface was configured, the
+ * last frame queued to it is left on the frame. Queue a blank video frame to clear the
+ * surface,
+ * <p>
* No callbacks are received for the flushed buffers.
*
* @throws IllegalStateException if the internal player engine has not been
@@ -437,10 +443,19 @@
mAudioBuffers.clear();
mCallbackHandler.removeCallbacksAndMessages(null);
}
- // TODO implement this for surface buffers.
+ if (mAudioTrack != null) {
+ mAudioTrack.pause();
+ mAudioTrack.flush();
+ // Call stop() to signal to the AudioSink to completely fill the
+ // internal buffer before resuming playback.
+ mAudioTrack.stop();
+ }
+ native_flush();
}
- /**
+ private native final void native_flush();
+
+ /**
* Get current playback position.
* <p>
* The MediaTimestamp represents how the media time correlates to the system time in
@@ -478,6 +493,7 @@
/**
* Queues the audio data asynchronously for playback (AudioTrack must be in streaming mode).
+ * If the audio track was flushed as a result of {@link #flush}, it will be restarted.
* @param audioData the buffer that holds the data to play. This buffer will be returned
* to the client via registered callback.
* @param bufferId an integer used to identify audioData. It will be returned to
@@ -519,6 +535,14 @@
AudioBuffer audioBuffer = mAudioBuffers.get(0);
int size = audioBuffer.mByteBuffer.remaining();
+ // restart audio track after flush
+ if (size > 0 && mAudioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
+ try {
+ mAudioTrack.play();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "could not start audio track");
+ }
+ }
int sizeWritten = mAudioTrack.write(
audioBuffer.mByteBuffer,
size,
@@ -558,17 +582,19 @@
final MediaSync sync = this;
mCallbackHandler.post(new Runnable() {
public void run() {
+ Callback callback;
synchronized(mCallbackLock) {
+ callback = mCallback;
if (mCallbackHandler == null
|| mCallbackHandler.getLooper().getThread()
!= Thread.currentThread()) {
// callback handler has been changed.
return;
}
- if (mCallback != null) {
- mCallback.onAudioBufferConsumed(sync, audioBuffer.mByteBuffer,
- audioBuffer.mBufferIndex);
- }
+ }
+ if (callback != null) {
+ callback.onAudioBufferConsumed(sync, audioBuffer.mByteBuffer,
+ audioBuffer.mBufferIndex);
}
}
});
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index ce72c2f..a3d748e 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -49,6 +49,7 @@
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -611,7 +612,7 @@
String format = DELIMITER_INFO_IN_ID + PREFIX_HDMI_DEVICE
+ "%0" + LENGTH_HDMI_PHYSICAL_ADDRESS + "X"
+ "%0" + LENGTH_HDMI_DEVICE_ID + "X";
- return name.flattenToShortString() + String.format(format,
+ return name.flattenToShortString() + String.format(Locale.ENGLISH, format,
deviceInfo.getPhysicalAddress(), deviceInfo.getId());
}
diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
index 8e0ed64..893c414 100644
--- a/media/jni/android_media_MediaSync.cpp
+++ b/media/jni/android_media_MediaSync.cpp
@@ -102,6 +102,10 @@
return mSync->getVideoFrameRate();
}
+void JMediaSync::flush() {
+ mSync->flush();
+}
+
status_t JMediaSync::updateQueuedAudioData(
int sizeInBytes, int64_t presentationTimeUs) {
return mSync->updateQueuedAudioData(sizeInBytes, presentationTimeUs);
@@ -464,6 +468,16 @@
return scs.asJobject(env, gSyncParamsFields);
}
+static void android_media_MediaSync_native_flush(JNIEnv *env, jobject thiz) {
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ sync->flush();
+}
+
static void android_media_MediaSync_native_init(JNIEnv *env) {
ScopedLocalRef<jclass> clazz(env, env->FindClass("android/media/MediaSync"));
CHECK(clazz.get() != NULL);
@@ -524,6 +538,8 @@
"()J",
(void *)android_media_MediaSync_native_getPlayTimeForPendingAudioFrames },
+ { "native_flush", "()V", (void *)android_media_MediaSync_native_flush },
+
{ "native_init", "()V", (void *)android_media_MediaSync_native_init },
{ "native_setup", "()V", (void *)android_media_MediaSync_native_setup },
diff --git a/media/jni/android_media_MediaSync.h b/media/jni/android_media_MediaSync.h
index 22c77c76..6f80885 100644
--- a/media/jni/android_media_MediaSync.h
+++ b/media/jni/android_media_MediaSync.h
@@ -49,6 +49,8 @@
status_t setVideoFrameRateHint(float rate);
float getVideoFrameRate();
+ void flush();
+
sp<const MediaClock> getMediaClock();
protected:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 23bd238..85da298 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -308,7 +308,8 @@
boolean showNextSecurityScreenOrFinish(boolean authenticated) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
boolean finish = false;
- if (mUpdateMonitor.getUserHasTrust(KeyguardUpdateMonitor.getCurrentUser())) {
+ if (mUpdateMonitor.getUserCanSkipBouncer(
+ KeyguardUpdateMonitor.getCurrentUser())) {
finish = true;
} else if (SecurityMode.None == mCurrentSecuritySelection) {
SecurityMode securityMode = mSecurityModel.getSecurityMode();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6574e4e..9e5644e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -455,9 +455,12 @@
& DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0;
}
+ public boolean getUserCanSkipBouncer(int userId) {
+ return getUserHasTrust(userId) || mUserFingerprintAuthenticated.get(userId);
+ }
+
public boolean getUserHasTrust(int userId) {
- return !isTrustDisabled(userId) && mUserHasTrust.get(userId)
- || mUserFingerprintAuthenticated.get(userId);
+ return !isTrustDisabled(userId) && mUserHasTrust.get(userId);
}
public boolean getUserTrustIsManaged(int userId) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 9832b45..c00fdf3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -76,7 +76,9 @@
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
<uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
<uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
- <uses-permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS" />
+ <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
+ <uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
+ <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
<uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
<uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 5d46712..887391c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -136,7 +136,7 @@
mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
DozeLog.PULSE_REASON_SENSOR_PICKUP);
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(true);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mDisplayStateSupported = mDozeParameters.getDisplayStateSupported();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 937615a..61695b2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -92,7 +92,8 @@
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
- state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing() && !mKeyguard.isTrusted());
+ state.visible = !mKeyguard.isSecure() || !mKeyguard.isShowing()
+ || mKeyguard.canSkipBouncer();
state.label = mContext.getString(R.string.quick_settings_cast_title);
state.value = false;
state.autoMirrorDrawable = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 815e123..91adc460 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -18,7 +18,6 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
-import android.app.Application;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -30,8 +29,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
@@ -255,10 +252,10 @@
private Intent getCameraIntent() {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
- boolean currentUserHasTrust = updateMonitor.getUserHasTrust(
+ boolean canSkipBouncer = updateMonitor.getUserCanSkipBouncer(
KeyguardUpdateMonitor.getCurrentUser());
boolean secure = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
- return (secure && !currentUserHasTrust) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
+ return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
}
private void updateCameraVisibility() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 6bcb766..9e2ce15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -214,7 +214,7 @@
} else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
return R.drawable.lockscreen_fingerprint_error_state_to_fp_animation;
} else if (oldState == STATE_FINGERPRINT && newState == STATE_LOCK_OPEN
- && !mUnlockMethodCache.isCurrentlyInsecure()) {
+ && !mUnlockMethodCache.isTrusted()) {
return R.drawable.lockscreen_fingerprint_draw_off_animation;
} else if (newState == STATE_FINGERPRINT && !oldScreenOn && screenOn) {
return R.drawable.lockscreen_fingerprint_draw_on_animation;
@@ -226,7 +226,7 @@
private int getState() {
boolean fingerprintRunning =
KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
- if (mUnlockMethodCache.isCurrentlyInsecure()) {
+ if (mUnlockMethodCache.canSkipBouncer()) {
return STATE_LOCK_OPEN;
} else if (mTransientFpError) {
return STATE_FINGERPRINT_ERROR;
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 094b9b5..10191ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -773,14 +773,7 @@
&& mQsExpansionEnabled) {
mTwoFingerQsExpandPossible = true;
}
- final int pointerCount = event.getPointerCount();
- final boolean twoFingerDrag = action == MotionEvent.ACTION_POINTER_DOWN
- && pointerCount == 2;
- final boolean stylusClickDrag = action == MotionEvent.ACTION_DOWN
- && pointerCount == 1 && event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
- && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
- || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
- if (mTwoFingerQsExpandPossible && (twoFingerDrag || stylusClickDrag)
+ if (mTwoFingerQsExpandPossible && isOpenQsEvent(event)
&& event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1);
mQsExpandImmediate = true;
@@ -799,6 +792,24 @@
|| y <= mQsContainer.getY() + mQsContainer.getHeight());
}
+ private boolean isOpenQsEvent(MotionEvent event) {
+ final int pointerCount = event.getPointerCount();
+ final int action = event.getActionMasked();
+
+ final boolean twoFingerDrag = action == MotionEvent.ACTION_POINTER_DOWN
+ && pointerCount == 2;
+
+ final boolean stylusButtonClickDrag = action == MotionEvent.ACTION_DOWN
+ && (event.isButtonPressed(MotionEvent.BUTTON_STYLUS_PRIMARY)
+ || event.isButtonPressed(MotionEvent.BUTTON_STYLUS_SECONDARY));
+
+ final boolean mouseButtonClickDrag = action == MotionEvent.ACTION_DOWN
+ && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)
+ || event.isButtonPressed(MotionEvent.BUTTON_TERTIARY));
+
+ return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag;
+ }
+
private void handleQsDown(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN
&& shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
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 f3fc112..f0927a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2001,7 +2001,7 @@
}
public boolean isKeyguardCurrentlySecure() {
- return !mUnlockMethodCache.isCurrentlyInsecure();
+ return !mUnlockMethodCache.canSkipBouncer();
}
public void setPanelExpanded(boolean isExpanded) {
@@ -3049,20 +3049,20 @@
boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();
boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();
boolean isSecure = mUnlockMethodCache.isMethodSecure();
- boolean isCurrentlyInsecure = mUnlockMethodCache.isCurrentlyInsecure();
+ boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();
int stateFingerprint = getLoggingFingerprint(mState,
isShowing,
isOccluded,
isBouncerShowing,
isSecure,
- isCurrentlyInsecure);
+ canSkipBouncer);
if (stateFingerprint != mLastLoggedStateFingerprint) {
EventLogTags.writeSysuiStatusBarState(mState,
isShowing ? 1 : 0,
isOccluded ? 1 : 0,
isBouncerShowing ? 1 : 0,
isSecure ? 1 : 0,
- isCurrentlyInsecure ? 1 : 0);
+ canSkipBouncer ? 1 : 0);
mLastLoggedStateFingerprint = stateFingerprint;
}
}
@@ -3666,7 +3666,7 @@
public void onTrackingStopped(boolean expand) {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- if (!expand && !mUnlockMethodCache.isCurrentlyInsecure()) {
+ if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
showBouncer();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index bacf890..6816399 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -105,7 +105,7 @@
public void onTrackingStarted() {
mExpanding = true;
- mDarkenWhileDragging = !mUnlockMethodCache.isCurrentlyInsecure();
+ mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
}
public void onExpandingFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 66d71f6..6fc15a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -39,9 +39,10 @@
/** Whether the user configured a secure unlock method (PIN, password, etc.) */
private boolean mSecure;
/** Whether the unlock method is currently insecure (insecure method or trusted environment) */
- private boolean mCurrentlyInsecure;
+ private boolean mCanSkipBouncer;
private boolean mTrustManaged;
private boolean mFaceUnlockRunning;
+ private boolean mTrusted;
private UnlockMethodCache(Context ctx) {
mLockPatternUtils = new LockPatternUtils(ctx);
@@ -64,11 +65,15 @@
return mSecure;
}
+ public boolean isTrusted() {
+ return mTrusted;
+ }
+
/**
- * @return whether the lockscreen is currently insecure, i. e. the bouncer won't be shown
+ * @return whether the lockscreen is currently insecure, and the bouncer won't be shown
*/
- public boolean isCurrentlyInsecure() {
- return mCurrentlyInsecure;
+ public boolean canSkipBouncer() {
+ return mCanSkipBouncer;
}
public void addListener(OnUnlockMethodChangedListener listener) {
@@ -82,15 +87,17 @@
private void update(boolean updateAlways) {
int user = KeyguardUpdateMonitor.getCurrentUser();
boolean secure = mLockPatternUtils.isSecure(user);
- boolean currentlyInsecure = !secure || mKeyguardUpdateMonitor.getUserHasTrust(user);
+ boolean canSkipBouncer = !secure || mKeyguardUpdateMonitor.getUserCanSkipBouncer(user);
boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
+ boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
boolean faceUnlockRunning = mKeyguardUpdateMonitor.isFaceUnlockRunning(user)
&& trustManaged;
- boolean changed = secure != mSecure || currentlyInsecure != mCurrentlyInsecure ||
+ boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer ||
trustManaged != mTrustManaged || faceUnlockRunning != mFaceUnlockRunning;
if (changed || updateAlways) {
mSecure = secure;
- mCurrentlyInsecure = currentlyInsecure;
+ mCanSkipBouncer = canSkipBouncer;
+ mTrusted = trusted;
mTrustManaged = trustManaged;
mFaceUnlockRunning = faceUnlockRunning;
notifyListeners();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 04c626b..61986ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -232,7 +232,13 @@
} else if (hhmm != null && hhmm.length() == 4) {
int hh = Integer.parseInt(hhmm.substring(0, 2));
int mm = Integer.parseInt(hhmm.substring(2));
- mCalendar.set(Calendar.HOUR, hh);
+ boolean is24 = DateFormat.is24HourFormat(
+ getContext(), ActivityManager.getCurrentUser());
+ if (is24) {
+ mCalendar.set(Calendar.HOUR_OF_DAY, hh);
+ } else {
+ mCalendar.set(Calendar.HOUR, hh);
+ }
mCalendar.set(Calendar.MINUTE, mm);
}
setText(getSmallTime());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index d4eb553..d907b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -36,7 +36,7 @@
private int mCurrentUser;
private boolean mShowing;
private boolean mSecure;
- private boolean mTrusted;
+ private boolean mCanSkipBouncer;
private boolean mListening;
@@ -47,7 +47,7 @@
@Override
public void onUserSwitched(int newUserId) {
mCurrentUser = newUserId;
- updateTrustedState();
+ updateCanSkipBouncerState();
}
};
}
@@ -57,7 +57,7 @@
if (mCallbacks.size() != 0 && !mListening) {
mListening = true;
mCurrentUser = ActivityManager.getCurrentUser();
- updateTrustedState();
+ updateCanSkipBouncerState();
mKeyguardUpdateMonitor.registerCallback(this);
mUserTracker.startTracking();
}
@@ -79,8 +79,8 @@
return mSecure;
}
- public boolean isTrusted() {
- return mTrusted;
+ public boolean canSkipBouncer() {
+ return mCanSkipBouncer;
}
public void notifyKeyguardState(boolean showing, boolean secure) {
@@ -92,12 +92,12 @@
@Override
public void onTrustChanged(int userId) {
- updateTrustedState();
+ updateCanSkipBouncerState();
notifyKeyguardChanged();
}
- private void updateTrustedState() {
- mTrusted = mKeyguardUpdateMonitor.getUserHasTrust(mCurrentUser);
+ private void updateCanSkipBouncerState() {
+ mCanSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(mCurrentUser);
}
private void notifyKeyguardChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 41fc967..6fabe9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -412,7 +412,7 @@
public int getCount() {
boolean secureKeyguardShowing = mController.mKeyguardMonitor.isShowing()
&& mController.mKeyguardMonitor.isSecure()
- && !mController.mKeyguardMonitor.isTrusted();
+ && !mController.mKeyguardMonitor.canSkipBouncer();
if (!secureKeyguardShowing) {
return mController.mUsers.size();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1582037..3bf6fde 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,10 +18,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -3516,8 +3513,8 @@
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo,
- null, null, null, null, 0, 0, 0, null, 0, 0, 0, null, false, null, null,
- null);
+ null, null, null, null, 0, 0, 0, null, 0, 0, 0, null, false, false,
+ null, null, null);
}
}
}
@@ -3803,13 +3800,14 @@
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- profilerInfo, null, null, options, userId, null, null);
+ profilerInfo, null, null, options, false, userId, null, null);
}
@Override
public final int startActivityAsCaller(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
- int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
+ int startFlags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity,
+ int userId) {
// This is very dangerous -- it allows you to perform a start activity (including
// permission grants) as any app that may launch one of your own activities. So
@@ -3843,6 +3841,16 @@
+ sourceRecord.launchedFromUid);
}
}
+ if (ignoreTargetSecurity) {
+ if (intent.getComponent() == null) {
+ throw new SecurityException(
+ "Component must be specified with ignoreTargetSecurity");
+ }
+ if (intent.getSelector() != null) {
+ throw new SecurityException(
+ "Selector not allowed with ignoreTargetSecurity");
+ }
+ }
targetUid = sourceRecord.launchedFromUid;
targetPackage = sourceRecord.launchedFromPackage;
}
@@ -3855,7 +3863,7 @@
try {
int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
- null, null, options, userId, null, null);
+ null, null, options, ignoreTargetSecurity, userId, null, null);
return ret;
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
@@ -3884,7 +3892,7 @@
// TODO: Switch to user app stacks here.
mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
- options, userId, null, null);
+ options, false, userId, null, null);
return res;
}
@@ -3898,7 +3906,7 @@
// TODO: Switch to user app stacks here.
int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, config, options, userId, null, null);
+ null, null, config, options, false, userId, null, null);
return ret;
}
@@ -3956,7 +3964,7 @@
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent,
resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
- null, options, userId, null, null);
+ null, options, false, userId, null, null);
}
@Override
@@ -4067,7 +4075,7 @@
int res = mStackSupervisor.startActivityLocked(r.app.thread, intent,
r.resolvedType, aInfo, null, null, resultTo != null ? resultTo.appToken : null,
resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage,
- -1, r.launchedFromUid, 0, options, false, null, null, null);
+ -1, r.launchedFromUid, 0, options, false, false, null, null, null);
Binder.restoreCallingIdentity(origId);
r.finishing = wasFinishing;
@@ -4125,7 +4133,7 @@
// TODO: Switch to user app stacks here.
int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, null, options, userId, container, inTask);
+ null, null, null, options, false, userId, container, inTask);
return ret;
}
@@ -20529,7 +20537,7 @@
}
return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent,
resolvedType, null, null, null, null, 0, 0, null, null,
- null, options, callingUser, null, tr);
+ null, options, false, callingUser, null, tr);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 470bbb0e..e57e3ff 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3117,7 +3117,7 @@
int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent,
null, aInfo, null, null, parent.appToken, null,
0, -1, parent.launchedFromUid, parent.launchedFromPackage,
- -1, parent.launchedFromUid, 0, null, true, null, null, null);
+ -1, parent.launchedFromUid, 0, null, false, true, null, null, null);
foundParentInTask = res == ActivityManager.START_SUCCESS;
} catch (RemoteException e) {
foundParentInTask = false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c12aff6..05c58d7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -911,7 +911,8 @@
null /* voiceSession */, null /* voiceInteractor */, null /* resultTo */,
null /* resultWho */, 0 /* requestCode */, 0 /* callingPid */, 0 /* callingUid */,
null /* callingPackage */, 0 /* realCallingPid */, 0 /* realCallingUid */,
- 0 /* startFlags */, null /* options */, false /* componentSpecified */,
+ 0 /* startFlags */, null /* options */, false /* ignoreTargetSecurity */,
+ false /* componentSpecified */,
null /* outActivity */, null /* container */, null /* inTask */);
if (inResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
@@ -926,7 +927,8 @@
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
- Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {
+ Bundle options, boolean ignoreTargetSecurity, int userId,
+ IActivityContainer iContainer, TaskRecord inTask) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -1043,7 +1045,7 @@
int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
- realCallingPid, realCallingUid, startFlags, options,
+ realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
componentSpecified, null, container, inTask);
Binder.restoreCallingIdentity(origId);
@@ -1159,7 +1161,7 @@
int res = startActivityLocked(caller, intent, resolvedTypes[i],
aInfo, null, null, resultTo, null, -1, callingPid, callingUid,
callingPackage, callingPid, callingUid,
- 0, theseOptions, componentSpecified, outActivity, null, null);
+ 0, theseOptions, false, componentSpecified, outActivity, null, null);
if (res < 0) {
return res;
}
@@ -1400,8 +1402,8 @@
IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage,
int realCallingPid, int realCallingUid, int startFlags, Bundle options,
- boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,
- TaskRecord inTask) {
+ boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
+ ActivityContainer container, TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS;
ProcessRecord callerApp = null;
@@ -1546,7 +1548,7 @@
if (startAnyPerm != PERMISSION_GRANTED) {
final int componentRestriction = getComponentRestrictionForCallingPackage(
- aInfo, callingPackage, callingPid, callingUid);
+ aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
final int actionRestriction = getActionRestrictionForCallingPackage(
intent.getAction(), callingPackage, callingPid, callingUid);
@@ -1675,13 +1677,13 @@
}
private int getComponentRestrictionForCallingPackage(ActivityInfo activityInfo,
- String callingPackage, int callingPid, int callingUid) {
+ String callingPackage, int callingPid, int callingUid, boolean ignoreTargetSecurity) {
if (activityInfo.permission == null) {
return ACTIVITY_RESTRICTION_NONE;
}
- if (mService.checkComponentPermission(activityInfo.permission, callingPid, callingUid,
- activityInfo.applicationInfo.uid, activityInfo.exported)
+ if (!ignoreTargetSecurity && mService.checkComponentPermission(activityInfo.permission,
+ callingPid, callingUid, activityInfo.applicationInfo.uid, activityInfo.exported)
== PackageManager.PERMISSION_DENIED) {
return ACTIVITY_RESTRICTION_PERMISSION;
}
@@ -1693,7 +1695,9 @@
if (mService.mAppOpsService.noteOperation(opCode, callingUid,
callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return ACTIVITY_RESTRICTION_APPOP;
+ if (!ignoreTargetSecurity) {
+ return ACTIVITY_RESTRICTION_APPOP;
+ }
}
return ACTIVITY_RESTRICTION_NONE;
@@ -4296,7 +4300,7 @@
intent.addFlags(FORCE_NEW_TASK_FLAGS);
return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null,
- 0, 0, null, null, null, null, userId, this, null);
+ 0, 0, null, null, null, null, false, userId, this, null);
}
@Override
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 91d97ef..a956c56 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -321,14 +321,12 @@
}
public void skipCurrentReceiverLocked(ProcessRecord app) {
- BroadcastRecord r = app.curReceiver;
- if (r != null && r.queue == this) {
- // The current broadcast is waiting for this app's receiver
- // to be finished. Looks like that's not going to happen, so
- // let the broadcast continue.
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, false);
+ BroadcastRecord r = null;
+ if (mOrderedBroadcasts.size() > 0) {
+ BroadcastRecord br = mOrderedBroadcasts.get(0);
+ if (br.curApp == app) {
+ r = br;
+ }
}
if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 7fde68f..b76db41 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -72,6 +72,7 @@
static {
CONTACTS_PERMISSIONS.add(Manifest.permission.READ_CONTACTS);
CONTACTS_PERMISSIONS.add(Manifest.permission.WRITE_CONTACTS);
+ CONTACTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
}
private static final Set<String> LOCATION_PERMISSIONS = new ArraySet<>();
@@ -117,11 +118,6 @@
STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
- private static final Set<String> ACCOUNTS_PERMISSIONS = new ArraySet<>();
- static {
- ACCOUNTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS);
- }
-
private final PackageManagerService mService;
private PackagesProvider mImePackagesProvider;
@@ -352,7 +348,6 @@
&& doesPackageSupportRuntimePermissions(calendarPackage)) {
grantRuntimePermissionsLPw(calendarPackage, CALENDAR_PERMISSIONS, userId);
grantRuntimePermissionsLPw(calendarPackage, CONTACTS_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(calendarPackage, ACCOUNTS_PERMISSIONS, userId);
}
// Calendar provider
@@ -362,7 +357,6 @@
grantRuntimePermissionsLPw(calendarProviderPackage, CONTACTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(calendarProviderPackage, CALENDAR_PERMISSIONS,
true, userId);
- grantRuntimePermissionsLPw(calendarProviderPackage, ACCOUNTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(calendarProviderPackage, STORAGE_PERMISSIONS, userId);
}
@@ -386,7 +380,6 @@
&& doesPackageSupportRuntimePermissions(contactsPackage)) {
grantRuntimePermissionsLPw(contactsPackage, CONTACTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(contactsPackage, PHONE_PERMISSIONS, userId);
- grantRuntimePermissionsLPw(contactsPackage, ACCOUNTS_PERMISSIONS, userId);
}
// Contacts provider sync adapters
@@ -408,7 +401,6 @@
true, userId);
grantRuntimePermissionsLPw(contactsProviderPackage, PHONE_PERMISSIONS,
true, userId);
- grantRuntimePermissionsLPw(contactsProviderPackage, ACCOUNTS_PERMISSIONS, userId);
grantRuntimePermissionsLPw(contactsProviderPackage, STORAGE_PERMISSIONS, userId);
}
@@ -419,7 +411,7 @@
getDefaultSystemHandlerActivityPackageLPr(deviceProvisionIntent, userId);
if (deviceProvisionPackage != null
&& doesPackageSupportRuntimePermissions(deviceProvisionPackage)) {
- grantRuntimePermissionsLPw(deviceProvisionPackage, ACCOUNTS_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId);
}
// Maps
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2abd924..07de6f5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -43,7 +43,6 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
-import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
@@ -71,7 +70,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
-import android.os.storage.VolumeInfo;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -123,6 +121,7 @@
/** XML constants used in {@link #mSessionsFile} */
private static final String TAG_SESSIONS = "sessions";
private static final String TAG_SESSION = "session";
+ private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
private static final String ATTR_SESSION_ID = "sessionId";
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
@@ -144,6 +143,7 @@
private static final String ATTR_REFERRER_URI = "referrerUri";
private static final String ATTR_ABI_OVERRIDE = "abiOverride";
private static final String ATTR_VOLUME_UUID = "volumeUuid";
+ private static final String ATTR_NAME = "name";
/** Automatically destroy sessions older than this */
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
@@ -374,16 +374,15 @@
}
} catch (FileNotFoundException e) {
// Missing sessions are okay, probably first boot
- } catch (IOException e) {
- Slog.wtf(TAG, "Failed reading install sessions", e);
- } catch (XmlPullParserException e) {
+ } catch (IOException | XmlPullParserException e) {
Slog.wtf(TAG, "Failed reading install sessions", e);
} finally {
IoUtils.closeQuietly(fis);
}
}
- private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException {
+ private PackageInstallerSession readSessionLocked(XmlPullParser in) throws IOException,
+ XmlPullParserException {
final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
final int userId = readIntAttribute(in, ATTR_USER_ID);
final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
@@ -409,6 +408,7 @@
params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
+ params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
final File appIconFile = buildAppIconFile(sessionId);
if (appIconFile.exists()) {
@@ -501,9 +501,51 @@
params.appIconLastModified = appIconFile.lastModified();
}
+ writeGrantedRuntimePermissions(out, params.grantedRuntimePermissions);
+
out.endTag(null, TAG_SESSION);
}
+ private static void writeGrantedRuntimePermissions(XmlSerializer out,
+ String[] grantedRuntimePermissions) throws IOException {
+ if (grantedRuntimePermissions != null) {
+ for (String permission : grantedRuntimePermissions) {
+ out.startTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
+ writeStringAttribute(out, ATTR_NAME, permission);
+ out.endTag(null, TAG_GRANTED_RUNTIME_PERMISSION);
+ }
+ }
+ }
+
+ private static String[] readGrantedRuntimePermissions(XmlPullParser in)
+ throws IOException, XmlPullParserException {
+ List<String> permissions = null;
+
+ final int outerDepth = in.getDepth();
+ int type;
+ while ((type = in.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || in.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (TAG_GRANTED_RUNTIME_PERMISSION.equals(in.getName())) {
+ String permission = readStringAttribute(in, ATTR_NAME);
+ if (permissions == null) {
+ permissions = new ArrayList<>();
+ }
+ permissions.add(permission);
+ }
+ }
+
+ if (permissions == null) {
+ return null;
+ }
+
+ String[] permissionsArray = new String[permissions.size()];
+ permissions.toArray(permissionsArray);
+ return permissionsArray;
+ }
+
private File buildAppIconFile(int sessionId) {
return new File(mSessionsDir, "app_icon." + sessionId + ".png");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2a08c34..d3f7795 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16,7 +16,6 @@
package com.android.server.pm;
-import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
@@ -1339,8 +1338,8 @@
// permissions if requested before broadcasting the install.
if ((args.installFlags
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0) {
- grantRequestedRuntimePermissions(res.pkg,
- args.user.getIdentifier());
+ grantRequestedRuntimePermissions(res.pkg, args.user.getIdentifier(),
+ args.installGrantPermissions);
}
// Determine the set of users who are adding this
@@ -1669,12 +1668,17 @@
}
};
- private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId) {
+ private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId,
+ String[] grantedPermissions) {
if (userId >= UserHandle.USER_OWNER) {
- grantRequestedRuntimePermissionsForUser(pkg, userId);
+ grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
} else if (userId == UserHandle.USER_ALL) {
- for (int someUserId : UserManagerService.getInstance().getUserIds()) {
- grantRequestedRuntimePermissionsForUser(pkg, someUserId);
+ final int[] userIds;
+ synchronized (mPackages) {
+ userIds = UserManagerService.getInstance().getUserIds();
+ }
+ for (int someUserId : userIds) {
+ grantRequestedRuntimePermissionsForUser(pkg, someUserId, grantedPermissions);
}
}
@@ -1684,7 +1688,8 @@
}
}
- private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId) {
+ private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
+ String[] grantedPermissions) {
SettingBase sb = (SettingBase) pkg.mExtras;
if (sb == null) {
return;
@@ -1694,7 +1699,8 @@
for (String permission : pkg.requestedPermissions) {
BasePermission bp = mSettings.mPermissions.get(permission);
- if (bp != null && bp.isRuntime()) {
+ if (bp != null && bp.isRuntime() && (grantedPermissions == null
+ || ArrayUtils.contains(grantedPermissions, permission))) {
permissionsState.grantRuntimePermission(bp, userId);
}
}
@@ -3382,7 +3388,7 @@
}
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
"grantRuntimePermission");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
@@ -3466,7 +3472,7 @@
}
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
"revokeRuntimePermission");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
@@ -3517,7 +3523,7 @@
@Override
public void resetRuntimePermissions() {
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
"revokeRuntimePermission");
int callingUid = Binder.getCallingUid();
@@ -3527,16 +3533,19 @@
"resetRuntimePermissions");
}
- final int[] userIds;
-
synchronized (mPackages) {
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL);
- final int userCount = UserManagerService.getInstance().getUserIds().length;
- userIds = Arrays.copyOf(UserManagerService.getInstance().getUserIds(), userCount);
- }
-
- for (int userId : userIds) {
- mDefaultPermissionPolicy.grantDefaultPermissions(userId);
+ for (int userId : UserManagerService.getInstance().getUserIds()) {
+ final int packageCount = mPackages.size();
+ for (int i = 0; i < packageCount; i++) {
+ PackageParser.Package pkg = mPackages.valueAt(i);
+ if (!(pkg.mExtras instanceof PackageSetting)) {
+ continue;
+ }
+ PackageSetting ps = (PackageSetting) pkg.mExtras;
+ resetUserChangesToRuntimePermissionsAndFlagsLocked(ps, userId);
+ }
+ }
}
}
@@ -3546,9 +3555,7 @@
return 0;
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
- "getPermissionFlags");
+ enforceGrantRevokeRuntimePermissionPermissions("getPermissionFlags");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
"getPermissionFlags");
@@ -3581,9 +3588,7 @@
return;
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
- "updatePermissionFlags");
+ enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
"updatePermissionFlags");
@@ -3643,9 +3648,7 @@
return;
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
- "updatePermissionFlagsForAllApps");
+ enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlagsForAllApps");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
"updatePermissionFlagsForAllApps");
@@ -3675,6 +3678,17 @@
}
}
+ private void enforceGrantRevokeRuntimePermissionPermissions(String message) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(message + " requires "
+ + Manifest.permission.GRANT_RUNTIME_PERMISSIONS + " or "
+ + Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
+ }
+ }
+
@Override
public boolean shouldShowRequestPermissionRationale(String permissionName,
String packageName, int userId) {
@@ -6158,12 +6172,16 @@
return false;
}
}
-
- synchronized (mInstallLock) {
- final String[] instructionSets = new String[] { targetInstructionSet };
- int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
- false /* forceDex */, false /* defer */, true /* inclDependencies */);
- return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mInstallLock) {
+ final String[] instructionSets = new String[] { targetInstructionSet };
+ int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
+ false /* forceDex */, false /* defer */, true /* inclDependencies */);
+ return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
}
}
@@ -9444,7 +9462,7 @@
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
- null, verificationParams, user, packageAbiOverride);
+ null, verificationParams, user, packageAbiOverride, null);
mHandler.sendMessage(msg);
}
@@ -9464,7 +9482,8 @@
final Message msg = mHandler.obtainMessage(INIT_COPY);
msg.obj = new InstallParams(origin, null, observer, params.installFlags,
- installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride);
+ installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride,
+ params.grantedRuntimePermissions);
mHandler.sendMessage(msg);
}
@@ -10344,10 +10363,13 @@
private InstallArgs mArgs;
private int mRet;
final String packageAbiOverride;
+ final String[] grantedRuntimePermissions;
+
InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
- VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
+ VerificationParams verificationParams, UserHandle user, String packageAbiOverride,
+ String[] grantedPermissions) {
super(user);
this.origin = origin;
this.move = move;
@@ -10357,6 +10379,7 @@
this.volumeUuid = volumeUuid;
this.verificationParams = verificationParams;
this.packageAbiOverride = packageAbiOverride;
+ this.grantedRuntimePermissions = grantedPermissions;
}
@Override
@@ -10620,6 +10643,12 @@
final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers, verificationState);
+ // Apps installed for "all" users use the device owner to verify the app
+ UserHandle verifierUser = getUser();
+ if (verifierUser == UserHandle.ALL) {
+ verifierUser = UserHandle.OWNER;
+ }
+
/*
* If any sufficient verifiers were listed in the package
* manifest, attempt to ask them.
@@ -10635,8 +10664,7 @@
final Intent sufficientIntent = new Intent(verification);
sufficientIntent.setComponent(verifierComponent);
-
- mContext.sendBroadcastAsUser(sufficientIntent, getUser());
+ mContext.sendBroadcastAsUser(sufficientIntent, verifierUser);
}
}
}
@@ -10651,7 +10679,7 @@
* target BroadcastReceivers have run.
*/
verification.setComponent(requiredVerifierComponent);
- mContext.sendOrderedBroadcastAsUser(verification, getUser(),
+ mContext.sendOrderedBroadcastAsUser(verification, verifierUser,
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
new BroadcastReceiver() {
@Override
@@ -10781,6 +10809,7 @@
final ManifestDigest manifestDigest;
final UserHandle user;
final String abiOverride;
+ final String[] installGrantPermissions;
// The list of instruction sets supported by this app. This is currently
// only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -10790,7 +10819,7 @@
InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
- String abiOverride) {
+ String abiOverride, String[] installGrantPermissions) {
this.origin = origin;
this.move = move;
this.installFlags = installFlags;
@@ -10801,6 +10830,7 @@
this.user = user;
this.instructionSets = instructionSets;
this.abiOverride = abiOverride;
+ this.installGrantPermissions = installGrantPermissions;
}
abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
@@ -10893,7 +10923,8 @@
FileInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
- params.getUser(), null /* instruction sets */, params.packageAbiOverride);
+ params.getUser(), null /* instruction sets */, params.packageAbiOverride,
+ params.grantedRuntimePermissions);
if (isFwdLocked()) {
throw new IllegalArgumentException("Forward locking only supported in ASEC");
}
@@ -10902,7 +10933,7 @@
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
- null);
+ null, null);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
@@ -11118,7 +11149,8 @@
AsecInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
- params.getUser(), null /* instruction sets */, params.packageAbiOverride);
+ params.getUser(), null /* instruction sets */, params.packageAbiOverride,
+ params.grantedRuntimePermissions);
}
/** Existing install */
@@ -11126,7 +11158,7 @@
boolean isExternal, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
- instructionSets, null);
+ instructionSets, null, null);
// Hackily pretend we're still looking at a full code path
if (!fullCodePath.endsWith(RES_FILE_NAME)) {
fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
@@ -11143,7 +11175,7 @@
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
- instructionSets, null);
+ instructionSets, null, null);
this.cid = cid;
setMountPath(PackageHelper.getSdDir(cid));
}
@@ -11410,7 +11442,8 @@
MoveInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
- params.getUser(), null /* instruction sets */, params.packageAbiOverride);
+ params.getUser(), null /* instruction sets */, params.packageAbiOverride,
+ params.grantedRuntimePermissions);
}
int copyApk(IMediaContainerService imcs, boolean temp) {
@@ -15864,7 +15897,7 @@
final Message msg = mHandler.obtainMessage(INIT_COPY);
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
msg.obj = new InstallParams(origin, move, installObserver, installFlags,
- installerPackageName, volumeUuid, null, user, packageAbiOverride);
+ installerPackageName, volumeUuid, null, user, packageAbiOverride, null);
mHandler.sendMessage(msg);
}
@@ -16031,7 +16064,9 @@
@Override
public void setPermissionEnforced(String permission, boolean enforced) {
- mContext.enforceCallingOrSelfPermission(GRANT_REVOKE_PERMISSIONS, null);
+ // TODO: Now that we no longer change GID for storage, this should to away.
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ "setPermissionEnforced");
if (READ_EXTERNAL_STORAGE.equals(permission)) {
synchronized (mPackages) {
if (mSettings.mReadExternalStorageEnforced == null
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 13e075c..28cbaab 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -104,7 +104,6 @@
import android.view.Surface;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerInternal;
@@ -359,6 +358,7 @@
boolean mSystemReady;
boolean mSystemBooted;
+ private boolean mDeferBindKeyguard;
boolean mHdmiPlugged;
HdmiControl mHdmiControl;
IUiModeManager mUiModeManager;
@@ -6012,6 +6012,7 @@
readCameraLensCoverState();
updateUiMode();
+ boolean bindKeyguardNow;
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -6021,13 +6022,36 @@
updateSettings();
}
});
+
+ bindKeyguardNow = mDeferBindKeyguard;
+ if (bindKeyguardNow) {
+ // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
+ mDeferBindKeyguard = false;
+ }
+ }
+
+ if (bindKeyguardNow) {
+ mKeyguardDelegate.bindService(mContext);
+ mKeyguardDelegate.onBootCompleted();
}
}
/** {@inheritDoc} */
@Override
public void systemBooted() {
- if (mKeyguardDelegate != null) {
+ boolean bindKeyguardNow = false;
+ synchronized (mLock) {
+ // Time to bind Keyguard; take care to only bind it once, either here if ready or
+ // in systemReady if not.
+ if (mKeyguardDelegate != null) {
+ bindKeyguardNow = true;
+ } else {
+ // Because mKeyguardDelegate is null, we know that the synchronized block in
+ // systemReady didn't run yet and setting this will actually have an effect.
+ mDeferBindKeyguard = true;
+ }
+ }
+ if (bindKeyguardNow) {
mKeyguardDelegate.bindService(mContext);
mKeyguardDelegate.onBootCompleted();
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index b9f132b..1406789 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -37,7 +37,7 @@
private final KeyguardState mKeyguardState = new KeyguardState();
private ShowListener mShowListenerWhenConnect;
- /* package */ static final class KeyguardState {
+ private static final class KeyguardState {
KeyguardState() {
// Assume keyguard is showing and secure until we know for sure. This is here in
// the event something checks before the service is actually started.
@@ -119,8 +119,13 @@
mKeyguardState.showing = false;
mKeyguardState.showingAndNotOccluded = false;
mKeyguardState.secure = false;
- mKeyguardState.deviceHasKeyguard = false;
- hideScrim();
+ synchronized (mKeyguardState) {
+ // TODO: Fix synchronisation model in this class. The other state in this class
+ // is at least self-healing but a race condition here can lead to the scrim being
+ // stuck on keyguard-less devices.
+ mKeyguardState.deviceHasKeyguard = false;
+ hideScrim();
+ }
} else {
if (DEBUG) Log.v(TAG, "*** Keyguard started");
}
@@ -307,13 +312,15 @@
}
public void showScrim() {
- if (!mKeyguardState.deviceHasKeyguard) return;
- mScrim.post(new Runnable() {
- @Override
- public void run() {
- mScrim.setVisibility(View.VISIBLE);
- }
- });
+ synchronized (mKeyguardState) {
+ if (!mKeyguardState.deviceHasKeyguard) return;
+ mScrim.post(new Runnable() {
+ @Override
+ public void run() {
+ mScrim.setVisibility(View.VISIBLE);
+ }
+ });
+ }
}
public void hideScrim() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bc63c69..c776e8f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2730,10 +2730,10 @@
wasVisible = win.isWinVisibleLw();
if (wasVisible) {
- int transit = WindowManagerPolicy.TRANSIT_EXIT;
- if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
- transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
- }
+ final int transit = (!startingWindow)
+ ? WindowManagerPolicy.TRANSIT_EXIT
+ : WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+
// Try starting an animation.
if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
win.mExiting = true;
@@ -2745,12 +2745,13 @@
}
}
final AppWindowToken appToken = win.mAppToken;
+ final boolean isAnimating = win.mWinAnimator.isAnimating();
// The starting window is the last window in this app token and it isn't animating.
// Allow it to be removed now as there is no additional window or animation that will
// trigger its removal.
final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null
- && appToken.allAppWindows.size() == 1 && !win.mWinAnimator.isAnimating();
- if (!lastWinStartingNotAnimating && (win.mExiting || win.mWinAnimator.isAnimating())) {
+ && appToken.allAppWindows.size() == 1 && !isAnimating;
+ if (!lastWinStartingNotAnimating && (win.mExiting || isAnimating)) {
// The exit animation is running... wait for it!
win.mExiting = true;
win.mRemoveOnExit = true;
@@ -4527,7 +4528,10 @@
}
wtoken.willBeHidden = false;
- if (wtoken.hidden == visible) {
+ // Allow for state changes and animation to be applied if token is transitioning
+ // visibility state or the token was marked as hidden and is exiting before we had a chance
+ // to play the transition animation.
+ if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting)) {
boolean changed = false;
if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 58fb088..bf78712 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1050,6 +1050,7 @@
private int mConnectionCapabilities;
private VideoProvider mVideoProvider;
private boolean mAudioModeIsVoip;
+ private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
private StatusHints mStatusHints;
private int mVideoState;
private DisconnectCause mDisconnectCause;
@@ -1162,6 +1163,19 @@
}
/**
+ * Retrieves the connection start time of the {@code Connnection}, if specified. A value of
+ * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the
+ * start time of the conference.
+ *
+ * @return The time at which the {@code Connnection} was connected.
+ *
+ * @hide
+ */
+ public final long getConnectTimeMillis() {
+ return mConnectTimeMillis;
+ }
+
+ /**
* @return The status hints for this connection.
*/
public final StatusHints getStatusHints() {
@@ -1476,6 +1490,18 @@
}
/**
+ * Sets the time at which a call became active on this Connection. This is set only
+ * when a conference call becomes active on this connection.
+ *
+ * @param connectionTimeMillis The connection time, in milliseconds.
+ *
+ * @hide
+ */
+ public final void setConnectTimeMillis(long connectTimeMillis) {
+ mConnectTimeMillis = connectTimeMillis;
+ }
+
+ /**
* Sets the label and icon status to display in the in-call UI.
*
* @param statusHints The status label and icon to set.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index d2e7a74..96f44b9 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -651,6 +651,7 @@
connection.getVideoState(),
connection.isRingbackRequested(),
connection.getAudioModeIsVoip(),
+ connection.getConnectTimeMillis(),
connection.getStatusHints(),
connection.getDisconnectCause(),
createIdList(connection.getConferenceables()),
@@ -979,6 +980,7 @@
connection.getVideoState(),
connection.isRingbackRequested(),
connection.getAudioModeIsVoip(),
+ connection.getConnectTimeMillis(),
connection.getStatusHints(),
connection.getDisconnectCause(),
emptyList,
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 683ab6a..fe0a4d8 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -44,6 +44,7 @@
private final int mVideoState;
private final boolean mRingbackRequested;
private final boolean mIsVoipAudioMode;
+ private final long mConnectTimeMillis;
private final StatusHints mStatusHints;
private final DisconnectCause mDisconnectCause;
private final List<String> mConferenceableConnectionIds;
@@ -62,6 +63,7 @@
int videoState,
boolean ringbackRequested,
boolean isVoipAudioMode,
+ long connectTimeMillis,
StatusHints statusHints,
DisconnectCause disconnectCause,
List<String> conferenceableConnectionIds,
@@ -77,6 +79,7 @@
mVideoState = videoState;
mRingbackRequested = ringbackRequested;
mIsVoipAudioMode = isVoipAudioMode;
+ mConnectTimeMillis = connectTimeMillis;
mStatusHints = statusHints;
mDisconnectCause = disconnectCause;
mConferenceableConnectionIds = conferenceableConnectionIds;
@@ -128,6 +131,10 @@
return mIsVoipAudioMode;
}
+ public long getConnectTimeMillis() {
+ return mConnectTimeMillis;
+ }
+
public final StatusHints getStatusHints() {
return mStatusHints;
}
@@ -176,6 +183,7 @@
int videoState = source.readInt();
boolean ringbackRequested = source.readByte() == 1;
boolean audioModeIsVoip = source.readByte() == 1;
+ long connectTimeMillis = source.readLong();
StatusHints statusHints = source.readParcelable(classLoader);
DisconnectCause disconnectCause = source.readParcelable(classLoader);
List<String> conferenceableConnectionIds = new ArrayList<>();
@@ -194,6 +202,7 @@
videoState,
ringbackRequested,
audioModeIsVoip,
+ connectTimeMillis,
statusHints,
disconnectCause,
conferenceableConnectionIds,
@@ -227,6 +236,7 @@
destination.writeInt(mVideoState);
destination.writeByte((byte) (mRingbackRequested ? 1 : 0));
destination.writeByte((byte) (mIsVoipAudioMode ? 1 : 0));
+ destination.writeLong(mConnectTimeMillis);
destination.writeParcelable(mStatusHints, 0);
destination.writeParcelable(mDisconnectCause, 0);
destination.writeStringList(mConferenceableConnectionIds);
diff --git a/telecomm/java/android/telecom/Voicemail.java b/telecomm/java/android/telecom/Voicemail.java
index 151917e..ca235bf 100644
--- a/telecomm/java/android/telecom/Voicemail.java
+++ b/telecomm/java/android/telecom/Voicemail.java
@@ -36,10 +36,11 @@
private final Uri mUri;
private final Boolean mIsRead;
private final Boolean mHasContent;
+ private final String mTranscription;
private Voicemail(Long timestamp, String number, PhoneAccountHandle phoneAccountHandle, Long id,
Long duration, String source, String providerData, Uri uri, Boolean isRead,
- Boolean hasContent) {
+ Boolean hasContent, String transcription) {
mTimestamp = timestamp;
mNumber = number;
mPhoneAccount = phoneAccountHandle;
@@ -50,6 +51,7 @@
mUri = uri;
mIsRead = isRead;
mHasContent = hasContent;
+ mTranscription = transcription;
}
/**
@@ -88,6 +90,7 @@
private Uri mBuilderUri;
private Boolean mBuilderIsRead;
private boolean mBuilderHasContent;
+ private String mBuilderTranscription;
/** You should use the correct factory method to construct a builder. */
private Builder() {
@@ -143,6 +146,11 @@
return this;
}
+ public Builder setTranscription(String transcription) {
+ mBuilderTranscription = transcription;
+ return this;
+ }
+
public Voicemail build() {
mBuilderId = mBuilderId == null ? -1 : mBuilderId;
mBuilderTimestamp = mBuilderTimestamp == null ? 0 : mBuilderTimestamp;
@@ -150,7 +158,7 @@
mBuilderIsRead = mBuilderIsRead == null ? false : mBuilderIsRead;
return new Voicemail(mBuilderTimestamp, mBuilderNumber, mBuilderPhoneAccount,
mBuilderId, mBuilderDuration, mBuilderSourcePackage, mBuilderSourceData,
- mBuilderUri, mBuilderIsRead, mBuilderHasContent);
+ mBuilderUri, mBuilderIsRead, mBuilderHasContent, mBuilderTranscription);
}
}
@@ -230,6 +238,13 @@
return mHasContent;
}
+ /**
+ * Returns the text transcription of this voicemail, or null if this field is not set.
+ */
+ public String getTranscription() {
+ return mTranscription;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -265,6 +280,7 @@
} else {
dest.writeInt(0);
}
+ dest.writeCharSequence(mTranscription);
}
public static final Creator<Voicemail> CREATOR
@@ -299,5 +315,6 @@
}
mIsRead = in.readInt() > 0 ? true : false;
mHasContent = in.readInt() > 0 ? true : false;
+ mTranscription = (String) in.readCharSequence();
}
}