Merge "Updating PIP to match UX"
diff --git a/Android.mk b/Android.mk
index 7c9397f..8c0c640 100644
--- a/Android.mk
+++ b/Android.mk
@@ -108,6 +108,7 @@
core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
core/java/android/app/backup/IRestoreObserver.aidl \
core/java/android/app/backup/IRestoreSession.aidl \
+ core/java/android/app/usage/IStorageStatsManager.aidl \
core/java/android/app/usage/IUsageStatsManager.aidl \
core/java/android/bluetooth/IBluetooth.aidl \
core/java/android/bluetooth/IBluetoothA2dp.aidl \
@@ -689,6 +690,8 @@
frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
frameworks/base/core/java/android/service/chooser/ChooserTarget.aidl \
frameworks/base/core/java/android/speech/tts/Voice.aidl \
+ frameworks/base/core/java/android/app/usage/StorageStats.aidl \
+ frameworks/base/core/java/android/app/usage/StorageSummary.aidl \
frameworks/base/core/java/android/app/usage/UsageEvents.aidl \
frameworks/base/core/java/android/app/Notification.aidl \
frameworks/base/core/java/android/app/NotificationManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index b58947d..a8cdd10 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5393,7 +5393,6 @@
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public boolean isAllowed();
- method public void setAllowed(boolean);
method public void setBypassDnd(boolean);
method public void setImportance(int);
method public void setLights(boolean);
@@ -6679,6 +6678,36 @@
method public abstract void onThresholdReached(int, java.lang.String);
}
+ public final class StorageStats implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getCacheBytes();
+ method public long getCacheQuotaBytes();
+ method public long getCodeBytes();
+ method public long getDataBytes();
+ method public int getUid();
+ method public java.lang.String getVolumeUuid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
+ }
+
+ public class StorageStatsManager {
+ method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
+ method public android.app.usage.StorageSummary querySummary(java.lang.String);
+ }
+
+ public final class StorageSummary implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getFreeBytes();
+ method public long getSharedAudioBytes();
+ method public long getSharedImagesBytes();
+ method public long getSharedTotalBytes();
+ method public long getSharedVideoBytes();
+ method public long getTotalBytes();
+ method public java.lang.String getVolumeUuid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.usage.StorageSummary> CREATOR;
+ }
+
public final class UsageEvents implements android.os.Parcelable {
method public int describeContents();
method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -8415,6 +8444,7 @@
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
+ field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
@@ -11949,8 +11979,6 @@
method public boolean clipRect(float, float, float, float, android.graphics.Region.Op);
method public boolean clipRect(float, float, float, float);
method public boolean clipRect(int, int, int, int);
- method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
- method public deprecated boolean clipRegion(android.graphics.Region);
method public void concat(android.graphics.Matrix);
method public void drawARGB(int, int, int, int);
method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
diff --git a/api/removed.txt b/api/removed.txt
index 35b4859..d7a8bce 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -78,6 +78,11 @@
enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
}
+ public class Canvas {
+ method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
+ method public deprecated boolean clipRegion(android.graphics.Region);
+ }
+
public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
ctor public LayerRasterizer();
method public void addLayer(android.graphics.Paint, float, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7a0f24c..cc1832d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5555,7 +5555,6 @@
method public boolean isAllowed();
method public void lockFields(int);
method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
- method public void setAllowed(boolean);
method public void setBypassDnd(boolean);
method public void setImportance(int);
method public void setLights(boolean);
@@ -6992,6 +6991,36 @@
method public abstract void onThresholdReached(int, java.lang.String);
}
+ public final class StorageStats implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getCacheBytes();
+ method public long getCacheQuotaBytes();
+ method public long getCodeBytes();
+ method public long getDataBytes();
+ method public int getUid();
+ method public java.lang.String getVolumeUuid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
+ }
+
+ public class StorageStatsManager {
+ method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
+ method public android.app.usage.StorageSummary querySummary(java.lang.String);
+ }
+
+ public final class StorageSummary implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getFreeBytes();
+ method public long getSharedAudioBytes();
+ method public long getSharedImagesBytes();
+ method public long getSharedTotalBytes();
+ method public long getSharedVideoBytes();
+ method public long getTotalBytes();
+ method public java.lang.String getVolumeUuid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.usage.StorageSummary> CREATOR;
+ }
+
public final class UsageEvents implements android.os.Parcelable {
method public int describeContents();
method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -8770,6 +8799,7 @@
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
+ field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
@@ -12447,8 +12477,6 @@
method public boolean clipRect(float, float, float, float, android.graphics.Region.Op);
method public boolean clipRect(float, float, float, float);
method public boolean clipRect(int, int, int, int);
- method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
- method public deprecated boolean clipRegion(android.graphics.Region);
method public void concat(android.graphics.Matrix);
method public void drawARGB(int, int, int, int);
method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
@@ -27279,6 +27307,8 @@
public class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
+ method public boolean hasNoInternetAccess();
+ method public boolean isNoInternetAccessExpected();
method public boolean isPasspoint();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
@@ -27451,6 +27481,7 @@
method public static int calculateSignalLevel(int, int);
method public void cancelWps(android.net.wifi.WifiManager.WpsCallback);
method public static int compareSignalLevel(int, int);
+ method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
@@ -27550,6 +27581,11 @@
field public static final int WPS_WEP_PROHIBITED = 4; // 0x4
}
+ public static abstract interface WifiManager.ActionListener {
+ method public abstract void onFailure(int);
+ method public abstract void onSuccess();
+ }
+
public class WifiManager.MulticastLock {
method public void acquire();
method public boolean isHeld();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 8016f58..7ba88bd 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -76,6 +76,11 @@
enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
}
+ public class Canvas {
+ method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
+ method public deprecated boolean clipRegion(android.graphics.Region);
+ }
+
public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
ctor public LayerRasterizer();
method public void addLayer(android.graphics.Paint, float, float);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4118053..e614883 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5403,7 +5403,6 @@
method public android.net.Uri getSound();
method public long[] getVibrationPattern();
method public boolean isAllowed();
- method public void setAllowed(boolean);
method public void setBypassDnd(boolean);
method public void setImportance(int);
method public void setLights(boolean);
@@ -6701,6 +6700,36 @@
method public abstract void onThresholdReached(int, java.lang.String);
}
+ public final class StorageStats implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getCacheBytes();
+ method public long getCacheQuotaBytes();
+ method public long getCodeBytes();
+ method public long getDataBytes();
+ method public int getUid();
+ method public java.lang.String getVolumeUuid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.usage.StorageStats> CREATOR;
+ }
+
+ public class StorageStatsManager {
+ method public android.app.usage.StorageStats queryStatsForUid(java.lang.String, int);
+ method public android.app.usage.StorageSummary querySummary(java.lang.String);
+ }
+
+ public final class StorageSummary implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getFreeBytes();
+ method public long getSharedAudioBytes();
+ method public long getSharedImagesBytes();
+ method public long getSharedTotalBytes();
+ method public long getSharedVideoBytes();
+ method public long getTotalBytes();
+ method public java.lang.String getVolumeUuid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.usage.StorageSummary> CREATOR;
+ }
+
public final class UsageEvents implements android.os.Parcelable {
method public int describeContents();
method public boolean getNextEvent(android.app.usage.UsageEvents.Event);
@@ -8439,6 +8468,7 @@
field public static final java.lang.String SENSOR_SERVICE = "sensor";
field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
+ field public static final java.lang.String STORAGE_STATS_SERVICE = "storagestats";
field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
field public static final java.lang.String TELEPHONY_SERVICE = "phone";
@@ -11980,8 +12010,6 @@
method public boolean clipRect(float, float, float, float, android.graphics.Region.Op);
method public boolean clipRect(float, float, float, float);
method public boolean clipRect(int, int, int, int);
- method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
- method public deprecated boolean clipRegion(android.graphics.Region);
method public void concat(android.graphics.Matrix);
method public void drawARGB(int, int, int, int);
method public void drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 35b4859..d7a8bce 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -78,6 +78,11 @@
enum_constant public static final android.graphics.AvoidXfermode.Mode TARGET;
}
+ public class Canvas {
+ method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
+ method public deprecated boolean clipRegion(android.graphics.Region);
+ }
+
public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
ctor public LayerRasterizer();
method public void addLayer(android.graphics.Paint, float, float);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8185818..2be84c1 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -328,7 +328,6 @@
/**
* Token type for the special case where a UID has access only to an account
* but no authenticator specific auth token types.
- *
* @hide
*/
public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
@@ -354,9 +353,9 @@
* the applications are added, accounts are removed, or an account's credentials (saved
* password, etc) are changed. List of supported account types shoud be specified in the
* Manifest file using {@link #SUPPORTED_ACCOUNT_TYPES}
- *
- * @see #addOnAccountsUpdatedListener
* @hide
+ * @see #addOnAccountsUpdatedListener
+ *
*/
public static final String ACTION_VISIBLE_ACCOUNTS_CHANGED =
"android.accounts.action.VISIBLE_ACCOUNTS_CHANGED";
@@ -364,6 +363,7 @@
/**
* Authenticators may subscribe to get notifications about apps interested in their managed account
* types using {@link #SUPPORTED_ACCOUNT_TYPES}.
+ * Package name will be specified using {@link Intent.EXTRA_PACKAGE_NAME}
* @hide
*/
public static final String ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED =
@@ -1024,7 +1024,7 @@
public boolean isAccountVisible(Account account, int uid) {
try {
Integer visibility = mService.getAccountVisibility(account, uid);
- return visibility == VISIBILITY_USER_MANAGED_NOT_VISIBLE
+ return visibility == VISIBILITY_USER_MANAGED_VISIBLE
|| visibility == VISIBILITY_VISIBLE;
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -1058,6 +1058,7 @@
/**
* Gets visibility of certain account for given UID. Possible returned values are:
* <ul>
+ * <li>{@link #VISIBILITY_UNDEFINED}</li>
* <li>{@link #VISIBILITY_VISIBLE}</li>
* <li>{@link #VISIBILITY_USER_MANAGED_VISIBLE}</li>
* <li>{@link #VISIBILITY_NOT_VISIBLE}
diff --git a/core/java/android/accounts/ChooseAccountActivity.java b/core/java/android/accounts/ChooseAccountActivity.java
index 242b3ea..16a45ba 100644
--- a/core/java/android/accounts/ChooseAccountActivity.java
+++ b/core/java/android/accounts/ChooseAccountActivity.java
@@ -52,7 +52,9 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+ // TODO This activity is only used by getAuthTokenByFeatures and can not see
+ // VISIBILITY_USER_MANAGED_NOT_VISIBLE accounts. It should be moved to account managed
+ // service.
mAccounts = getIntent().getParcelableArrayExtra(AccountManager.KEY_ACCOUNTS);
mAccountManagerResponse =
getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 761da35..cd50c4d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -80,7 +80,39 @@
import java.util.List;
/**
- * Interact with the overall activities running in the system.
+ * <p>
+ * This class gives information about, and interacts
+ * with, activities, services, and the containing
+ * process.
+ * </p>
+ *
+ * <p>
+ * A number of the methods in this class are for
+ * debugging or informational purposes and they should
+ * not be used to affect any runtime behavior of
+ * your app. These methods are called out as such in
+ * the method level documentation.
+ * </p>
+ *
+ *<p>
+ * Most application developers should not have the need to
+ * use this class, most of whose methods are for specialized
+ * use cases. However, a few methods are more broadly applicable.
+ * For instance, {@link android.app.ActivityManager#isLowRamDevice() isLowRamDevice()}
+ * enables your app to detect whether it is running on a low-memory device,
+ * and behave accordingly.
+ * {@link android.app.ActivityManager#clearApplicationUserData() clearApplicationUserData()}
+ * is for apps with reset-data functionality.
+ * </p>
+ *
+ * <p>
+ * In some special use cases, where an app interacts with
+ * its Task stack, the app may use the
+ * {@link android.app.ActivityManager.AppTask} and
+ * {@link android.app.ActivityManager.RecentTaskInfo} inner
+ * classes. However, in general, the methods in this class should
+ * be used for testing and debugging purposes only.
+ * </p>
*/
public class ActivityManager {
private static String TAG = "ActivityManager";
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 52d9b67..bdccb8a 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -55,7 +55,6 @@
private static final String ATT_AUDIO_ATTRIBUTES = "audio_attributes";
private static final String ATT_SHOW_BADGE = "show_badge";
private static final String ATT_USER_LOCKED = "locked";
- private static final String ATT_ALLOWED = "allowed";
private static final String DELIMITER = ",";
/**
@@ -243,12 +242,12 @@
this.mImportance = importance;
}
+ // Modifiable by apps on channel creation.
+
/**
* Sets whether notifications posted to this channel can appear as application icon badges
* in a Launcher.
*
- * Only modifiable by the system and notification ranker.
- *
* @param showBadge true if badges should be allowed to be shown.
*/
public void setShowBadge(boolean showBadge) {
@@ -256,20 +255,6 @@
}
/**
- * Sets whether notifications are allowed to be posted to this channel.
- *
- * Only modifiable by the system and notification ranker.
- *
- * @param allowed true if notifications are not allowed from this channel.
- */
- public void setAllowed(boolean allowed) {
- this.mAllowed = allowed;
- }
-
-
- // Modifiable by apps on channel creation.
-
- /**
* Sets the sound that should be played for notifications posted to this channel if
* the notifications don't supply a sound. Only modifiable before the channel is submitted
* to the NotificationManager.
@@ -408,7 +393,6 @@
enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
setShowBadge(safeBool(parser, ATT_SHOW_BADGE, false));
- setAllowed(safeBool(parser, ATT_ALLOWED, true));
lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
}
@@ -450,9 +434,6 @@
if (canShowBadge()) {
out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
}
- if (!isAllowed()) {
- out.attribute(null, ATT_ALLOWED, Boolean.toString(isAllowed()));
- }
out.endTag(null, TAG_CHANNEL);
}
@@ -483,8 +464,6 @@
record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
record.put(ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
- record.put(ATT_ALLOWED, Boolean.toString(isAllowed()));
-
return record;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6bddfba..9387019 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -23,8 +23,10 @@
import android.app.job.IJobScheduler;
import android.app.job.JobScheduler;
import android.app.trust.TrustManager;
+import android.app.usage.IStorageStatsManager;
import android.app.usage.IUsageStatsManager;
import android.app.usage.NetworkStatsManager;
+import android.app.usage.StorageStatsManager;
import android.app.usage.UsageStatsManager;
import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothManager;
@@ -434,6 +436,15 @@
return new StorageManager(ctx, ctx.mMainThread.getHandler().getLooper());
}});
+ registerService(Context.STORAGE_STATS_SERVICE, StorageStatsManager.class,
+ new CachedServiceFetcher<StorageStatsManager>() {
+ @Override
+ public StorageStatsManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IStorageStatsManager service = IStorageStatsManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.STORAGE_STATS_SERVICE));
+ return new StorageStatsManager(ctx, service);
+ }});
+
registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
new CachedServiceFetcher<TelephonyManager>() {
@Override
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 20ddb77..28704e6 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -19,10 +19,8 @@
import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.PersistableBundle;
import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
@@ -49,25 +47,45 @@
* Unknown policy type, used only internally.
*/
private static final int TYPE_UNKNOWN = -1;
+
/**
* Install system update automatically as soon as one is available.
*/
public static final int TYPE_INSTALL_AUTOMATIC = 1;
/**
- * Install system update automatically within a daily maintenance window, for a maximum of 30
- * days. After the expiration the policy will no longer be effective and the system should
- * revert back to its normal behavior as if no policy were set. The only exception is
- * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
- * immediately.
+ * Install system update automatically within a daily maintenance window. An update can be
+ * delayed for a maximum of 30 days, after which the policy will no longer be effective and the
+ * system will revert back to its normal behavior as if no policy were set.
+ *
+ * <p>After this policy expires, resetting it to any policy other than
+ * {@link #TYPE_INSTALL_AUTOMATIC} will produce no effect, as the 30-day maximum delay has
+ * already been used up.
+ * The {@link #TYPE_INSTALL_AUTOMATIC} policy will still take effect to install the delayed
+ * system update immediately.
+ *
+ * <p>Re-applying this policy or changing it to {@link #TYPE_POSTPONE} within the 30-day period
+ * will <i>not</i> extend policy expiration.
+ * However, the expiration will be recalculated when a new system update is made available.
*/
public static final int TYPE_INSTALL_WINDOWED = 2;
/**
- * Incoming system update will be blocked for a maximum of 30 days, after which the system
- * should revert back to its normal behavior as if no policy were set. The only exception is
- * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
- * immediately.
+ * Incoming system updates (except for security updates) will be blocked for 30 days, after
+ * which the policy will no longer be effective and the system will revert back to its normal
+ * behavior as if no policy were set.
+ * <b>Note:</b> security updates (e.g. monthly security patches) will <i>not</i> be affected by
+ * this policy.
+ *
+ * <p>After this policy expires, resetting it to any policy other than
+ * {@link #TYPE_INSTALL_AUTOMATIC} will produce no effect, as the 30-day maximum delay has
+ * already been used up.
+ * The {@link #TYPE_INSTALL_AUTOMATIC} policy will still take effect to install the delayed
+ * system update immediately.
+ *
+ * <p>Re-applying this policy or changing it to {@link #TYPE_INSTALL_WINDOWED} within the 30-day
+ * period will <i>not</i> extend policy expiration.
+ * However, the expiration will be recalculated when a new system update is made available.
*/
public static final int TYPE_POSTPONE = 3;
@@ -105,11 +123,12 @@
/**
* Create a policy object and set it to: new system update will only be installed automatically
* when the system clock is inside a daily maintenance window. If the start and end times are
- * the same, the window is considered to include the WHOLE 24 hours, that is, updates can
- * install at any time. If the given window in invalid, a {@link IllegalArgumentException} will
- * be thrown. If start time is later than end time, the window is considered spanning midnight,
- * i.e. end time donates a time on the next day. The maintenance window will last for 30 days,
- * after which the system should revert back to its normal behavior as if no policy were set.
+ * the same, the window is considered to include the <i>whole 24 hours</i>. That is, updates can
+ * install at any time. If the given window in invalid, an {@link IllegalArgumentException}
+ * will be thrown. If start time is later than end time, the window is considered spanning
+ * midnight (i.e. the end time denotes a time on the next day). The maintenance window will last
+ * for 30 days, after which the system will revert back to its normal behavior as if no policy
+ * were set.
*
* @param startTime the start of the maintenance window, measured as the number of minutes from
* midnight in the device's local time. Must be in the range of [0, 1440).
@@ -131,9 +150,12 @@
/**
* Create a policy object and set it to block installation for a maximum period of 30 days.
- * After expiration the system should revert back to its normal behavior as if no policy were
+ * After expiration the system will revert back to its normal behavior as if no policy were
* set.
*
+ * <p><b>Note: </b> security updates (e.g. monthly security patches) will <i>not</i> be affected
+ * by this policy.
+ *
* @see #TYPE_POSTPONE
*/
public static SystemUpdatePolicy createPostponeInstallPolicy() {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/core/java/android/app/usage/IStorageStatsManager.aidl
similarity index 60%
copy from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
copy to core/java/android/app/usage/IStorageStatsManager.aidl
index a35e71d..96125a1 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/core/java/android/app/usage/IStorageStatsManager.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
* limitations under the License.
*/
-package android.net.wifi.aware;
+package android.app.usage;
-parcelable WifiAwareCharacteristics;
+import android.app.usage.StorageStats;
+import android.app.usage.StorageSummary;
+
+/** {@hide} */
+interface IStorageStatsManager {
+ StorageStats queryStats(String volumeUuid, int uid, String callingPackage);
+ StorageSummary querySummary(String volumeUuid, String callingPackage);
+}
diff --git a/core/java/android/view/GraphicBuffer.aidl b/core/java/android/app/usage/StorageStats.aidl
similarity index 83%
copy from core/java/android/view/GraphicBuffer.aidl
copy to core/java/android/app/usage/StorageStats.aidl
index 6dc6bed..fde6267 100644
--- a/core/java/android/view/GraphicBuffer.aidl
+++ b/core/java/android/app/usage/StorageStats.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.view;
+package android.app.usage;
-parcelable GraphicBuffer;
+parcelable StorageStats;
diff --git a/core/java/android/app/usage/StorageStats.java b/core/java/android/app/usage/StorageStats.java
new file mode 100644
index 0000000..b2486d8
--- /dev/null
+++ b/core/java/android/app/usage/StorageStats.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Storage statistics for a single UID on a single storage volume.
+ * <p class="note">
+ * Note: multiple packages using the same {@code sharedUserId} in their manifest
+ * will be merged into a single UID.
+ * </p>
+ *
+ * @see StorageStatsManager
+ */
+public final class StorageStats implements Parcelable {
+ /** {@hide} */ public final String volumeUuid;
+ /** {@hide} */ public final int uid;
+
+ /** {@hide} */ public long codeBytes;
+ /** {@hide} */ public long dataBytes;
+ /** {@hide} */ public long cacheQuotaBytes;
+ /** {@hide} */ public long cacheBytes;
+
+ /**
+ * Return the UUID of the storage volume that these statistics refer to. The
+ * value {@code null} indicates the default internal storage.
+ */
+ public String getVolumeUuid() {
+ return volumeUuid;
+ }
+
+ /**
+ * Return the UID that these statistics refer to.
+ *
+ * @see ApplicationInfo#uid
+ * @see PackageManager#getPackagesForUid(int)
+ */
+ public int getUid() {
+ return uid;
+ }
+
+ /**
+ * Return the size of all code associated with {@link #getUid()} on
+ * {@link #getVolumeUuid()}. This includes {@code APK} files and optimized
+ * compiler output.
+ * <p>
+ * If the primary shared storage location is also hosted on
+ * {@link #getVolumeUuid()} then this includes files stored under
+ * {@link Context#getObbDir()}.
+ * <p>
+ * Code is shared between all users on a multiuser device.
+ */
+ public long getCodeBytes() {
+ return codeBytes;
+ }
+
+ /**
+ * Return the size of all data associated with {@link #getUid()} on
+ * {@link #getVolumeUuid()}. This includes files stored under
+ * {@link Context#getDataDir()}, {@link Context#getCacheDir()},
+ * {@link Context#getCodeCacheDir()}.
+ * <p>
+ * If the primary shared storage location is also hosted on
+ * {@link #getVolumeUuid()} then this includes files stored under
+ * {@link Context#getExternalFilesDir(String)} and
+ * {@link Context#getExternalCacheDir()}.
+ * <p>
+ * Data is isolated for each user on a multiuser device.
+ */
+ public long getDataBytes() {
+ return dataBytes;
+ }
+
+ /**
+ * Return the quota for cached data associated with {@link #getUid()} on
+ * {@link #getVolumeUuid()}. This quota value is calculated based on how
+ * frequently the user has interacted with the UID.
+ * <p>
+ * When clearing cached data, the system will first focus on packages whose
+ * cached data is larger than their allocated quota.
+ */
+ public long getCacheQuotaBytes() {
+ return cacheQuotaBytes;
+ }
+
+ /**
+ * Return the size of all cached data associated with {@link #getUid()} on
+ * {@link #getVolumeUuid()}. This includes files stored under
+ * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}.
+ * <p>
+ * If the primary shared storage location is also hosted on
+ * {@link #getVolumeUuid()} then this includes files stored under
+ * {@link Context#getExternalCacheDir()}.
+ * <p>
+ * Cached data is isolated for each user on a multiuser device.
+ */
+ public long getCacheBytes() {
+ return cacheBytes;
+ }
+
+ /** {@hide} */
+ public StorageStats(String uuid, int uid) {
+ this.volumeUuid = uuid;
+ this.uid = uid;
+ }
+
+ /** {@hide} */
+ public StorageStats(Parcel in) {
+ this.volumeUuid = in.readString();
+ this.uid = in.readInt();
+ this.codeBytes = in.readLong();
+ this.dataBytes = in.readLong();
+ this.cacheQuotaBytes = in.readLong();
+ this.cacheBytes = in.readLong();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(volumeUuid);
+ dest.writeInt(uid);
+ dest.writeLong(codeBytes);
+ dest.writeLong(dataBytes);
+ dest.writeLong(cacheQuotaBytes);
+ dest.writeLong(cacheBytes);
+ }
+
+ public static final Creator<StorageStats> CREATOR = new Creator<StorageStats>() {
+ @Override
+ public StorageStats createFromParcel(Parcel in) {
+ return new StorageStats(in);
+ }
+
+ @Override
+ public StorageStats[] newArray(int size) {
+ return new StorageStats[size];
+ }
+ };
+}
diff --git a/core/java/android/app/usage/StorageStatsManager.java b/core/java/android/app/usage/StorageStatsManager.java
new file mode 100644
index 0000000..cdfbe0c
--- /dev/null
+++ b/core/java/android/app/usage/StorageStatsManager.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage;
+
+import android.annotation.WorkerThread;
+import android.content.Context;
+import android.os.RemoteException;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Provides access to detailed storage statistics.
+ * <p class="note">
+ * Note: this API requires the permission
+ * {@code android.permission.PACKAGE_USAGE_STATS}, which is a system-level
+ * permission that will not be granted to normal apps. However, declaring the
+ * permission expresses your intention to use this API and an end user can then
+ * choose to grant this permission through the Settings application.
+ * </p>
+ */
+public class StorageStatsManager {
+ private final Context mContext;
+ private final IStorageStatsManager mService;
+
+ /** {@hide} */
+ public StorageStatsManager(Context context, IStorageStatsManager service) {
+ mContext = Preconditions.checkNotNull(context);
+ mService = Preconditions.checkNotNull(service);
+ }
+
+ /**
+ * Return detailed statistics for the a specific UID on the requested
+ * storage volume.
+ * <p>
+ * This method may take several seconds to calculate the requested values,
+ * so it should only be called from a worker thread.
+ *
+ * @param volumeUuid the UUID of the storage volume you're interested in, or
+ * {@code null} to specify the default internal storage.
+ * @param uid the UID you're interested in.
+ */
+ @WorkerThread
+ public StorageStats queryStatsForUid(String volumeUuid, int uid) {
+ try {
+ return mService.queryStats(volumeUuid, uid, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return summary statistics for the requested storage volume.
+ * <p>
+ * This method may take several seconds to calculate the requested values,
+ * so it should only be called from a worker thread.
+ *
+ * @param volumeUuid the UUID of the storage volume you're interested in, or
+ * {@code null} to specify the default internal storage.
+ */
+ @WorkerThread
+ public StorageSummary querySummary(String volumeUuid) {
+ try {
+ return mService.querySummary(volumeUuid, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/view/GraphicBuffer.aidl b/core/java/android/app/usage/StorageSummary.aidl
similarity index 83%
copy from core/java/android/view/GraphicBuffer.aidl
copy to core/java/android/app/usage/StorageSummary.aidl
index 6dc6bed..b20e025 100644
--- a/core/java/android/view/GraphicBuffer.aidl
+++ b/core/java/android/app/usage/StorageSummary.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.view;
+package android.app.usage;
-parcelable GraphicBuffer;
+parcelable StorageSummary;
diff --git a/core/java/android/app/usage/StorageSummary.java b/core/java/android/app/usage/StorageSummary.java
new file mode 100644
index 0000000..e72c9ec
--- /dev/null
+++ b/core/java/android/app/usage/StorageSummary.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.usage;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.File;
+
+/**
+ * Storage summary for a single storage volume.
+ * <p>
+ * When presenting this summary to users, the
+ * <p>
+ * Details for specific UIDs are available through {@link StorageStats}.
+ *
+ * @see StorageStatsManager
+ */
+public final class StorageSummary implements Parcelable {
+ /** {@hide} */ public final String volumeUuid;
+
+ /** {@hide} */ public long totalBytes;
+ /** {@hide} */ public long freeBytes;
+
+ /** {@hide} */ public long sharedTotalBytes;
+ /** {@hide} */ public long sharedAudioBytes;
+ /** {@hide} */ public long sharedVideoBytes;
+ /** {@hide} */ public long sharedImagesBytes;
+
+ /**
+ * Return the UUID of the storage volume that these statistics refer to. The
+ * value {@code null} indicates the default internal storage.
+ */
+ public String getVolumeUuid() {
+ return volumeUuid;
+ }
+
+ /**
+ * Return the total size of the storage volume.
+ * <p>
+ * To reduce end user confusion, this value is the total storage size
+ * advertised in a retail environment, which is typically larger than the
+ * actual writable partition total size.
+ */
+ public long getTotalBytes() {
+ return totalBytes;
+ }
+
+ /**
+ * Return the free space on this storage volume.
+ * <p>
+ * The free space is equivalent to {@link File#getFreeSpace()} plus the size
+ * of any cached data that can be automatically deleted by the system as
+ * additional space is needed.
+ */
+ public long getFreeBytes() {
+ return freeBytes;
+ }
+
+ /**
+ * Return the total bytes used by all files in the shared storage hosted on
+ * this volume.
+ *
+ * @return total bytes, or {@code -1} if no shared storage is hosted on this
+ * volume.
+ */
+ public long getSharedTotalBytes() {
+ return sharedTotalBytes;
+ }
+
+ /**
+ * Return the total bytes used by audio files in the shared storage hosted
+ * on this volume.
+ *
+ * @return total bytes, or {@code -1} if no shared storage is hosted on this
+ * volume.
+ */
+ public long getSharedAudioBytes() {
+ return sharedAudioBytes;
+ }
+
+ /**
+ * Return the total bytes used by video files in the shared storage hosted
+ * on this volume.
+ *
+ * @return total bytes, or {@code -1} if no shared storage is hosted on this
+ * volume.
+ */
+ public long getSharedVideoBytes() {
+ return sharedVideoBytes;
+ }
+
+ /**
+ * Return the total bytes used by image files in the shared storage hosted
+ * on this volume.
+ *
+ * @return total bytes, or {@code -1} if no shared storage is hosted on this
+ * volume.
+ */
+ public long getSharedImagesBytes() {
+ return sharedImagesBytes;
+ }
+
+ /** {@hide} */
+ public StorageSummary(String uuid) {
+ this.volumeUuid = uuid;
+ }
+
+ /** {@hide} */
+ public StorageSummary(Parcel in) {
+ this.volumeUuid = in.readString();
+ this.totalBytes = in.readLong();
+ this.freeBytes = in.readLong();
+ this.sharedTotalBytes = in.readLong();
+ this.sharedAudioBytes = in.readLong();
+ this.sharedVideoBytes = in.readLong();
+ this.sharedImagesBytes = in.readLong();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(volumeUuid);
+ dest.writeLong(totalBytes);
+ dest.writeLong(freeBytes);
+ dest.writeLong(sharedTotalBytes);
+ dest.writeLong(sharedAudioBytes);
+ dest.writeLong(sharedVideoBytes);
+ dest.writeLong(sharedImagesBytes);
+ }
+
+ public static final Creator<StorageSummary> CREATOR = new Creator<StorageSummary>() {
+ @Override
+ public StorageSummary createFromParcel(Parcel in) {
+ return new StorageSummary(in);
+ }
+
+ @Override
+ public StorageSummary[] newArray(int size) {
+ return new StorageSummary[size];
+ }
+ };
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9dc60ab..ffe1248 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2680,6 +2680,7 @@
SEARCH_SERVICE,
SENSOR_SERVICE,
STORAGE_SERVICE,
+ STORAGE_STATS_SERVICE,
WALLPAPER_SERVICE,
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
@@ -3077,6 +3078,16 @@
public static final String STORAGE_SERVICE = "storage";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.app.usage.StorageStatsManager} for accessing system storage
+ * statistics.
+ *
+ * @see #getSystemService
+ * @see android.app.usage.StorageStatsManager
+ */
+ public static final String STORAGE_STATS_SERVICE = "storagestats";
+
+ /**
* Use with {@link #getSystemService} to retrieve a
* com.android.server.WallpaperService for accessing wallpapers.
*
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9b99bbf..adc99d3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -36,6 +36,8 @@
import java.util.Comparator;
import java.util.Objects;
+import static android.os.Build.VERSION_CODES.DONUT;
+
/**
* Information you can retrieve about a particular application. This
* corresponds to information collected from the AndroidManifest.xml's
@@ -1085,6 +1087,18 @@
FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
}
+ /**
+ * Is using compatibility mode for non densty aware legacy applications.
+ *
+ * @hide
+ */
+ public boolean usesCompatibilityMode() {
+ return targetSdkVersion < DONUT ||
+ (flags & (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS |
+ FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS |
+ FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS)) == 0;
+ }
+
/** {@hide} */
public void initForUser(int userId) {
uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cf4c0fa..ad1ed55 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2387,10 +2387,28 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
}
+ // At this point we can check if an application is not supporting densities and hence
+ // cannot be windowed / resized. Note that an SDK version of 0 is common for
+ // pre-Doughnut applications.
+ if (pkg.applicationInfo.usesCompatibilityMode()) {
+ adjustPackageToBeUnresizeable(pkg);
+ }
return pkg;
}
/**
+ * This is a pre-density application which will get scaled - instead of being pixel perfect.
+ * This type of application is not resizable.
+ *
+ * @param pkg The package which needs to be marked as unresizable.
+ */
+ private void adjustPackageToBeUnresizeable(Package pkg) {
+ for (Activity a : pkg.activities) {
+ a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ }
+ }
+
+ /**
* Computes the targetSdkVersion to use at runtime. If the package is not
* compatible with this platform, populates {@code outError[0]} with an
* error message.
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index a4d8916..b4dcdf7 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1061,11 +1061,6 @@
* Launcher apps should show the launcher icon for the returned activity alongside
* this shortcut.
*
- * <p>When a shortcut is dynamic or manifest
- * (i.e. either {@link #isDynamic()} or {@link #isDeclaredInManifest()} returns {@code TRUE}),
- * then it should always have a non-null target activity.
- * Otherwise it will return null.
- *
* @see Builder#setActivity
*/
@Nullable
@@ -1372,7 +1367,7 @@
}
/**
- * Return {@code TRUE} if a shortcut is pinned but neither manifest nor dynamic.
+ * @return true if pinned but neither static nor dynamic.
* @hide
*/
public boolean isFloating() {
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 4e606ef..717ac70 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -16,18 +16,15 @@
package android.net;
-import android.Manifest;
import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.content.Context;
-import android.content.Intent;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
-import android.os.UserHandle;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -44,19 +41,11 @@
* <p>A network scorer is any application which:
* <ul>
* <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
- * <li>Includes a receiver for {@link #ACTION_SCORE_NETWORKS} guarded by the
- * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission which scores
- * networks and (eventually) calls {@link #updateScores} with the results. If this receiver
- * specifies an android:label attribute, this label will be used when referring to the
- * application throughout system settings; otherwise, the application label will be used.
+ * <li>Include a Service for the {@link #ACTION_RECOMMEND_NETWORKS} action
+ * protected by the {@link android.Manifest.permission#BIND_NETWORK_RECOMMENDATION_SERVICE}
+ * permission.
* </ul>
*
- * <p>The system keeps track of an active scorer application; at any time, only this application
- * will receive {@link #ACTION_SCORE_NETWORKS} broadcasts and will be permitted to call
- * {@link #updateScores}. Applications may determine the current active scorer with
- * {@link #getActiveScorerPackage()} and request to change the active scorer by sending an
- * {@link #ACTION_CHANGE_ACTIVE} broadcast with another scorer.
- *
* @hide
*/
@SystemApi
@@ -263,12 +252,9 @@
/**
* Request scoring for networks.
*
- * <p>Note that this is just a helper method to assemble the broadcast, and will run in the
- * calling process.
- *
* @return true if the broadcast was sent, or false if there is no active scorer.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
* @hide
*/
public boolean requestScores(NetworkKey[] networks) throws SecurityException {
@@ -285,7 +271,7 @@
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
* @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE.
* @hide
@@ -302,7 +288,7 @@
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
* @param filterType the {@link CacheUpdateFilter} to apply
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
* @hide
*/
@@ -321,7 +307,7 @@
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
* @hide
*/
@@ -342,7 +328,8 @@
* request details
* @return a {@link RecommendationResult} instance containing the recommended network
* to connect to
- * @throws SecurityException
+ * @throws SecurityException if the caller does not hold the
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
*/
public RecommendationResult requestRecommendation(RecommendationRequest request)
throws SecurityException {
diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java
index b509d76..af328d0 100644
--- a/core/java/android/os/BatteryProperties.java
+++ b/core/java/android/os/BatteryProperties.java
@@ -30,6 +30,7 @@
public int batteryLevel;
public int batteryVoltage;
public int batteryTemperature;
+ public int batteryFullCharge;
public int batteryChargeCounter;
public String batteryTechnology;
@@ -48,6 +49,7 @@
batteryLevel = other.batteryLevel;
batteryVoltage = other.batteryVoltage;
batteryTemperature = other.batteryTemperature;
+ batteryFullCharge = other.batteryFullCharge;
batteryChargeCounter = other.batteryChargeCounter;
batteryTechnology = other.batteryTechnology;
}
@@ -69,6 +71,7 @@
batteryLevel = p.readInt();
batteryVoltage = p.readInt();
batteryTemperature = p.readInt();
+ batteryFullCharge = p.readInt();
batteryChargeCounter = p.readInt();
batteryTechnology = p.readString();
}
@@ -85,6 +88,7 @@
p.writeInt(batteryLevel);
p.writeInt(batteryVoltage);
p.writeInt(batteryTemperature);
+ p.writeInt(batteryFullCharge);
p.writeInt(batteryChargeCounter);
p.writeString(batteryTechnology);
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8d73544..013972d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -24,6 +24,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Predicate;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -1342,9 +1343,11 @@
public static final int EVENT_WAKEUP_AP = 0x0013;
// Event for reporting that a specific partial wake lock has been held for a long duration.
public static final int EVENT_LONG_WAKE_LOCK = 0x0014;
+ // Event reporting the new estimated (learned) capacity of the battery in mAh.
+ public static final int EVENT_ESTIMATED_BATTERY_CAP = 0x0015;
// Number of event types.
- public static final int EVENT_COUNT = 0x0015;
+ public static final int EVENT_COUNT = 0x0016;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -2040,13 +2043,28 @@
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
"active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist",
- "screenwake", "wakeupap", "longwake"
+ "screenwake", "wakeupap", "longwake", "est_capacity"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
"Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw",
- "Esw", "Ewa", "Elw"
+ "Esw", "Ewa", "Elw", "Eec"
+ };
+
+ @FunctionalInterface
+ public interface IntToString {
+ String applyAsString(int val);
+ }
+
+ private static final IntToString sUidToString = UserHandle::formatUid;
+ private static final IntToString sIntToString = Integer::toString;
+
+ public static final IntToString[] HISTORY_EVENT_INT_FORMATTERS = new IntToString[] {
+ sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString,
+ sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString,
+ sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString,
+ sUidToString, sUidToString, sUidToString, sIntToString
};
/**
@@ -4975,7 +4993,8 @@
if (checkin) {
pw.print(rec.eventTag.poolIdx);
} else {
- UserHandle.formatUid(pw, rec.eventTag.uid);
+ pw.append(HISTORY_EVENT_INT_FORMATTERS[idx]
+ .applyAsString(rec.eventTag.uid));
pw.print(":\"");
pw.print(rec.eventTag.string);
pw.print("\"");
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 760df45..73c9462 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -762,4 +762,19 @@
public static @Nullable File newFileOrNull(@Nullable String path) {
return (path != null) ? new File(path) : null;
}
+
+ /**
+ * Creates a directory with name {@code name} under an existing directory {@code baseDir}.
+ * Returns a {@code File} object representing the directory on success, {@code null} on
+ * failure.
+ */
+ public static @Nullable File createDir(File baseDir, String name) {
+ final File dir = new File(baseDir, name);
+
+ if (dir.exists()) {
+ return dir.isDirectory() ? dir : null;
+ }
+
+ return dir.mkdir() ? dir : null;
+ }
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 3fc7dba..03fd8d3 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -52,6 +52,7 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
@@ -974,10 +975,17 @@
try (final FileInputStream fis = new FileInputStream(path);
final BufferedReader reader = new BufferedReader(new InputStreamReader(fis));) {
return Long.parseLong(reader.readLine());
- } catch (Exception e) {
- Slog.w(TAG, "readLong(): could not read " + path + ": " + e);
+ } catch (FileNotFoundException e) {
+ // This is expected since we are trying to parse multiple paths.
+ Slog.i(TAG, "readLong(): Path doesn't exist: " + path + ": " + e);
return 0;
- }
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "readLong(): Could not parse " + path + ": " + e);
+ return 0;
+ } catch (Exception e) {
+ Slog.e(TAG, "readLong(): Unknown exception while opening " + path + ": " + e);
+ return 0;
+ }
}
/** @removed */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 43590c7..cede9eb 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6394,13 +6394,6 @@
public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES =
"enabled_notification_policy_access_packages";
- /** @hide */
- public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
-
- /** @hide */
- public static final String VOLUME_CONTROLLER_SERVICE_COMPONENT
- = "volume_controller_service_component";
-
/**
* Defines whether managed profile ringtones should be synced from it's parent profile
* <p>
@@ -6809,7 +6802,8 @@
QS_TILES,
DOZE_ENABLED,
DOZE_PULSE_ON_PICK_UP,
- DOZE_PULSE_ON_DOUBLE_TAP
+ DOZE_PULSE_ON_DOUBLE_TAP,
+ NFC_PAYMENT_DEFAULT_COMPONENT
};
/**
diff --git a/core/java/android/view/IApplicationToken.aidl b/core/java/android/view/IApplicationToken.aidl
index 633b40f..b01c0ef 100644
--- a/core/java/android/view/IApplicationToken.aidl
+++ b/core/java/android/view/IApplicationToken.aidl
@@ -20,10 +20,5 @@
/** {@hide} */
interface IApplicationToken
{
- void windowsDrawn();
- void windowsVisible();
- void windowsGone();
- boolean keyDispatchingTimedOut(String reason);
- long getKeyDispatchingTimeout();
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 21875fe..8611d69 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -83,41 +83,9 @@
void setOverscan(int displayId, int left, int top, int right, int bottom);
// These can only be called when holding the MANAGE_APP_TOKENS permission.
- void pauseKeyDispatching(IBinder token);
- void resumeKeyDispatching(IBinder token);
void setEventDispatching(boolean enabled);
void addWindowToken(IBinder token, int type, int displayId);
void removeWindowToken(IBinder token, int displayId);
- /**
- * Creates the object representation for the application token in the window manager and adds it
- * to the specified task Id.
- *
- * @param addPos The position to add the token to in the task.
- * @param token The token to add.
- * @param taskId The Id of the task we are adding the token to.
- * @param requestedOrientation Orientation to use.
- * @param fullscreen True if the application token is fullscreen.
- * @param showWhenLocked True if the application token should be shown when locked.
- * @param configChanges Input configuration changes.
- * @param voiceInteraction True if the token is in voice interaction mode.
- * @param launchTaskBehind True if the token is been launched from behind.
- * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
- * they are in.
- * @param targetSdkVersion The application's target SDK version
- */
- void addAppToken(int addPos, IApplicationToken token, int taskId, int requestedOrientation,
- boolean fullscreen, boolean showWhenLocked, int configChanges, boolean voiceInteraction,
- boolean launchTaskBehind, boolean alwaysFocusable, int targetSdkVersion,
- int rotationAnimationHint);
- /**
- * Adds an already existing application token on the window manager side to the input task id.
- *
- * @param token The token we are adding to the input task Id.
- * @param taskId The Id of the task we are adding the token to.
- */
- void addAppToTask(IBinder token, int taskId);
- void setAppOrientation(IApplicationToken token, int requestedOrientation);
- int getAppOrientation(IApplicationToken token);
void setFocusedApp(IBinder token, boolean moveFocusNow);
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
int getPendingAppTransition();
@@ -154,20 +122,6 @@
boolean scaleUp);
void executeAppTransition();
- /**
- * Called to set the starting window for the input token and returns true if the starting
- * window was set for the token.
- */
- boolean setAppStartingWindow(IBinder token, String pkg, int theme,
- in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
- int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
- void setAppVisibility(IBinder token, boolean visible);
- void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface);
- void notifyAppStopped(IBinder token);
- void startAppFreezingScreen(IBinder token, int configChanges);
- void stopAppFreezingScreen(IBinder token, boolean force);
- void removeAppToken(IBinder token, int displayId);
-
/** Used by system ui to report that recents has shown itself. */
void endProlongedAnimations();
@@ -315,15 +269,6 @@
boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver);
/**
- * Create a screenshot of the applications currently displayed.
- *
- * @param frameScale the scale to apply to the frame, only used when width = -1 and
- * height = -1
- */
- Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth, int maxHeight,
- float frameScale);
-
- /**
* Called by the status bar to notify Views of changes to System UI visiblity.
*/
oneway void statusBarVisibilityChanged(int visibility);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 7747580..9515040 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -200,8 +200,7 @@
// in mTransformationInfo instead of in RenderNode, so we need to update
// it with the final value here.
if (mRenderProperty == RenderNodeAnimator.ALPHA) {
- // Don't need null check because ViewPropertyAnimator's
- // ctor calls ensureTransformationInfo()
+ mViewTarget.ensureTransformationInfo();
mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index aa941b8..aad7e0a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3394,7 +3394,8 @@
float mTransitionAlpha = 1f;
}
- TransformationInfo mTransformationInfo;
+ /** @hide */
+ public TransformationInfo mTransformationInfo;
/**
* Current clip bounds. to which all drawing of this view are constrained.
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index dd63fef..3213a34 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -169,7 +169,7 @@
*
* @param listener the callback to call on checked state change
*/
- public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
+ public void setOnCheckedChangeListener(@Nullable OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 5623a2c..99a25fd 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -125,7 +125,7 @@
void noteNetworkStatsEnabled();
void noteDeviceIdleMode(int mode, String activeReason, int activeUid);
void setBatteryState(int status, int health, int plugType, int level, int temp, int volt,
- int chargeUAh);
+ int chargeUAh, int chargeFullUAh);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags
index 4364cc3..93d5a03 100644
--- a/core/java/com/android/internal/logging/EventLogTags.logtags
+++ b/core/java/com/android/internal/logging/EventLogTags.logtags
@@ -5,5 +5,6 @@
# interaction logs
524287 sysui_view_visibility (category|1|5),(visible|1|6)
524288 sysui_action (category|1|5),(pkg|3)
+524292 sysui_multi_action (content|4)
524290 sysui_count (name|3),(increment|1)
524291 sysui_histogram (name|3),(bucket|1)
diff --git a/core/java/com/android/internal/logging/LogBuilder.java b/core/java/com/android/internal/logging/LogBuilder.java
new file mode 100644
index 0000000..634d061
--- /dev/null
+++ b/core/java/com/android/internal/logging/LogBuilder.java
@@ -0,0 +1,67 @@
+package com.android.internal.logging;
+
+import android.util.EventLog;
+import android.util.SparseArray;
+import android.view.View;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+
+/**
+ * Helper class to assemble more complex logs.
+ *
+ * @hide
+ */
+
+public class LogBuilder {
+
+ private SparseArray<Object> entries = new SparseArray();
+
+ public LogBuilder() {}
+
+
+ public LogBuilder setView(View view) {
+ entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VIEW, view.getId());
+ return this;
+ }
+
+ public LogBuilder setCategory(int category) {
+ entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY, category);
+ return this;
+ }
+
+ public LogBuilder setType(int type) {
+ entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_TYPE, type);
+ return this;
+ }
+
+ /**
+ * @param tag From your MetricsEvent enum.
+ * @param value One of Integer, Long, Float, String
+ * @return
+ */
+ public LogBuilder addTaggedData(int tag, Object value) {
+ if (!(value instanceof Integer ||
+ value instanceof String ||
+ value instanceof Long ||
+ value instanceof Float)) {
+ throw new IllegalArgumentException(
+ "Value must be loggable type - int, long, float, String");
+ }
+ entries.put(tag, value);
+ return this;
+ }
+
+ /**
+ * Assemble logs into structure suitable for EventLog.
+ */
+ public Object[] serialize() {
+ Object[] out = new Object[entries.size() * 2];
+ for (int i = 0; i < entries.size(); i++) {
+ out[i * 2] = entries.keyAt(i);
+ out[i * 2 + 1] = entries.valueAt(i);
+ }
+ return out;
+ }
+}
+
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index a94f308..5eb39ae 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -17,10 +17,12 @@
import android.content.Context;
import android.os.Build;
+import android.util.EventLog;
import android.view.View;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
/**
* Log all the things.
*
@@ -71,6 +73,14 @@
action(context, category, Boolean.toString(value));
}
+ public static void action(LogBuilder content) {
+ //EventLog.writeEvent(524292, content.serialize());
+ // Below would be the *right* way to do this, using the generated
+ // EventLogTags method, but that doesn't work.
+ EventLogTags.writeSysuiMultiAction(content.serialize());
+ }
+
+
public static void action(Context context, int category, String pkg) {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
throw new IllegalArgumentException("Must define metric category");
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5d49d12..5fd68e6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -559,6 +559,10 @@
private int mEstimatedBatteryCapacity = -1;
+ // Last learned capacity reported by BatteryService in
+ // setBatteryState().
+ private int mLastChargeFullUAh = 0;
+
private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
private PowerProfile mPowerProfile;
@@ -9818,7 +9822,7 @@
public static final int BATTERY_PLUGGED_NONE = 0;
public void setBatteryStateLocked(int status, int health, int plugType, int level,
- int temp, int volt, int chargeUAh) {
+ int temp, int volt, int chargeUAh, int chargeFullUAh) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
final long uptime = mClocks.uptimeMillis();
final long elapsedRealtime = mClocks.elapsedRealtime();
@@ -9980,6 +9984,16 @@
// The next time we are unplugged, history will be cleared.
mRecordingHistory = DEBUG;
}
+
+ if (differsByMoreThan(chargeFullUAh, mLastChargeFullUAh, 100)) {
+ mLastChargeFullUAh = chargeFullUAh;
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ESTIMATED_BATTERY_CAP,
+ "", chargeFullUAh / 1000);
+ }
+ }
+
+ private static boolean differsByMoreThan(int left, int right, int diff) {
+ return Math.abs(left - right) > diff;
}
public long getAwakeTimeBattery() {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 96492e2..4ba19f4 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -24,6 +24,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
+import android.graphics.drawable.Drawable;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
@@ -143,6 +144,10 @@
private PatternExploreByTouchHelper mExploreByTouchHelper;
private AudioManager mAudioManager;
+ private Drawable mSelectedDrawable;
+ private Drawable mNotSelectedDrawable;
+ private boolean mUseLockPatternDrawable;
+
/**
* Represents a cell in the 3 X 3 matrix of the unlock pattern view.
*/
@@ -314,6 +319,12 @@
mDotSizeActivated = getResources().getDimensionPixelSize(
R.dimen.lock_pattern_dot_size_activated);
+ mUseLockPatternDrawable = getResources().getBoolean(R.bool.use_lock_pattern_drawable);
+ if (mUseLockPatternDrawable) {
+ mSelectedDrawable = getResources().getDrawable(R.drawable.lockscreen_selected);
+ mNotSelectedDrawable = getResources().getDrawable(R.drawable.lockscreen_notselected);
+ }
+
mPaint.setAntiAlias(true);
mPaint.setDither(true);
@@ -621,6 +632,11 @@
final int height = h - mPaddingTop - mPaddingBottom;
mSquareHeight = height / 3.0f;
mExploreByTouchHelper.invalidateRoot();
+
+ if (mUseLockPatternDrawable) {
+ mNotSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height);
+ mSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height);
+ }
}
private int resolveMeasured(int measureSpec, int desired)
@@ -1095,14 +1111,18 @@
CellState cellState = mCellStates[i][j];
float centerX = getCenterXForColumn(j);
float translationY = cellState.translationY;
- if (isHardwareAccelerated() && cellState.hwAnimating) {
- DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
- displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
- cellState.hwRadius, cellState.hwPaint);
- } else {
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- cellState.radius, drawLookup[i][j], cellState.alpha);
+ if (mUseLockPatternDrawable) {
+ drawCellDrawable(canvas, i, j, cellState.radius, drawLookup[i][j]);
+ } else {
+ if (isHardwareAccelerated() && cellState.hwAnimating) {
+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+ displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
+ cellState.hwRadius, cellState.hwPaint);
+ } else {
+ drawCircle(canvas, (int) centerX, (int) centerY + translationY,
+ cellState.radius, drawLookup[i][j], cellState.alpha);
+ }
}
}
}
@@ -1193,6 +1213,30 @@
canvas.drawCircle(centerX, centerY, radius, mPaint);
}
+ /**
+ * @param partOfPattern Whether this circle is part of the pattern.
+ */
+ private void drawCellDrawable(Canvas canvas, int i, int j, float radius,
+ boolean partOfPattern) {
+ Rect dst = new Rect(
+ (int) (mPaddingLeft + j * mSquareWidth),
+ (int) (mPaddingTop + i * mSquareHeight),
+ (int) (mPaddingLeft + (j + 1) * mSquareWidth),
+ (int) (mPaddingTop + (i + 1) * mSquareHeight));
+ float scale = radius / (mDotSize / 2);
+
+ // Only draw on this square with the appropriate scale.
+ canvas.save();
+ canvas.clipRect(dst);
+ canvas.scale(scale, scale, dst.centerX(), dst.centerY());
+ if (!partOfPattern || scale > 1) {
+ mNotSelectedDrawable.draw(canvas);
+ } else {
+ mSelectedDrawable.draw(canvas);
+ }
+ canvas.restore();
+ }
+
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 252f168..29483c7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -60,7 +60,6 @@
android_graphics_drawable_VectorDrawable.cpp \
android_view_DisplayEventReceiver.cpp \
android_view_DisplayListCanvas.cpp \
- android_view_GraphicBuffer.cpp \
android_view_HardwareLayer.cpp \
android_view_InputChannel.cpp \
android_view_InputDevice.cpp \
@@ -120,6 +119,7 @@
android/graphics/FontFamily.cpp \
android/graphics/CreateJavaOutputStreamAdaptor.cpp \
android/graphics/GIFMovie.cpp \
+ android/graphics/GraphicBuffer.cpp \
android/graphics/Graphics.cpp \
android/graphics/HarfBuzzNGFaceSkia.cpp \
android/graphics/Interpolator.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6c9a764..c195cfe 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -57,6 +57,7 @@
extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
extern int register_android_graphics_Camera(JNIEnv* env);
extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
+extern int register_android_graphics_GraphicBuffer(JNIEnv* env);
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_Interpolator(JNIEnv* env);
extern int register_android_graphics_MaskFilter(JNIEnv* env);
@@ -134,7 +135,6 @@
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_DisplayListCanvas(JNIEnv* env);
-extern int register_android_view_GraphicBuffer(JNIEnv* env);
extern int register_android_view_HardwareLayer(JNIEnv* env);
extern int register_android_view_RenderNode(JNIEnv* env);
extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
@@ -1296,7 +1296,6 @@
REG_JNI(register_android_view_DisplayEventReceiver),
REG_JNI(register_android_view_RenderNode),
REG_JNI(register_android_view_RenderNodeAnimator),
- REG_JNI(register_android_view_GraphicBuffer),
REG_JNI(register_android_view_DisplayListCanvas),
REG_JNI(register_android_view_HardwareLayer),
REG_JNI(register_android_view_ThreadedRenderer),
@@ -1328,6 +1327,7 @@
REG_JNI(register_android_graphics_ColorFilter),
REG_JNI(register_android_graphics_DrawFilter),
REG_JNI(register_android_graphics_FontFamily),
+ REG_JNI(register_android_graphics_GraphicBuffer),
REG_JNI(register_android_graphics_Interpolator),
REG_JNI(register_android_graphics_MaskFilter),
REG_JNI(register_android_graphics_Matrix),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 59cbc93..2bde991 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,6 +1,7 @@
#define LOG_TAG "Bitmap"
#include "Bitmap.h"
+#include "GraphicBuffer.h"
#include "SkBitmap.h"
#include "SkPixelRef.h"
#include "SkImageEncoder.h"
@@ -1291,7 +1292,7 @@
return static_cast<jint>(bitmapHandle->getAllocationByteCount());
}
-static jobject Bitmap_nativeCopyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
+static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
LocalScopedBitmap bitmapHandle(bitmapPtr);
LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
"Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
@@ -1308,6 +1309,26 @@
return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None);
}
+static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
+ sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
+ sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
+ if (!bitmap.get()) {
+ ALOGW("failed to create hardware bitmap from graphic buffer");
+ return NULL;
+ }
+ return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
+}
+
+static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
+ LocalScopedBitmap bitmapHandle(bitmapPtr);
+ LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
+ "Hardware config is only supported config in Bitmap_getGraphicBuffer");
+
+ Bitmap& hwuiBitmap = bitmapHandle->bitmap();
+ sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer());
+ return createJavaGraphicBuffer(env, buffer);
+}
+
///////////////////////////////////////////////////////////////////////////////
static jclass make_globalref(JNIEnv* env, const char classname[])
{
@@ -1367,7 +1388,11 @@
{ "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
{ "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
{ "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
- (void*)Bitmap_nativeCopyPreserveInternalConfig },
+ (void*)Bitmap_copyPreserveInternalConfig },
+ { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
+ (void*) Bitmap_createHardwareBitmap },
+ { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
+ (void*) Bitmap_createGraphicBufferHandle }
};
int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android/graphics/GraphicBuffer.cpp
similarity index 81%
rename from core/jni/android_view_GraphicBuffer.cpp
rename to core/jni/android/graphics/GraphicBuffer.cpp
index f18837f..c61b53e 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android/graphics/GraphicBuffer.cpp
@@ -20,9 +20,8 @@
#include "JNIHelp.h"
#include "android_os_Parcel.h"
-#include "android_view_GraphicBuffer.h"
-#include "android/graphics/GraphicsJNI.h"
-#include "Bitmap.h"
+#include "GraphicBuffer.h"
+#include "GraphicsJNI.h"
#include <android_runtime/AndroidRuntime.h>
@@ -59,6 +58,8 @@
static struct {
jfieldID mNativeObject;
+ jclass mClass;
+ jmethodID mConstructorMethodID;
} gGraphicBufferClassInfo;
static struct {
@@ -100,7 +101,7 @@
// GraphicBuffer lifecycle
// ----------------------------------------------------------------------------
-static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz,
+static jlong android_graphics_GraphicBuffer_create(JNIEnv* env, jobject clazz,
jint width, jint height, jint format, jint usage) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -125,7 +126,7 @@
return reinterpret_cast<jlong>(wrapper);
}
-static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz,
+static void android_graphics_GraphicBuffer_destroy(JNIEnv* env, jobject clazz,
jlong wrapperHandle) {
GraphicBufferWrapper* wrapper =
reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
@@ -151,7 +152,7 @@
}
}
-static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
+static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
GraphicBufferWrapper* wrapper =
@@ -209,7 +210,7 @@
return JNI_TRUE;
}
-static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
+static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
jlong wrapperHandle, jobject canvas) {
GraphicBufferWrapper* wrapper =
@@ -229,7 +230,7 @@
// Serialization
// ----------------------------------------------------------------------------
-static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz,
+static void android_graphics_GraphicBuffer_write(JNIEnv* env, jobject clazz,
jlong wrapperHandle, jobject dest) {
GraphicBufferWrapper* wrapper =
reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
@@ -239,7 +240,7 @@
}
}
-static jlong android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz,
+static jlong android_graphics_GraphicBuffer_read(JNIEnv* env, jobject clazz,
jobject in) {
Parcel* parcel = parcelForJavaObject(env, in);
@@ -252,17 +253,6 @@
return NULL;
}
-static jobject android_view_GraphicBuffer_createHardwareBitmap(JNIEnv* env, jobject,
- jlong wrapperHandle) {
- GraphicBufferWrapper* wrapper = reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
- sk_sp<Bitmap> bitmap = Bitmap::createFrom(wrapper->buffer);
- if (!bitmap.get()) {
- ALOGW("failed to create hardware bitmap from graphic buffer");
- return NULL;
- }
- return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
-}
-
// ----------------------------------------------------------------------------
// External helpers
// ----------------------------------------------------------------------------
@@ -279,35 +269,46 @@
return NULL;
}
+jobject createJavaGraphicBuffer(JNIEnv* env, const sp<GraphicBuffer>& buffer) {
+ GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
+ jobject obj = env->NewObject(gGraphicBufferClassInfo.mClass,
+ gGraphicBufferClassInfo.mConstructorMethodID, buffer->getWidth(), buffer->getHeight(),
+ buffer->getPixelFormat(), buffer->getUsage(), reinterpret_cast<jlong>(wrapper));
+ return obj;
+}
+
+};
+
+using namespace android;
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
-const char* const kClassPathName = "android/view/GraphicBuffer";
+const char* const kClassPathName = "android/graphics/GraphicBuffer";
static const JNINativeMethod gMethods[] = {
- { "nCreateGraphicBuffer", "(IIII)J", (void*) android_view_GraphiceBuffer_create },
- { "nDestroyGraphicBuffer", "(J)V", (void*) android_view_GraphiceBuffer_destroy },
+ { "nCreateGraphicBuffer", "(IIII)J", (void*) android_graphics_GraphicBuffer_create },
+ { "nDestroyGraphicBuffer", "(J)V", (void*) android_graphics_GraphicBuffer_destroy },
{ "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V",
- (void*) android_view_GraphiceBuffer_write },
+ (void*) android_graphics_GraphicBuffer_write },
{ "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J",
- (void*) android_view_GraphiceBuffer_read },
+ (void*) android_graphics_GraphicBuffer_read },
{ "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
- (void*) android_view_GraphicBuffer_lockCanvas },
+ (void*) android_graphics_GraphicBuffer_lockCanvas },
{ "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
- (void*) android_view_GraphicBuffer_unlockCanvasAndPost },
- { "nCreateHardwareBitmap", "(J)Landroid/graphics/Bitmap;",
- (void*) android_view_GraphicBuffer_createHardwareBitmap
- }
+ (void*) android_graphics_GraphicBuffer_unlockCanvasAndPost }
};
-int register_android_view_GraphicBuffer(JNIEnv* env) {
- jclass clazz = FindClassOrDie(env, "android/view/GraphicBuffer");
- gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J");
+int register_android_graphics_GraphicBuffer(JNIEnv* env) {
+ gGraphicBufferClassInfo.mClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kClassPathName));
+ gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, gGraphicBufferClassInfo.mClass,
+ "mNativeObject", "J");
+ gGraphicBufferClassInfo.mConstructorMethodID = env->GetMethodID(gGraphicBufferClassInfo.mClass,
+ "<init>", "(IIIIJ)V");
- clazz = FindClassOrDie(env, "android/graphics/Rect");
+ jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
@@ -315,6 +316,4 @@
gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
-}
-
-};
+}
\ No newline at end of file
diff --git a/core/jni/android_view_GraphicBuffer.h b/core/jni/android/graphics/GraphicBuffer.h
similarity index 91%
rename from core/jni/android_view_GraphicBuffer.h
rename to core/jni/android/graphics/GraphicBuffer.h
index 509587c..0d72669 100644
--- a/core/jni/android_view_GraphicBuffer.h
+++ b/core/jni/android/graphics/GraphicBuffer.h
@@ -24,4 +24,6 @@
// object must be an instance of android.view.GraphicBuffer
extern sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj);
+jobject createJavaGraphicBuffer(JNIEnv* env, const sp<GraphicBuffer>& buffer);
+
}
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index be9449b..9ce5670 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -219,13 +219,6 @@
return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}
-static jboolean clipRegion(JNIEnv* env, jobject, jlong canvasHandle, jlong deviceRgnHandle,
- jint opHandle) {
- SkRegion* deviceRgn = reinterpret_cast<SkRegion*>(deviceRgnHandle);
- bool nonEmptyClip = get_canvas(canvasHandle)->clipRegion(deviceRgn, opHandleToClipOp(opHandle));
- return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
-}
-
static void drawColor(JNIEnv* env, jobject, jlong canvasHandle, jint color, jint modeHandle) {
SkBlendMode mode = static_cast<SkBlendMode>(modeHandle);
get_canvas(canvasHandle)->drawColor(color, mode);
@@ -616,7 +609,6 @@
{"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
{"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
{"nClipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
- {"nClipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
{"nSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
};
diff --git a/core/jni/android_hardware_Radio.cpp b/core/jni/android_hardware_Radio.cpp
index 42ceec4..397e67b 100644
--- a/core/jni/android_hardware_Radio.cpp
+++ b/core/jni/android_hardware_Radio.cpp
@@ -313,12 +313,14 @@
ALOGV("%s", __FUNCTION__);
int jStatus;
jobject jMetadata = NULL;
- if (nProgramInfo->metadata != NULL) {
- ALOGV("%s metadata %p", __FUNCTION__, nProgramInfo->metadata);
- jStatus = convertMetadataFromNative(env, &jMetadata, nProgramInfo->metadata);
- if (jStatus < 0) {
- return jStatus;
- }
+
+ if (nProgramInfo == nullptr || nProgramInfo->metadata == nullptr) {
+ return (jint)RADIO_STATUS_BAD_VALUE;
+ }
+
+ jStatus = convertMetadataFromNative(env, &jMetadata, nProgramInfo->metadata);
+ if (jStatus < 0) {
+ return jStatus;
}
ALOGV("%s channel %d tuned %d", __FUNCTION__, nProgramInfo->channel, nProgramInfo->tuned);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 14dcb3f..c00bcd4 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -36,7 +36,6 @@
#include <android_runtime/android_view_Surface.h>
#include <system/window.h>
-#include "android_view_GraphicBuffer.h"
#include "android_os_MessageQueue.h"
#include <Animator.h>
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4b4fd84..48805d8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -480,6 +480,9 @@
<protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
<protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+ <protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
+ <protected-broadcast android:name="android.accounts.action.ACCOUNTS_LISTENER_PACKAGE_INSTALLED" />
+
<protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
<protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
@@ -1259,7 +1262,7 @@
recommendations and scores from the NetworkScoreService.
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.REQUEST_NETWORK_SCORES"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature" />
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
diff --git a/core/res/res/drawable/lockscreen_notselected.xml b/core/res/res/drawable/lockscreen_notselected.xml
new file mode 100644
index 0000000..eecea13
--- /dev/null
+++ b/core/res/res/drawable/lockscreen_notselected.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="260dp"
+ android:height="260dp"
+ android:viewportWidth="260"
+ android:viewportHeight="260">
+
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 43.3333 34.3333 C 48.3038627485 34.3333 52.3333 38.3627372515 52.3333 43.3333 C 52.3333 48.3038627485 48.3038627485 52.3333 43.3333 52.3333 C 38.3627372515 52.3333 34.3333 48.3038627485 34.3333 43.3333 C 34.3333 38.3627372515 38.3627372515 34.3333 43.3333 34.3333 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 43.3333 121 C 48.3038627485 121 52.3333 125.029437252 52.3333 130 C 52.3333 134.970562748 48.3038627485 139 43.3333 139 C 38.3627372515 139 34.3333 134.970562748 34.3333 130 C 34.3333 125.029437252 38.3627372515 121 43.3333 121 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 43.3333 207.6667 C 48.3038627485 207.6667 52.3333 211.696137252 52.3333 216.6667 C 52.3333 221.637262748 48.3038627485 225.6667 43.3333 225.6667 C 38.3627372515 225.6667 34.3333 221.637262748 34.3333 216.6667 C 34.3333 211.696137252 38.3627372515 207.6667 43.3333 207.6667 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 130 34.3333 C 134.970562748 34.3333 139 38.3627372515 139 43.3333 C 139 48.3038627485 134.970562748 52.3333 130 52.3333 C 125.029437252 52.3333 121 48.3038627485 121 43.3333 C 121 38.3627372515 125.029437252 34.3333 130 34.3333 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 130 121 C 134.970562748 121 139 125.029437252 139 130 C 139 134.970562748 134.970562748 139 130 139 C 125.029437252 139 121 134.970562748 121 130 C 121 125.029437252 125.029437252 121 130 121 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 130 207.6667 C 134.970562748 207.6667 139 211.696137252 139 216.6667 C 139 221.637262748 134.970562748 225.6667 130 225.6667 C 125.029437252 225.6667 121 221.637262748 121 216.6667 C 121 211.696137252 125.029437252 207.6667 130 207.6667 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 216.6667 34.3333 C 221.637262748 34.3333 225.6667 38.3627372515 225.6667 43.3333 C 225.6667 48.3038627485 221.637262748 52.3333 216.6667 52.3333 C 211.696137252 52.3333 207.6667 48.3038627485 207.6667 43.3333 C 207.6667 38.3627372515 211.696137252 34.3333 216.6667 34.3333 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 216.6667 121 C 221.637262748 121 225.6667 125.029437252 225.6667 130 C 225.6667 134.970562748 221.637262748 139 216.6667 139 C 211.696137252 139 207.6667 134.970562748 207.6667 130 C 207.6667 125.029437252 211.696137252 121 216.6667 121 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 216.6667 207.6667 C 221.637262748 207.6667 225.6667 211.696137252 225.6667 216.6667 C 225.6667 221.637262748 221.637262748 225.6667 216.6667 225.6667 C 211.696137252 225.6667 207.6667 221.637262748 207.6667 216.6667 C 207.6667 211.696137252 211.696137252 207.6667 216.6667 207.6667 Z" />
+</vector>
diff --git a/core/res/res/drawable/lockscreen_selected.xml b/core/res/res/drawable/lockscreen_selected.xml
new file mode 100644
index 0000000..eecea13
--- /dev/null
+++ b/core/res/res/drawable/lockscreen_selected.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="260dp"
+ android:height="260dp"
+ android:viewportWidth="260"
+ android:viewportHeight="260">
+
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 43.3333 34.3333 C 48.3038627485 34.3333 52.3333 38.3627372515 52.3333 43.3333 C 52.3333 48.3038627485 48.3038627485 52.3333 43.3333 52.3333 C 38.3627372515 52.3333 34.3333 48.3038627485 34.3333 43.3333 C 34.3333 38.3627372515 38.3627372515 34.3333 43.3333 34.3333 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 43.3333 121 C 48.3038627485 121 52.3333 125.029437252 52.3333 130 C 52.3333 134.970562748 48.3038627485 139 43.3333 139 C 38.3627372515 139 34.3333 134.970562748 34.3333 130 C 34.3333 125.029437252 38.3627372515 121 43.3333 121 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 43.3333 207.6667 C 48.3038627485 207.6667 52.3333 211.696137252 52.3333 216.6667 C 52.3333 221.637262748 48.3038627485 225.6667 43.3333 225.6667 C 38.3627372515 225.6667 34.3333 221.637262748 34.3333 216.6667 C 34.3333 211.696137252 38.3627372515 207.6667 43.3333 207.6667 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 130 34.3333 C 134.970562748 34.3333 139 38.3627372515 139 43.3333 C 139 48.3038627485 134.970562748 52.3333 130 52.3333 C 125.029437252 52.3333 121 48.3038627485 121 43.3333 C 121 38.3627372515 125.029437252 34.3333 130 34.3333 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 130 121 C 134.970562748 121 139 125.029437252 139 130 C 139 134.970562748 134.970562748 139 130 139 C 125.029437252 139 121 134.970562748 121 130 C 121 125.029437252 125.029437252 121 130 121 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 130 207.6667 C 134.970562748 207.6667 139 211.696137252 139 216.6667 C 139 221.637262748 134.970562748 225.6667 130 225.6667 C 125.029437252 225.6667 121 221.637262748 121 216.6667 C 121 211.696137252 125.029437252 207.6667 130 207.6667 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 216.6667 34.3333 C 221.637262748 34.3333 225.6667 38.3627372515 225.6667 43.3333 C 225.6667 48.3038627485 221.637262748 52.3333 216.6667 52.3333 C 211.696137252 52.3333 207.6667 48.3038627485 207.6667 43.3333 C 207.6667 38.3627372515 211.696137252 34.3333 216.6667 34.3333 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 216.6667 121 C 221.637262748 121 225.6667 125.029437252 225.6667 130 C 225.6667 134.970562748 221.637262748 139 216.6667 139 C 211.696137252 139 207.6667 134.970562748 207.6667 130 C 207.6667 125.029437252 211.696137252 121 216.6667 121 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M 216.6667 207.6667 C 221.637262748 207.6667 225.6667 211.696137252 225.6667 216.6667 C 225.6667 221.637262748 221.637262748 225.6667 216.6667 225.6667 C 211.696137252 225.6667 207.6667 221.637262748 207.6667 216.6667 C 207.6667 211.696137252 211.696137252 207.6667 216.6667 207.6667 Z" />
+</vector>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 5c50e73..b49fe49 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -24,4 +24,10 @@
<bool name="show_ongoing_ime_switcher">true</bool>
<bool name="action_bar_expanded_action_views_exclusive">true</bool>
<bool name="target_honeycomb_needs_options_menu">true</bool>
+ <!-- Whether or not to use the drawable/lockscreen_notselected and
+ drawable/lockscreen_selected instead of the generic dots when displaying
+ the LockPatternView.
+ <p>The main purpose is for OEMs to customize the rendering of the
+ lockscreen, setting this to true should come with customized drawables. -->
+ <bool name="use_lock_pattern_drawable">false</bool>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5967c69..9cbb8c3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1260,9 +1260,8 @@
<!-- A list of potential packages, in priority order, that may contain a
network recommendation provider. A network recommendation provider must:
* Be granted the SCORE_NETWORKS permission.
- * Include a Receiver for the android.net.scoring.SCORE_NETWORKS action guarded by the
- BROADCAST_NETWORK_PRIVILEGED permission.
- * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action.
+ * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action
+ protected by the BIND_NETWORK_RECOMMENDATION_SERVICE permission.
This may be empty if network scoring and recommending isn't supported.
-->
@@ -2697,4 +2696,7 @@
<!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
<bool name="config_allow3rdPartyAppOnInternal">true</bool>
+
+ <!-- Component name of the default cell broadcast receiver -->
+ <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 880944e..b7f5a9b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4135,7 +4135,7 @@
<string name="date_picker_day_typeface">sans-serif-medium</string>
<!-- Notify use that they are in Lock-to-app -->
- <string name="lock_to_app_toast">To unpin this screen, touch & hold Back.</string>
+ <string name="lock_to_app_toast">To unpin this screen, touch & hold Back and Overview.</string>
<!-- Notify user that they are locked in lock-to-app mode -->
<string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string>
<!-- Starting lock-to-app indication. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 95de54b..cd3c0e3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2775,4 +2775,10 @@
<!-- Whether allow 3rd party apps on internal storage. -->
<java-symbol type="bool" name="config_allow3rdPartyAppOnInternal" />
+
+ <java-symbol type="bool" name="use_lock_pattern_drawable" />
+ <java-symbol type="drawable" name="lockscreen_notselected" />
+ <java-symbol type="drawable" name="lockscreen_selected" />
+
+ <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
</resources>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index cd41987..e3a85b5 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1107,6 +1107,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.app.Activity" android:label="Empty Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<!-- Activity-level metadata -->
<meta-data android:name="com.android.frameworks.coretests.isApp" android:value="true" />
<meta-data android:name="com.android.frameworks.coretests.string" android:value="foo" />
diff --git a/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
new file mode 100644
index 0000000..b52d98c
--- /dev/null
+++ b/core/tests/coretests/src/android/view/RenderNodeAnimatorTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.app.Activity;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@MediumTest
+public class RenderNodeAnimatorTest {
+ @Rule
+ public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+
+ private Context getContext() {
+ return InstrumentationRegistry.getTargetContext();
+ }
+
+ private Activity getActivity() {
+ return mActivityRule.getActivity();
+ }
+
+ @UiThreadTest
+ @Test
+ public void testAlphaTransformationInfo() throws Throwable {
+ View view = new View(getContext());
+
+ // attach the view, since otherwise the RenderNodeAnimator won't accept view as target
+ getActivity().setContentView(view);
+
+ RenderNodeAnimator anim = new RenderNodeAnimator(RenderNodeAnimator.ALPHA, 0.5f);
+ anim.setTarget(view);
+ assertNull(view.mTransformationInfo);
+ anim.start(); // should initialize mTransformationInfo
+ assertNotNull(view.mTransformationInfo);
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
new file mode 100644
index 0000000..e7d23a8
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
@@ -0,0 +1,43 @@
+package com.android.internal.logging;
+
+import junit.framework.TestCase;
+
+public class LogBuilderTest extends TestCase {
+
+ public void testSerialize() {
+ LogBuilder builder = new LogBuilder();
+ builder.addTaggedData(1, "one");
+ builder.addTaggedData(2, "two");
+ Object[] out = builder.serialize();
+ assertEquals(1, out[0]);
+ assertEquals("one", out[1]);
+ assertEquals(2, out[2]);
+ assertEquals("two", out[3]);
+ }
+
+ public void testInvalidInputThrows() {
+ LogBuilder builder = new LogBuilder();
+ boolean threw = false;
+ try {
+ builder.addTaggedData(0, new Object());
+ } catch (IllegalArgumentException e) {
+ threw = true;
+ }
+ assertTrue(threw);
+ assertEquals(0, builder.serialize().length);
+ }
+
+ public void testValidInputTypes() {
+ LogBuilder builder = new LogBuilder();
+ builder.addTaggedData(1, "onetwothree");
+ builder.addTaggedData(2, 123);
+ builder.addTaggedData(3, 123L);
+ builder.addTaggedData(4, 123.0F);
+ Object[] out = builder.serialize();
+ assertEquals("onetwothree", out[1]);
+ assertEquals(123, out[3]);
+ assertEquals(123L, out[5]);
+ assertEquals(123.0F, out[7]);
+ }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 9b2b9f1..836ede6 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -23,7 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
LOCAL_PACKAGE_NAME := MultiDexLegacyAndException
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 874263f..2915914 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -23,7 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp
@@ -45,7 +45,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 8
LOCAL_PACKAGE_NAME := MultiDexLegacyTestApp2
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index a259937..ba7f05d 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -655,6 +655,17 @@
}
/**
+ * Create hardware bitmap backed GraphicBuffer.
+ *
+ * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat.
+ * currently PIXEL_FORMAT_RGBA_8888 is the only supported format
+ * @hide
+ */
+ public static Bitmap createHardwareBitmap(GraphicBuffer graphicBuffer) {
+ return nativeCreateHardwareBitmap(graphicBuffer);
+ }
+
+ /**
* Creates a new bitmap, scaled from an existing bitmap, when possible. If the
* specified width and height are the same as the current width and height of
* the source bitmap, the source bitmap is returned and no new bitmap is
@@ -1735,6 +1746,15 @@
nativePrepareToDraw(mNativePtr);
}
+ /**
+ *
+ * @return {@link GraphicBuffer} which is internally used by hardware bitmap
+ * @hide
+ */
+ public GraphicBuffer createGraphicBufferHandle() {
+ return nativeCreateGraphicBufferHandle(mNativePtr);
+ }
+
//////////// native methods
private static native Bitmap nativeCreate(int[] colors, int offset,
@@ -1794,4 +1814,6 @@
private static native void nativePrepareToDraw(long nativeBitmap);
private static native int nativeGetAllocationByteCount(long nativeBitmap);
private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
+ private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
+ private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index b093458..cc5cc7b 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -801,12 +801,13 @@
* @param op How the clip is modified
* @return true if the resulting is non-empty
*
+ * @removed
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
@Deprecated
public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
- return nClipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
+ return false;
}
/**
@@ -819,12 +820,13 @@
* @param region The region to operate on the current clip, based on op
* @return true if the resulting is non-empty
*
+ * @removed
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
@Deprecated
public boolean clipRegion(@NonNull Region region) {
- return clipRegion(region, Region.Op.INTERSECT);
+ return false;
}
public @Nullable DrawFilter getDrawFilter() {
@@ -1115,10 +1117,6 @@
long nativePath,
int regionOp);
@FastNative
- private static native boolean nClipRegion(long nativeCanvas,
- long nativeRegion,
- int regionOp);
- @FastNative
private static native void nSetDrawFilter(long nativeCanvas,
long nativeFilter);
@FastNative
diff --git a/core/java/android/view/GraphicBuffer.aidl b/graphics/java/android/graphics/GraphicBuffer.aidl
similarity index 95%
rename from core/java/android/view/GraphicBuffer.aidl
rename to graphics/java/android/graphics/GraphicBuffer.aidl
index 6dc6bed..134699a 100644
--- a/core/java/android/view/GraphicBuffer.aidl
+++ b/graphics/java/android/graphics/GraphicBuffer.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.view;
+package android.graphics;
parcelable GraphicBuffer;
diff --git a/core/java/android/view/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java
similarity index 93%
rename from core/java/android/view/GraphicBuffer.java
rename to graphics/java/android/graphics/GraphicBuffer.java
index 64611d0..3be9216 100644
--- a/core/java/android/view/GraphicBuffer.java
+++ b/graphics/java/android/graphics/GraphicBuffer.java
@@ -14,12 +14,8 @@
* limitations under the License.
*/
-package android.view;
+package android.graphics;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -265,16 +261,6 @@
nWriteGraphicBufferToParcel(mNativeObject, dest);
}
- /**
- * Create hardware bitmap backed by this GraphicBuffer.
- *
- * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat.
- * currently PIXEL_FORMAT_RGBA_8888 is the only supported format
- */
- public Bitmap createHardwareBitmap() {
- return nCreateHardwareBitmap(mNativeObject);
- }
-
public static final Parcelable.Creator<GraphicBuffer> CREATOR =
new Parcelable.Creator<GraphicBuffer>() {
public GraphicBuffer createFromParcel(Parcel in) {
@@ -300,5 +286,4 @@
private static native long nReadGraphicBufferFromParcel(Parcel in);
private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty);
private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas);
- private static native Bitmap nCreateHardwareBitmap(long nativeObject);
}
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index f5aef05..d433b90 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -418,8 +418,10 @@
out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
out_values[STYLE_DENSITY] = config.density;
- if (out_indices != nullptr && value.dataType != Res_value::TYPE_NULL) {
+ if (value.dataType != Res_value::TYPE_NULL) {
indices_idx++;
+
+ // out_indices must NOT be nullptr.
out_indices[indices_idx] = ii;
}
@@ -428,9 +430,8 @@
res.unlock();
- if (out_indices != nullptr) {
- out_indices[0] = indices_idx;
- }
+ // out_indices must NOT be nullptr.
+ out_indices[0] = indices_idx;
}
bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 8d5ff46..69b76041 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -40,14 +40,20 @@
// TODO(adamlesinski): Run performance tests against these methods and a new, single method
// that uses all the sources and branches to the right ones within the inner loop.
+// `out_values` must NOT be nullptr.
+// `out_indices` may be nullptr.
bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
+// `out_values` must NOT be nullptr.
+// `out_indices` is NOT optional and must NOT be nullptr.
void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
uint32_t* out_values, uint32_t* out_indices);
+// `out_values` must NOT be nullptr.
+// `out_indices` may be nullptr.
bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index d417aba..7550517 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -16,6 +16,8 @@
#include "androidfw/AttributeResolution.h"
+#include <array>
+
#include "android-base/file.h"
#include "android-base/logging.h"
#include "android-base/macros.h"
@@ -67,15 +69,13 @@
ResTable::Theme theme(table_);
ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
- uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
- R::attr::attr_four};
- std::vector<uint32_t> values;
- values.resize(arraysize(attrs) * 6);
+ std::array<uint32_t, 4> attrs{
+ {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+ std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
- nullptr /*src_values*/, 0 /*src_values_length*/,
- attrs, arraysize(attrs), values.data(),
- nullptr /*out_indices*/));
+ nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
+ attrs.size(), values.data(), nullptr /*out_indices*/));
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
@@ -112,13 +112,12 @@
}
TEST_F(AttributeResolutionXmlTest, XmlParser) {
- uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
- R::attr::attr_four};
- std::vector<uint32_t> values;
- values.resize(arraysize(attrs) * 6);
+ std::array<uint32_t, 4> attrs{
+ {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four}};
+ std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
- ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs, arraysize(attrs),
- values.data(), nullptr /*out_indices*/));
+ ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
+ nullptr /*out_indices*/));
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -157,14 +156,13 @@
ResTable::Theme theme(table_);
ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
- uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
- R::attr::attr_four, R::attr::attr_five};
- std::vector<uint32_t> values;
- values.resize(arraysize(attrs) * 6);
+ std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+ R::attr::attr_four, R::attr::attr_five}};
+ std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
+ std::array<uint32_t, attrs.size()> indices;
- ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/,
- 0 /*def_style_res*/, attrs, arraysize(attrs),
- values.data(), nullptr /*out_indices*/);
+ ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
+ attrs.size(), values.data(), indices.data());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index dbbf00d..9c068b0 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -212,11 +212,6 @@
return !mSnapshot->clipIsEmpty();
}
-bool CanvasState::clipRegion(const SkRegion* region, SkClipOp op) {
- mSnapshot->clipRegionTransformed(*region, op);
- return !mSnapshot->clipIsEmpty();
-}
-
void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
Rect bounds;
float radius;
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index a805597..b1fe09e 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -124,7 +124,6 @@
bool clipRect(float left, float top, float right, float bottom, SkClipOp op);
bool clipPath(const SkPath* path, SkClipOp op);
- bool clipRegion(const SkRegion* region, SkClipOp op);
/**
* Sets a "clipping outline", which is independent from the regular clip.
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 2e56160..cf57516 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -146,7 +146,6 @@
void setClip(float left, float top, float right, float bottom);
void clipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op);
- void clipRegion(const SkRegion& region, SkRegion::Op op);
void clipPathWithTransform(const SkPath& path, const mat4* transform,
SkRegion::Op op);
@@ -195,6 +194,7 @@
void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op);
+ void clipRegion(const SkRegion& region, SkRegion::Op op);
void ensureClipRegion();
void onClipRegionUpdated();
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index effc65e..4f9a3de 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -22,6 +22,7 @@
#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
+#include "font/Font.h"
#include "Glop.h"
#include "GlopBuilder.h"
#include "PixelBuffer.h"
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 96c6d29..ee6279d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -240,9 +240,6 @@
bool RecordingCanvas::clipPath(const SkPath* path, SkClipOp op) {
return mState.clipPath(path, op);
}
-bool RecordingCanvas::clipRegion(const SkRegion* region, SkClipOp op) {
- return mState.clipRegion(region, op);
-}
// ----------------------------------------------------------------------------
// android/graphics/Canvas draw operations
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 5d49385..44181bd2 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -134,7 +134,6 @@
virtual bool clipRect(float left, float top, float right, float bottom,
SkClipOp op) override;
virtual bool clipPath(const SkPath* path, SkClipOp op) override;
- virtual bool clipRegion(const SkRegion* region, SkClipOp op) override;
// Misc
virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 8cae771..344df0a7 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -416,23 +416,6 @@
return !mCanvas->isClipEmpty();
}
-bool SkiaCanvas::clipRegion(const SkRegion* region, SkClipOp op) {
- SkPath rgnPath;
- if (region->getBoundaryPath(&rgnPath)) {
- // The region is specified in device space.
- SkMatrix savedMatrix = mCanvas->getTotalMatrix();
- mCanvas->resetMatrix();
- this->recordClip(rgnPath, op);
- mCanvas->clipPath(rgnPath, op);
- mCanvas->setMatrix(savedMatrix);
- } else {
- const auto emptyClip = SkRect::MakeEmpty();
- this->recordClip(emptyClip, op);
- mCanvas->clipRect(emptyClip, op);
- }
- return !mCanvas->isClipEmpty();
-}
-
// ----------------------------------------------------------------------------
// Canvas state operations: Filters
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 9639ebd..34c3717 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -94,7 +94,6 @@
virtual bool clipRect(float left, float top, float right, float bottom,
SkClipOp op) override;
virtual bool clipPath(const SkPath* path, SkClipOp op) override;
- virtual bool clipRegion(const SkRegion* region, SkClipOp op) override;
virtual SkDrawFilter* getDrawFilter() override;
virtual void setDrawFilter(SkDrawFilter* drawFilter) override;
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 75396f7..c5156cf 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -19,6 +19,7 @@
#include "hwui/Bitmap.h"
#include <cutils/log.h>
+#include <SkLatticeIter.h>
#include <SkPatchUtils.h>
#include <SkPaint.h>
#include <SkPath.h>
@@ -140,6 +141,39 @@
SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
}
+void SkiaCanvasProxy::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
+ const SkPaint* paint) {
+ SkBitmap skiaBitmap;
+ if (image->asLegacyBitmap(&skiaBitmap, SkImage::kRO_LegacyBitmapMode)) {
+ onDrawBitmap(skiaBitmap, left, top, paint);
+ }
+}
+
+void SkiaCanvasProxy::onDrawImageRect(const SkImage* image, const SkRect* srcPtr, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint) {
+ SkBitmap skiaBitmap;
+ if (image->asLegacyBitmap(&skiaBitmap, SkImage::kRO_LegacyBitmapMode)) {
+ sk_sp<Bitmap> bitmap = Bitmap::createFrom(skiaBitmap.info(), *skiaBitmap.pixelRef());
+ SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(image->width(), image->height());
+ mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+ dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+ }
+}
+
+void SkiaCanvasProxy::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+ const SkPaint*) {
+ SkDEBUGFAIL("SkiaCanvasProxy::onDrawImageNine is not yet supported");
+}
+
+void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
+ const SkRect& dst, const SkPaint* paint) {
+ SkLatticeIter iter(lattice, dst);
+ SkRect srcR, dstR;
+ while (iter.next(&srcR, &dstR)) {
+ onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint);
+ }
+}
+
void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkBlendMode, const uint16_t indices[],
int indexCount, const SkPaint& paint) {
@@ -444,9 +478,5 @@
mCanvas->clipPath(&path, op);
}
-void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkClipOp op) {
- mCanvas->clipRegion(®ion, op);
-}
-
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index badcc1d..b3f6c07 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -66,6 +66,13 @@
const SkPaint* paint, SrcRectConstraint) override;
virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
const SkRect& dst, const SkPaint*) override;
+ virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
+ virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
+ SrcRectConstraint);
+ virtual void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+ const SkPaint*);
+ virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
+ const SkPaint*);
virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkBlendMode,
const uint16_t indices[], int indexCount,
@@ -93,7 +100,6 @@
virtual void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
virtual void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
virtual void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
- virtual void onClipRegion(const SkRegion&, SkClipOp) override;
private:
Canvas* mCanvas;
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 3f08009..9d719bd 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -72,11 +72,6 @@
// Clipping
///////////////////////////////////////////////////////////////////////////////
-void Snapshot::clipRegionTransformed(const SkRegion& region, SkClipOp op) {
- flags |= Snapshot::kFlagClipSet;
- mClipArea->clipRegion(region, static_cast<SkRegion::Op>(op));
-}
-
void Snapshot::clip(const Rect& localClip, SkClipOp op) {
flags |= Snapshot::kFlagClipSet;
mClipArea->clipRectWithTransform(localClip, transform, static_cast<SkRegion::Op>(op));
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 4f92657..8cd90a6 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -118,12 +118,6 @@
void clipTransformed(const Rect& r, SkClipOp op = SkClipOp::kIntersect);
/**
- * Modifies the current clip with the specified region and operation.
- * The specified region is considered already transformed.
- */
- void clipRegionTransformed(const SkRegion& region, SkClipOp op);
-
- /**
* Modifies the current clip with the specified path and operation.
*/
void clipPath(const SkPath& path, SkClipOp op);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index e7b6b2d..969d877 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -184,7 +184,6 @@
virtual bool clipRect(float left, float top, float right, float bottom,
SkClipOp op) = 0;
virtual bool clipPath(const SkPath* path, SkClipOp op) = 0;
- virtual bool clipRegion(const SkRegion* region, SkClipOp op) = 0;
// filters
virtual SkDrawFilter* getDrawFilter() = 0;
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index ac59ace..b60dbd5 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -41,8 +41,6 @@
public abstract void setRingerModeInternal(int ringerMode, String caller);
- public abstract int getVolumeControllerUid();
-
public abstract void updateRingerModeAffectedStreamsInternal();
public interface RingerModeDelegate {
diff --git a/media/java/android/media/ExternalRingtonesCursorWrapper.java b/media/java/android/media/ExternalRingtonesCursorWrapper.java
new file mode 100644
index 0000000..dd4c77a
--- /dev/null
+++ b/media/java/android/media/ExternalRingtonesCursorWrapper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.ContentProvider;
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.net.Uri;
+
+/**
+ * Cursor that adds the user id to fetched URIs. This is especially useful for {@link getCursor} as
+ * a managed profile should also list its parent's ringtones
+ *
+ * @hide
+ */
+public class ExternalRingtonesCursorWrapper extends CursorWrapper {
+
+ private int mUserId;
+
+ public ExternalRingtonesCursorWrapper(Cursor cursor, int userId) {
+ super(cursor);
+ mUserId = userId;
+ }
+
+ public String getString(int index) {
+ String result = super.getString(index);
+ if (index == RingtoneManager.URI_COLUMN_INDEX) {
+ result = ContentProvider.maybeAddUserId(Uri.parse(result), mUserId).toString();
+ }
+ return result;
+ }
+}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index de9f020..7614999 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -17,9 +17,11 @@
package android.media;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.WorkerThread;
import android.app.Activity;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -28,6 +30,7 @@
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.database.Cursor;
+import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
@@ -43,11 +46,16 @@
import libcore.io.Streams;
+import java.io.Closeable;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.LinkedBlockingQueue;
import static android.content.ContentProvider.maybeAddUserId;
import static android.content.pm.PackageManager.NameNotFoundException;
@@ -253,6 +261,8 @@
private boolean mStopPreviousRingtone = true;
private Ringtone mPreviousRingtone;
+ private boolean mIncludeParentRingtones;
+
/**
* Constructs a RingtoneManager. This constructor is recommended as its
* constructed instance manages cursor(s).
@@ -260,9 +270,24 @@
* @param activity The activity used to get a managed cursor.
*/
public RingtoneManager(Activity activity) {
+ this(activity, /* includeParentRingtones */ false);
+ }
+
+ /**
+ * Constructs a RingtoneManager. This constructor is recommended if there's the need to also
+ * list ringtones from the user's parent.
+ *
+ * @param activity The activity used to get a managed cursor.
+ * @param includeParentRingtones if true, this ringtone manager's cursor will also retrieve
+ * ringtones from the parent of the user specified in the given activity
+ *
+ * @hide
+ */
+ public RingtoneManager(Activity activity, boolean includeParentRingtones) {
mActivity = activity;
mContext = activity;
setType(mType);
+ mIncludeParentRingtones = includeParentRingtones;
}
/**
@@ -273,9 +298,23 @@
* @param context The context to used to get a cursor.
*/
public RingtoneManager(Context context) {
+ this(context, /* includeParentRingtones */ false);
+ }
+
+ /**
+ * Constructs a RingtoneManager.
+ *
+ * @param context The context to used to get a cursor.
+ * @param includeParentRingtones if true, this ringtone manager's cursor will also retrieve
+ * ringtones from the parent of the user specified in the given context
+ *
+ * @hide
+ */
+ public RingtoneManager(Context context, boolean includeParentRingtones) {
mActivity = null;
mContext = context;
setType(mType);
+ mIncludeParentRingtones = includeParentRingtones;
}
/**
@@ -395,14 +434,38 @@
if (mCursor != null && mCursor.requery()) {
return mCursor;
}
-
- final Cursor internalCursor = getInternalRingtones();
- final Cursor mediaCursor = getMediaRingtones();
-
- return mCursor = new SortCursor(new Cursor[] { internalCursor, mediaCursor },
+
+ ArrayList<Cursor> ringtoneCursors = new ArrayList<Cursor>();
+ ringtoneCursors.add(getInternalRingtones());
+ ringtoneCursors.add(getMediaRingtones());
+
+ if (mIncludeParentRingtones) {
+ Cursor parentRingtonesCursor = getParentProfileRingtones();
+ if (parentRingtonesCursor != null) {
+ ringtoneCursors.add(parentRingtonesCursor);
+ }
+ }
+
+ return mCursor = new SortCursor(ringtoneCursors.toArray(new Cursor[ringtoneCursors.size()]),
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
}
+ private Cursor getParentProfileRingtones() {
+ final UserManager um = UserManager.get(mContext);
+ final UserInfo parentInfo = um.getProfileParent(mContext.getUserId());
+ if (parentInfo != null && parentInfo.id != mContext.getUserId()) {
+ final Context parentContext = createPackageContextAsUser(mContext, parentInfo.id);
+ if (parentContext != null) {
+ // We don't need to re-add the internal ringtones for the work profile since
+ // they are the same as the personal profile. We just need the external
+ // ringtones.
+ return new ExternalRingtonesCursorWrapper(getMediaRingtones(parentContext),
+ parentInfo.id);
+ }
+ }
+ return null;
+ }
+
/**
* Gets a {@link Ringtone} for the ringtone at the given position in the
* {@link Cursor}.
@@ -434,7 +497,35 @@
return getUriFromCursor(mCursor);
}
-
+
+ /**
+ * Queries the database for the Uri to a ringtone in a specific path (the ringtone has to have
+ * been scanned before)
+ *
+ * @param context Context used to query the database
+ * @param path Path to the ringtone file
+ * @return Uri of the ringtone, null if something fails in the query or the ringtone doesn't
+ * exist
+ *
+ * @hide
+ */
+ private static Uri getExistingRingtoneUriFromPath(Context context, String path) {
+ final String[] proj = {MediaStore.Audio.Media._ID};
+ final String[] selectionArgs = {path};
+ try (final Cursor cursor = context.getContentResolver().query(
+ MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj,
+ MediaStore.Audio.Media.DATA + "=? ", selectionArgs, /* sortOrder */ null)) {
+ if (cursor == null || !cursor.moveToFirst()) {
+ return null;
+ }
+ final int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
+ if (id == -1) {
+ return null;
+ }
+ return Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, "" + id);
+ }
+ }
+
private static Uri getUriFromCursor(Cursor cursor) {
return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
.getLong(ID_COLUMN_INDEX));
@@ -523,7 +614,11 @@
}
private Cursor getMediaRingtones() {
- if (PackageManager.PERMISSION_GRANTED != mContext.checkPermission(
+ return getMediaRingtones(mContext);
+ }
+
+ private Cursor getMediaRingtones(Context context) {
+ if (PackageManager.PERMISSION_GRANTED != context.checkPermission(
android.Manifest.permission.READ_EXTERNAL_STORAGE,
Process.myPid(), Process.myUid())) {
Log.w(TAG, "No READ_EXTERNAL_STORAGE permission, ignoring ringtones on ext storage");
@@ -537,7 +632,7 @@
? query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS,
constructBooleanTrueWhereClause(mFilterColumns), null,
- MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
+ MediaStore.Audio.Media.DEFAULT_SORT_ORDER, context)
: null;
}
@@ -592,10 +687,19 @@
String selection,
String[] selectionArgs,
String sortOrder) {
+ return query(uri, projection, selection, selectionArgs, sortOrder, mContext);
+ }
+
+ private Cursor query(Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String sortOrder,
+ Context context) {
if (mActivity != null) {
return mActivity.managedQuery(uri, projection, selection, selectionArgs, sortOrder);
} else {
- return mContext.getContentResolver().query(uri, projection, selection, selectionArgs,
+ return context.getContentResolver().query(uri, projection, selection, selectionArgs,
sortOrder);
}
}
@@ -642,7 +746,29 @@
return null;
}
-
+
+ /**
+ * Look up the path for a given {@link Uri} referring to a ringtone sound (TYPE_RINGTONE,
+ * TYPE_NOTIFICATION, or TYPE_ALARM). This is saved in {@link MediaStore.Audio.Media#DATA}.
+ *
+ * @return a {@link File} pointing at the location of the {@param uri} on disk, or {@code null}
+ * if there is no such file.
+ */
+ private File getRingtonePathFromUri(Uri uri) {
+ // Query cursor to get ringtone path
+ final String[] projection = {MediaStore.Audio.Media.DATA};
+ setFilterColumnsList(TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM);
+
+ String path = null;
+ try (Cursor cursor = query(uri, projection, constructBooleanTrueWhereClause(mFilterColumns),
+ null, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
+ }
+ }
+ return path != null ? new File(path) : null;
+ }
+
/**
* Disables Settings.System.SYNC_PARENT_SOUNDS, copying the parent's ringtones to the current
* profile
@@ -659,17 +785,14 @@
UserManager um = UserManager.get(userContext);
UserInfo parentInfo = um.getProfileParent(userContext.getUserId());
if (parentInfo != null) {
- try {
- Context targetContext = userContext.createPackageContextAsUser(
- userContext.getPackageName(), 0 /* flags */, UserHandle.of(parentInfo.id));
+ final Context targetContext = createPackageContextAsUser(userContext, parentInfo.id);
+ if (targetContext != null) {
for (int ringtoneType : RINGTONE_TYPES) {
Uri ringtoneUri = getActualDefaultRingtoneUri(targetContext, ringtoneType);
// Add user id of parent so that custom ringtones can be read and played
RingtoneManager.setActualDefaultRingtoneUri(userContext, ringtoneType,
maybeAddUserId(ringtoneUri, parentInfo.id));
}
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Unable to create parent context", e);
}
}
}
@@ -749,9 +872,157 @@
}
private static boolean isInternalRingtoneUri(Uri uri) {
- Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(uri);
- return uriWithoutUserId == null ? false : uriWithoutUserId.toString()
- .startsWith(MediaStore.Audio.Media.INTERNAL_CONTENT_URI.toString());
+ return isRingtoneUriInStorage(uri, MediaStore.Audio.Media.INTERNAL_CONTENT_URI);
+ }
+
+ private static boolean isExternalRingtoneUri(Uri uri) {
+ return isRingtoneUriInStorage(uri, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
+ }
+
+ private static boolean isRingtoneUriInStorage(Uri ringtone, Uri storage) {
+ Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(ringtone);
+ return uriWithoutUserId == null ? false
+ : uriWithoutUserId.toString().startsWith(storage.toString());
+ }
+
+ /** @hide */
+ public boolean isCustomRingtone(Uri uri) {
+ if(!isExternalRingtoneUri(uri)) {
+ // A custom ringtone would be in the external storage
+ return false;
+ }
+
+ final File ringtoneFile = (uri == null ? null : getRingtonePathFromUri(uri));
+ final File parent = (ringtoneFile == null ? null : ringtoneFile.getParentFile());
+ if (parent == null) {
+ return false;
+ }
+
+ final String[] directories = {
+ Environment.DIRECTORY_RINGTONES,
+ Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_ALARMS
+ };
+ for (final String directory : directories) {
+ if (parent.equals(Environment.getExternalStoragePublicDirectory(directory))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds an audio file to the list of ringtones.
+ *
+ * After making sure the given file is an audio file, copies the file to the ringtone storage,
+ * and asks the {@link android.media.MediaScanner} to scan that file. This call will block until
+ * the scan is completed.
+ *
+ * The directory where the copied file is stored is the directory that matches the ringtone's
+ * type, which is one of: {@link android.is.Environment#DIRECTORY_RINGTONES};
+ * {@link android.is.Environment#DIRECTORY_NOTIFICATIONS};
+ * {@link android.is.Environment#DIRECTORY_ALARMS}.
+ *
+ * This does not allow modifying the type of an existing ringtone file. To change type, use the
+ * APIs in {@link android.content.ContentResolver} to update the corresponding columns.
+ *
+ * @param fileUri Uri of the file to be added as ringtone. Must be a media file.
+ * @param type The type of the ringtone to be added. Must be one of {@link #TYPE_RINGTONE},
+ * {@link #TYPE_NOTIFICATION}, or {@link #TYPE_ALARM}.
+ *
+ * @return The Uri of the installed ringtone, which may be the Uri of {@param fileUri} if it is
+ * already in ringtone storage.
+ *
+ * @throws FileNotFoundexception if an appropriate unique filename to save the new ringtone file
+ * as cannot be found, for example if the unique name is too long.
+ * @throws IllegalArgumentException if {@param fileUri} does not point to an existing audio
+ * file, or if the {@param type} is not one of the accepted ringtone types.
+ * @throws IOException if the audio file failed to copy to ringtone storage; for example, if
+ * external storage was not available, or if the file was copied but the media scanner
+ * did not recognize it as a ringtone.
+ *
+ * @hide
+ */
+ @WorkerThread
+ public Uri addCustomExternalRingtone(@NonNull final Uri fileUri, final int type)
+ throws FileNotFoundException, IllegalArgumentException, IOException {
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ throw new IOException("External storage is not mounted. Unable to install ringtones.");
+ }
+
+ // Sanity-check: are we actually being asked to install an audio file?
+ final String mimeType = mContext.getContentResolver().getType(fileUri);
+ if(mimeType == null || !mimeType.startsWith("audio/")) {
+ throw new IllegalArgumentException("Ringtone file must have MIME type \"audio/*\"."
+ + " Given file has MIME type \"" + mimeType + "\"");
+ }
+
+ // Choose a directory to save the ringtone. Only one type of installation at a time is
+ // allowed. Throws IllegalArgumentException if anything else is given.
+ final String subdirectory = getExternalDirectoryForType(type);
+
+ // Find a filename. Throws FileNotFoundException if none can be found.
+ final File outFile = Utils.getUniqueExternalFile(mContext, subdirectory,
+ Utils.getFileDisplayNameFromUri(mContext, fileUri), mimeType);
+
+ // Copy contents to external ringtone storage. Throws IOException if the copy fails.
+ try (final InputStream input = mContext.getContentResolver().openInputStream(fileUri);
+ final OutputStream output = new FileOutputStream(outFile)) {
+ Streams.copy(input, output);
+ }
+
+ // Tell MediaScanner about the new file. Wait for it to assign a {@link Uri}.
+ try (NewRingtoneScanner scanner = new NewRingtoneScanner(outFile)) {
+ return scanner.take();
+ } catch (InterruptedException e) {
+ throw new IOException("Audio file failed to scan as a ringtone", e);
+ }
+ }
+
+ private static final String getExternalDirectoryForType(final int type) {
+ switch (type) {
+ case TYPE_RINGTONE:
+ return Environment.DIRECTORY_RINGTONES;
+ case TYPE_NOTIFICATION:
+ return Environment.DIRECTORY_NOTIFICATIONS;
+ case TYPE_ALARM:
+ return Environment.DIRECTORY_ALARMS;
+ default:
+ throw new IllegalArgumentException("Unsupported ringtone type: " + type);
+ }
+ }
+
+ /**
+ * Deletes the actual file in the Uri and its ringtone database entry if the Uri's actual path
+ * is in one of the following directories: {@link android.is.Environment#DIRECTORY_RINGTONES},
+ * {@link android.is.Environment#DIRECTORY_NOTIFICATIONS} or
+ * {@link android.is.Environment#DIRECTORY_ALARMS}.
+ *
+ * The given Uri must be a ringtone Content Uri.
+ *
+ * Keep in mind that if the ringtone deleted is a default ringtone, it will still live in the
+ * ringtone cache file so it will be playable from there. However, if an app uses the ringtone
+ * as its own ringtone, it won't be played, which is the same behavior observed for 3rd party
+ * custom ringtones.
+ *
+ * @hide
+ */
+ public boolean deleteExternalRingtone(Uri uri) {
+ if(!isCustomRingtone(uri)) {
+ // We can only delete custom ringtones in the default ringtone storages
+ return false;
+ }
+
+ // Save the path of the ringtone before deleting from our content resolver.
+ final File ringtoneFile = getRingtonePathFromUri(uri);
+ try {
+ if (ringtoneFile != null && mContext.getContentResolver().delete(uri, null, null) > 0) {
+ return ringtoneFile.delete();
+ }
+ } catch (SecurityException e) {
+ Log.d(TAG, "Unable to delete custom ringtone", e);
+ }
+ return false;
}
/**
@@ -860,5 +1131,67 @@
return null;
}
}
-
+
+ /**
+ * Creates a {@link android.media.MediaScannerConnection} to scan a ringtone file and add its
+ * information to the internal database.
+ *
+ * It uses a {@link java.util.concurrent.LinkedBlockingQueue} so that the caller can block until
+ * the scan is completed.
+ */
+ private class NewRingtoneScanner implements Closeable, MediaScannerConnectionClient {
+ private MediaScannerConnection mMediaScannerConnection;
+ private File mFile;
+ private LinkedBlockingQueue<Uri> mQueue = new LinkedBlockingQueue<>(1);
+
+ public NewRingtoneScanner(File file) {
+ mFile = file;
+ mMediaScannerConnection = new MediaScannerConnection(mContext, this);
+ mMediaScannerConnection.connect();
+ }
+
+ @Override
+ public void close() {
+ mMediaScannerConnection.disconnect();
+ }
+
+ @Override
+ public void onMediaScannerConnected() {
+ mMediaScannerConnection.scanFile(mFile.getAbsolutePath(), null);
+ }
+
+ @Override
+ public void onScanCompleted(String path, Uri uri) {
+ if (uri == null) {
+ // There was some issue with scanning. Delete the copied file so it is not oprhaned.
+ mFile.delete();
+ return;
+ }
+ try {
+ mQueue.put(uri);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Unable to put new ringtone Uri in queue", e);
+ }
+ }
+
+ public Uri take() throws InterruptedException {
+ return mQueue.take();
+ }
+ }
+
+ /**
+ * Attempts to create a context for the given user.
+ *
+ * @return created context, or null if package does not exist
+ * @hide
+ */
+ private static Context createPackageContextAsUser(Context context, int userId) {
+ try {
+ return context.createPackageContextAsUser(context.getPackageName(), 0 /* flags */,
+ UserHandle.of(userId));
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Unable to create package context", e);
+ return null;
+ }
+ }
}
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index 35b083e..5b62f16 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -16,12 +16,21 @@
package android.media;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.provider.OpenableColumns;
import android.util.Log;
import android.util.Pair;
import android.util.Range;
import android.util.Rational;
import android.util.Size;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Vector;
@@ -307,4 +316,66 @@
Log.w(TAG, "could not parse size range '" + o + "'");
return null;
}
+
+ /**
+ * Creates a unique file in the specified external storage with the desired name. If the name is
+ * taken, the new file's name will have '(%d)' to avoid overwriting files.
+ *
+ * @param context {@link Context} to query the file name from.
+ * @param subdirectory One of the directories specified in {@link android.os.Environment}
+ * @param fileName desired name for the file.
+ * @param mimeType MIME type of the file to create.
+ * @return the File object in the storage, or null if an error occurs.
+ */
+ public static File getUniqueExternalFile(Context context, String subdirectory, String fileName,
+ String mimeType) {
+ File externalStorage = Environment.getExternalStoragePublicDirectory(subdirectory);
+ // Make sure the storage subdirectory exists
+ externalStorage.mkdirs();
+
+ File outFile = null;
+ try {
+ // Ensure the file has a unique name, as to not override any existing file
+ outFile = FileUtils.buildUniqueFile(externalStorage, mimeType, fileName);
+ } catch (FileNotFoundException e) {
+ // This might also be reached if the number of repeated files gets too high
+ Log.e(TAG, "Unable to get a unique file name: " + e);
+ return null;
+ }
+ return outFile;
+ }
+
+ /**
+ * Returns a file's display name from its {@link android.content.ContentResolver.SCHEME_FILE}
+ * or {@link android.content.ContentResolver.SCHEME_CONTENT} Uri. The display name of a file
+ * includes its extension.
+ *
+ * @param context Context trying to resolve the file's display name.
+ * @param uri Uri of the file.
+ * @return the file's display name, or the uri's string if something fails or the uri isn't in
+ * the schemes specified above.
+ */
+ static String getFileDisplayNameFromUri(Context context, Uri uri) {
+ String scheme = uri.getScheme();
+
+ if (ContentResolver.SCHEME_FILE.equals(scheme)) {
+ return uri.getLastPathSegment();
+ } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
+ // We need to query the ContentResolver to get the actual file name as the Uri masks it.
+ // This means we want the name used for display purposes only.
+ String[] proj = {
+ OpenableColumns.DISPLAY_NAME
+ };
+ try (Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null)) {
+ if (cursor != null && cursor.getCount() != 0) {
+ cursor.moveToFirst();
+ return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+ }
+ }
+ }
+
+ // This will only happen if the Uri isn't either SCHEME_CONTENT or SCHEME_FILE, so we assume
+ // it already represents the file's name.
+ return uri.toString();
+ }
}
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 33c9655..5843637 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -17,4 +17,5 @@
name: "libandroid.ndk",
symbol_file: "libandroid.map.txt",
first_version: "9",
+ unversioned_until: "current",
}
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index e09b0b4..17feb53 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -17,4 +17,5 @@
name: "libjnigraphics.ndk",
symbol_file: "libjnigraphics.map.txt",
first_version: "9",
+ unversioned_until: "current",
}
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 362cf44..5c00985 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -100,6 +100,129 @@
<item>Always use HDCP checking</item>
</string-array>
+
+ <!-- Bluetooth settings -->
+
+ <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40] -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item>Default</item>
+ <item>SBC</item>
+ <item>aptX</item>
+ <item>aptX-HD</item>
+ <item>LDAC</item>
+ </string-array>
+
+ <!-- Values for Bluetooth Audio Codec selection preference. -->
+ <string-array name="bluetooth_a2dp_codec_values" translatable="false" >
+ <item>1000000</item>
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ </string-array>
+
+ <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40]-->
+ <string-array name="bluetooth_a2dp_codec_summaries" >
+ <item>Default</item>
+ <item>SBC</item>
+ <item>aptX</item>
+ <item>aptX-HD</item>
+ <item>LDAC</item>
+ </string-array>
+
+ <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40] -->
+ <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
+ <item>Default</item>
+ <item>44.1 kHz</item>
+ <item>48.0 kHz</item>
+ <item>88.2 kHz</item>
+ <item>96.0 kHz</item>
+ </string-array>
+
+ <!-- Values for Bluetooth Audio Codec Sample Rate selection preference. -->
+ <string-array name="bluetooth_a2dp_codec_sample_rate_values" translatable="false" >
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ <item>4</item>
+ <item>8</item>
+ </string-array>
+
+ <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40]-->
+ <string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
+ <item>Default</item>
+ <item>44.1 kHz</item>
+ <item>48.0 kHz</item>
+ <item>88.2 kHz</item>
+ <item>96.0 kHz</item>
+ </string-array>
+
+ <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40] -->
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
+ <item>Default</item>
+ <item>16 bits/sample</item>
+ <item>24 bits/sample</item>
+ <item>32 bits/sample</item>
+ </string-array>
+
+ <!-- Values for Bluetooth Audio Codec Bits Per Sample selection preference. -->
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_values" translatable="false" >
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ <item>4</item>
+ </string-array>
+
+ <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40]-->
+ <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
+ <item>Default</item>
+ <item>16 bits/sample</item>
+ <item>24 bits/sample</item>
+ <item>32 bits/sample</item>
+ </string-array>
+
+ <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40] -->
+ <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
+ <item>Default</item>
+ <item>Mono</item>
+ <item>Stereo</item>
+ </string-array>
+
+ <!-- Values for Bluetooth Audio Codec Channel Mode selection preference. -->
+ <string-array name="bluetooth_a2dp_codec_channel_mode_values" translatable="false" >
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ </string-array>
+
+ <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40]-->
+ <string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
+ <item>Default</item>
+ <item>Mono</item>
+ <item>Stereo</item>
+ </string-array>
+
+ <!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40] -->
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
+ <item>Sound quality preferred (990kbps/909kbps)</item>
+ <item>Standard (660kbps/606kbps)</item>
+ <item>Connection preferred (330kbps/303kbps)</item>
+ </string-array>
+
+ <!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_values" translatable="false" >
+ <item>1000</item>
+ <item>1001</item>
+ <item>1002</item>
+ </string-array>
+
+ <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40]-->
+ <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
+ <item>Sound quality preferred (990kbps/909kbps)</item>
+ <item>Standard (660kbps/606kbps)</item>
+ <item>Connection preferred (330kbps/303kbps)</item>
+ </string-array>
+
<!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
<string-array name="select_logd_size_titles">
<item>Off</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f176aac..93bd5dc 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -428,6 +428,31 @@
<!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
<string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
+ <!-- UI debug setting: Select Bluetooth Audio Codec -->
+ <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
+ <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec -->
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Preferred Bluetooth A2DP Codec</string>
+
+ <!-- UI debug setting: Select Bluetooth Audio Sample Rate -->
+ <string name="bluetooth_select_a2dp_codec_sample_rate">Bluetooth Audio Sample Rate</string>
+ <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Sample Rate -->
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Preferred Bluetooth A2DP Codec Sample Rate</string>
+
+ <!-- UI debug setting: Select Bluetooth Audio Bits Per Sample -->
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample">Bluetooth Audio Bits Per Sample</string>
+ <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Bits Per Sample -->
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Preferred Bluetooth A2DP Codec Bits Per Sample</string>
+
+ <!-- UI debug setting: Select Bluetooth Audio Channel Mode -->
+ <string name="bluetooth_select_a2dp_codec_channel_mode">Bluetooth Audio Channel Mode</string>
+ <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Channel Mode -->
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Preferred Bluetooth A2DP Codec Channel Mode</string>
+
+ <!-- UI debug setting: Select Bluetooth Audio LDAC Playback Quality -->
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Playback Quality</string>
+ <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec LDAC Playback Quality -->
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Preferred Bluetooth A2DP Codec LDAC Playback Quality</string>
+
<!-- setting Checkbox summary whether to show options for wireless display certification -->
<string name="wifi_display_certification_summary">Show options for wireless display certification</string>
<!-- Setting Checkbox summary whether to enable Wifi verbose Logging [CHAR LIMIT=80] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 37f2fe9..6010621 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -377,11 +377,17 @@
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
+ }
+ }
+
+ /**
+ * Updates dashboard categories. Only necessary to call this after setTileEnabled
+ */
+ public void updateCategories() {
+ if (isDashboardFeatureEnabled()) {
+ new CategoriesUpdateTask().execute();
+ } else {
+ new CategoriesUpdater().execute();
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index eab4722..388c71d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -39,6 +39,7 @@
import android.view.LayoutInflater;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import java.util.ArrayList;
import java.util.List;
@@ -283,8 +284,6 @@
Class<?> pluginClass = Class.forName(cls, true, classLoader);
T plugin = (T) pluginClass.newInstance();
if (plugin.getVersion() != mVersion) {
- final int id = mContext.getResources().getIdentifier("notification_plugin",
- "id", mContext.getPackageName());
final int icon = mContext.getResources().getIdentifier("tuner", "drawable",
mContext.getPackageName());
final int color = Resources.getSystem().getIdentifier(
@@ -320,7 +319,8 @@
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
mContext.getSystemService(NotificationManager.class)
- .notifyAsUser(cls, id, nb.build(), UserHandle.ALL);
+ .notifyAsUser(cls, SystemMessage.NOTE_PLUGIN, nb.build(),
+ UserHandle.ALL);
// TODO: Warn user.
Log.w(TAG, "Plugin has invalid interface version " + plugin.getVersion()
+ ", expected " + mVersion);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
index c3de092..6096eaf 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -31,6 +31,7 @@
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
import dalvik.system.PathClassLoader;
@@ -141,10 +142,8 @@
mContext.getPackageManager().setComponentEnabledSetting(component,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
- int id = mContext.getResources().getIdentifier("notification_plugin", "id",
- mContext.getPackageName());
mContext.getSystemService(NotificationManager.class).cancel(component.getClassName(),
- id);
+ SystemMessage.NOTE_PLUGIN);
} else {
Uri data = intent.getData();
String pkg = data.getEncodedSchemeSpecificPart();
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c025f93..50ef392 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -290,6 +290,11 @@
<bool name="quick_settings_show_full_alarm">false</bool>
+ <!-- Whether to show a warning notification when the device reaches a certain temperature. -->
<bool name="config_showTemperatureWarning">false</bool>
+ <!-- Temp at which to show a warning notification if config_showTemperatureWarning is true.
+ If < 0, uses the value from HardwarePropertiesManager#getDeviceTemperatures. -->
+ <integer name="config_warningTemperature">-1</integer>
+
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 56cd8c7..4a19dde 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -52,7 +52,6 @@
<item type="id" name="notification_power"/>
<item type="id" name="notification_screenshot"/>
<item type="id" name="notification_hidden"/>
- <item type="id" name="notification_volumeui"/>
<item type="id" name="notification_temperature"/>
<item type="id" name="notification_plugin"/>
<item type="id" name="transformation_start_x_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dcb583f..34a0397 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1125,21 +1125,6 @@
<!-- Hide quick settings tile confirmation button -->
<string name="quick_settings_reset_confirmation_button">Hide</string>
- <!-- VolumeUI activation dialog: warning message -->
- <string name="volumeui_prompt_message"><xliff:g id="app_name" example="Volume Prototype 1">%1$s</xliff:g> wants to be the volume dialog.</string>
-
- <!-- VolumeUI activation dialog: allow button label -->
- <string name="volumeui_prompt_allow">Allow</string>
-
- <!-- VolumeUI activation dialog: deny button label -->
- <string name="volumeui_prompt_deny">Deny</string>
-
- <!-- VolumeUI restoration notification: title -->
- <string name="volumeui_notification_title"><xliff:g id="app_name" example="Volume Prototype 1">%1$s</xliff:g> is the volume dialog</string>
-
- <!-- VolumeUI restoration notification: text -->
- <string name="volumeui_notification_text">Tap to restore the original.</string>
-
<!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
<string name="managed_profile_foreground_toast">You\'re using your work profile</string>
@@ -1744,7 +1729,7 @@
<!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
<string name="high_temp_title">Phone is getting warm</string>
- <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=70] -->
+ <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=100] -->
<string name="high_temp_notif_message">Some features limited while phone cools down</string>
<!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
<string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index b207984..d109ae1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -42,6 +42,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.shortcut.ShortcutKeyDispatcher;
import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.SystemBars;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.tuner.TunerService;
@@ -65,6 +66,7 @@
private final Class<?>[] SERVICES = new Class[] {
FragmentService.class,
TunerService.class,
+ CommandQueue.CommandQueueStart.class,
KeyguardViewMediator.class,
Recents.class,
VolumeUI.class,
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 848fe9d..71dda2d 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -38,6 +38,7 @@
import android.provider.Settings;
import android.util.Slog;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -50,8 +51,8 @@
private static final String TAG = PowerUI.TAG + ".Notification";
private static final boolean DEBUG = PowerUI.DEBUG;
- private static final String TAG_NOTIFICATION_BATTERY = "low_battery";
- private static final String TAG_NOTIFICATION_TEMPERATURE = "high_temp";
+ private static final String TAG_BATTERY = "low_battery";
+ private static final String TAG_TEMPERATURE = "high_temp";
private static final int SHOWING_NOTHING = 0;
private static final int SHOWING_WARNING = 1;
@@ -136,7 +137,8 @@
showWarningNotification();
mShowing = SHOWING_WARNING;
} else {
- mNoMan.cancelAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, UserHandle.ALL);
+ mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL);
+ mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL);
mShowing = SHOWING_NOTHING;
}
}
@@ -155,7 +157,8 @@
com.android.internal.R.color.system_notification_accent_color));
SystemUI.overrideNotificationAppName(mContext, nb);
final Notification n = nb.build();
- mNoMan.notifyAsUser(TAG_NOTIFICATION_BATTERY, R.id.notification_power, n, UserHandle.ALL);
+ mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL);
+ mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, n, UserHandle.ALL);
}
private void showWarningNotification() {
@@ -185,8 +188,9 @@
mPlaySound = false;
}
SystemUI.overrideNotificationAppName(mContext, nb);
- mNoMan.notifyAsUser(
- TAG_NOTIFICATION_BATTERY, R.id.notification_power, nb.build(), UserHandle.ALL);
+ final Notification n = nb.build();
+ mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL);
+ mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL);
}
private PendingIntent pendingBroadcast(String action) {
@@ -213,8 +217,8 @@
return;
}
mTempWarning = false;
- mNoMan.cancelAsUser(
- TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, UserHandle.ALL);
+ mNoMan.cancelAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP,
+ UserHandle.ALL);
}
@Override
@@ -237,8 +241,7 @@
com.android.internal.R.color.battery_saver_mode_color));
SystemUI.overrideNotificationAppName(mContext, nb);
final Notification n = nb.build();
- mNoMan.notifyAsUser(
- TAG_NOTIFICATION_TEMPERATURE, R.id.notification_temperature, n, UserHandle.ALL);
+ mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index d4bb994..8988801 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -225,16 +225,20 @@
return;
}
- // Get the throttling temperature. No need to check if we're not throttling.
- float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
- HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
- HardwarePropertiesManager.TEMPERATURE_THROTTLING);
- if (throttlingTemps == null
- || throttlingTemps.length == 0
- || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
- return;
+ mThrottlingTemp = mContext.getResources().getInteger(R.integer.config_warningTemperature);
+
+ if (mThrottlingTemp < 0f) {
+ // Get the throttling temperature. No need to check if we're not throttling.
+ float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
+ HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+ HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+ if (throttlingTemps == null
+ || throttlingTemps.length == 0
+ || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
+ return;
+ }
+ mThrottlingTemp = throttlingTemps[0];
}
- mThrottlingTemp = throttlingTemps[0];
// We have passed all of the checks, start checking the temp
updateTemperatureWarning();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 5877440..5c7496d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -38,6 +38,7 @@
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -150,11 +151,19 @@
Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
t.userId, t.firstActiveTime, t.lastActiveTime);
- // This task is only shown in the stack if it statisfies the historical time or min
+ // This task is only shown in the stack if it satisfies the historical time or min
// number of tasks constraints. Freeform tasks are also always shown.
boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
- boolean isStackTask = isFreeformTask || !isHistoricalTask(t) ||
+ boolean isStackTask;
+ if (Recents.getConfiguration().isGridEnabled) {
+ // When grid layout is enabled, we only show the first
+ // TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT} tasks.
+ isStackTask = t.lastActiveTime >= lastStackActiveTime &&
+ i >= taskCount - TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT;
+ } else {
+ isStackTask = isFreeformTask || !isHistoricalTask(t) ||
(t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS));
+ }
boolean isLaunchTarget = taskKey.id == runningTaskId;
// The last stack active time is the baseline for which we show visible tasks. Since
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index be3af040..046ced4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -30,7 +30,7 @@
public class TaskGridLayoutAlgorithm {
private final String TAG = "TaskGridLayoutAlgorithm";
- private final int MAX_LAYOUT_TASK_COUNT = 8;
+ public static final int MAX_LAYOUT_TASK_COUNT = 8;
/** The horizontal padding around the whole recents view. */
private int mPaddingLeftRight;
@@ -135,6 +135,16 @@
updateAppAspectRatio();
}
+ /**
+ * Returns the proper task view transform of a certain task view, according to its index and the
+ * amount of task views.
+ * @param taskIndex The index of the task view whose transform we want. It's never greater
+ * than {@link MAX_LAYOUT_TASK_COUNT}.
+ * @param taskCount The current amount of task views.
+ * @param transformOut The result transform that this method returns.
+ * @param stackLayout The base stack layout algorithm.
+ * @return The expected transform of the (taskIndex)th task view.
+ */
public TaskViewTransform getTransform(int taskIndex, int taskCount,
TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 0eef864..db021ff 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -59,6 +59,7 @@
import android.view.animation.Interpolator;
import android.widget.ImageView;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
@@ -201,7 +202,8 @@
mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
SystemUI.overrideNotificationAppName(context, mNotificationBuilder);
- mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
+ mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+ mNotificationBuilder.build());
/**
* NOTE: The following code prepares the notification builder for updating the notification
@@ -348,7 +350,8 @@
.setPublicVersion(mPublicNotificationBuilder.build())
.setFlag(Notification.FLAG_NO_CLEAR, false);
- mNotificationManager.notify(R.id.notification_screenshot, mNotificationBuilder.build());
+ mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+ mNotificationBuilder.build());
}
mParams.finisher.run();
mParams.clearContext();
@@ -364,7 +367,7 @@
mParams.clearContext();
// Cancel the posted notification
- mNotificationManager.cancel(R.id.notification_screenshot);
+ mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
}
}
@@ -866,7 +869,7 @@
Notification n = new Notification.BigTextStyle(b)
.bigText(errorMsg)
.build();
- nManager.notify(R.id.notification_screenshot, n);
+ nManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT, n);
}
/**
@@ -878,7 +881,7 @@
// Clear the notification
final NotificationManager nm =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- nm.cancel(R.id.notification_screenshot);
+ nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
}
}
@@ -896,7 +899,7 @@
final NotificationManager nm =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
- nm.cancel(R.id.notification_screenshot);
+ nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
// And delete the image from the media store
new DeleteImageInBackgroundTask(context).execute(uri);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 80b43e6..db099bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -42,7 +42,6 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -80,13 +79,13 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
-import android.widget.ImageView;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.widget.LockPatternUtils;
@@ -544,7 +543,7 @@
} else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
NotificationManager noMan = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- noMan.cancel(R.id.notification_hidden);
+ noMan.cancel(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -753,7 +752,8 @@
mLockPatternUtils = new LockPatternUtils(mContext);
// Connect in to the status bar manager service
- mCommandQueue = new CommandQueue(this);
+ mCommandQueue = getComponent(CommandQueue.class);
+ mCommandQueue.addCallbacks(this);
int[] switches = new int[9];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
@@ -885,7 +885,7 @@
NotificationManager noMan =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- noMan.notify(R.id.notification_hidden, note.build());
+ noMan.notify(SystemMessage.NOTE_HIDDEN_NOTIFICATIONS, note.build());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 419c91b..a3e4d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -21,13 +21,16 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
+import android.support.annotation.VisibleForTesting;
import android.util.Pair;
import android.view.KeyEvent;
import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.SystemUI;
/**
* This class takes the functions from IStatusBar that come in on
@@ -88,55 +91,68 @@
private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
private final Object mLock = new Object();
- private Callbacks mCallbacks;
- private Handler mHandler = new H();
+ private Callbacks[] mCallbacks = new Callbacks[0];
+ private Handler mHandler = new H(Looper.getMainLooper());
/**
* These methods are called back on the main thread.
*/
public interface Callbacks {
- void setIcon(String slot, StatusBarIcon icon);
- void removeIcon(String slot);
- void disable(int state1, int state2, boolean animate);
- void animateExpandNotificationsPanel();
- void animateCollapsePanels(int flags);
- void animateExpandSettingsPanel(String obj);
- void setSystemUiVisibility(int vis, int fullscreenStackVis,
- int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds);
- void topAppWindowChanged(boolean visible);
- void setImeWindowStatus(IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher);
- void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
- void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
- void toggleRecentApps();
- void toggleSplitScreen();
- void preloadRecentApps();
- void dismissKeyboardShortcutsMenu();
- void toggleKeyboardShortcutsMenu(int deviceId);
- void cancelPreloadRecentApps();
- void setWindowState(int window, int state);
- void buzzBeepBlinked();
- void notificationLightOff();
- void notificationLightPulse(int argb, int onMillis, int offMillis);
- void showScreenPinningRequest(int taskId);
- void appTransitionPending();
- void appTransitionCancelled();
- void appTransitionStarting(long startTime, long duration);
- void appTransitionFinished();
- void showAssistDisclosure();
- void startAssist(Bundle args);
- void onCameraLaunchGestureDetected(int source);
- void showTvPictureInPictureMenu();
+ default void setIcon(String slot, StatusBarIcon icon) { }
+ default void removeIcon(String slot) { }
+ default void disable(int state1, int state2, boolean animate) { }
+ default void animateExpandNotificationsPanel() { }
+ default void animateCollapsePanels(int flags) { }
+ default void animateExpandSettingsPanel(String obj) { }
+ default void setSystemUiVisibility(int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+ }
+ default void topAppWindowChanged(boolean visible) { }
+ default void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) { }
+ default void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) { }
+ default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
+ default void toggleRecentApps() { }
+ default void toggleSplitScreen() { }
+ default void preloadRecentApps() { }
+ default void dismissKeyboardShortcutsMenu() { }
+ default void toggleKeyboardShortcutsMenu(int deviceId) { }
+ default void cancelPreloadRecentApps() { }
+ default void setWindowState(int window, int state) { }
+ default void buzzBeepBlinked() { }
+ default void notificationLightOff() { }
+ default void notificationLightPulse(int argb, int onMillis, int offMillis) { }
+ default void showScreenPinningRequest(int taskId) { }
+ default void appTransitionPending() { }
+ default void appTransitionCancelled() { }
+ default void appTransitionStarting(long startTime, long duration) { }
+ default void appTransitionFinished() { }
+ default void showAssistDisclosure() { }
+ default void startAssist(Bundle args) { }
+ default void onCameraLaunchGestureDetected(int source) { }
+ default void showTvPictureInPictureMenu() { }
- void addQsTile(ComponentName tile);
- void remQsTile(ComponentName tile);
- void clickTile(ComponentName tile);
+ default void addQsTile(ComponentName tile) { }
+ default void remQsTile(ComponentName tile) { }
+ default void clickTile(ComponentName tile) { }
- void handleSystemNavigationKey(int arg1);
+ default void handleSystemNavigationKey(int arg1) { }
}
- public CommandQueue(Callbacks callbacks) {
- mCallbacks = callbacks;
+ @VisibleForTesting
+ protected CommandQueue() {
+ }
+
+ public void addCallbacks(Callbacks callbacks) {
+ Callbacks[] newArray = new Callbacks[mCallbacks.length + 1];
+ for (int i = 0; i < newArray.length - 1; i++) {
+ newArray[i] = mCallbacks[i];
+ if (newArray[i] == callbacks) {
+ throw new IllegalArgumentException("Callback was already added");
+ }
+ }
+ newArray[newArray.length - 1] = callbacks;
+ mCallbacks = newArray;
}
public void setIcon(String slot, StatusBarIcon icon) {
@@ -328,8 +344,8 @@
public void appTransitionCancelled() {
synchronized (mLock) {
- mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
- mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+ mHandler.removeMessages(MSG_APP_TRANSITION_CANCELLED);
+ mHandler.sendEmptyMessage(MSG_APP_TRANSITION_CANCELLED);
}
}
@@ -400,6 +416,10 @@
}
private final class H extends Handler {
+ private H(Looper l) {
+ super(l);
+ }
+
public void handleMessage(Message msg) {
final int what = msg.what & MSG_MASK;
switch (what) {
@@ -407,118 +427,195 @@
switch (msg.arg1) {
case OP_SET_ICON: {
Pair<String, StatusBarIcon> p = (Pair<String, StatusBarIcon>) msg.obj;
- mCallbacks.setIcon(p.first, p.second);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].setIcon(p.first, p.second);
+ }
break;
}
case OP_REMOVE_ICON:
- mCallbacks.removeIcon((String) msg.obj);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].removeIcon((String) msg.obj);
+ }
break;
}
break;
}
case MSG_DISABLE:
- mCallbacks.disable(msg.arg1, msg.arg2, true /* animate */);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].disable(msg.arg1, msg.arg2, true /* animate */);
+ }
break;
case MSG_EXPAND_NOTIFICATIONS:
- mCallbacks.animateExpandNotificationsPanel();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].animateExpandNotificationsPanel();
+ }
break;
case MSG_COLLAPSE_PANELS:
- mCallbacks.animateCollapsePanels(0);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].animateCollapsePanels(0);
+ }
break;
case MSG_EXPAND_SETTINGS:
- mCallbacks.animateExpandSettingsPanel((String) msg.obj);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].animateExpandSettingsPanel((String) msg.obj);
+ }
break;
case MSG_SET_SYSTEMUI_VISIBILITY:
SomeArgs args = (SomeArgs) msg.obj;
- mCallbacks.setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
- args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
+ args.argi4, (Rect) args.arg1, (Rect) args.arg2);
+ }
args.recycle();
break;
case MSG_TOP_APP_WINDOW_CHANGED:
- mCallbacks.topAppWindowChanged(msg.arg1 != 0);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].topAppWindowChanged(msg.arg1 != 0);
+ }
break;
case MSG_SHOW_IME_BUTTON:
- mCallbacks.setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
- msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
+ msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
+ }
break;
case MSG_SHOW_RECENT_APPS:
- mCallbacks.showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+ }
break;
case MSG_HIDE_RECENT_APPS:
- mCallbacks.hideRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].hideRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+ }
break;
case MSG_TOGGLE_RECENT_APPS:
- mCallbacks.toggleRecentApps();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].toggleRecentApps();
+ }
break;
case MSG_PRELOAD_RECENT_APPS:
- mCallbacks.preloadRecentApps();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].preloadRecentApps();
+ }
break;
case MSG_CANCEL_PRELOAD_RECENT_APPS:
- mCallbacks.cancelPreloadRecentApps();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].cancelPreloadRecentApps();
+ }
break;
case MSG_DISMISS_KEYBOARD_SHORTCUTS:
- mCallbacks.dismissKeyboardShortcutsMenu();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].dismissKeyboardShortcutsMenu();
+ }
break;
case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
- mCallbacks.toggleKeyboardShortcutsMenu(msg.arg1);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].toggleKeyboardShortcutsMenu(msg.arg1);
+ }
break;
case MSG_SET_WINDOW_STATE:
- mCallbacks.setWindowState(msg.arg1, msg.arg2);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].setWindowState(msg.arg1, msg.arg2);
+ }
break;
case MSG_BUZZ_BEEP_BLINKED:
- mCallbacks.buzzBeepBlinked();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].buzzBeepBlinked();
+ }
break;
case MSG_NOTIFICATION_LIGHT_OFF:
- mCallbacks.notificationLightOff();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].notificationLightOff();
+ }
break;
case MSG_NOTIFICATION_LIGHT_PULSE:
- mCallbacks.notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
+ }
break;
case MSG_SHOW_SCREEN_PIN_REQUEST:
- mCallbacks.showScreenPinningRequest(msg.arg1);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].showScreenPinningRequest(msg.arg1);
+ }
break;
case MSG_APP_TRANSITION_PENDING:
- mCallbacks.appTransitionPending();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].appTransitionPending();
+ }
break;
case MSG_APP_TRANSITION_CANCELLED:
- mCallbacks.appTransitionCancelled();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].appTransitionCancelled();
+ }
break;
case MSG_APP_TRANSITION_STARTING:
- Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
- mCallbacks.appTransitionStarting(data.first, data.second);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
+ mCallbacks[i].appTransitionStarting(data.first, data.second);
+ }
break;
case MSG_APP_TRANSITION_FINISHED:
- mCallbacks.appTransitionFinished();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].appTransitionFinished();
+ }
break;
case MSG_ASSIST_DISCLOSURE:
- mCallbacks.showAssistDisclosure();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].showAssistDisclosure();
+ }
break;
case MSG_START_ASSIST:
- mCallbacks.startAssist((Bundle) msg.obj);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].startAssist((Bundle) msg.obj);
+ }
break;
case MSG_CAMERA_LAUNCH_GESTURE:
- mCallbacks.onCameraLaunchGestureDetected(msg.arg1);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].onCameraLaunchGestureDetected(msg.arg1);
+ }
break;
case MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU:
- mCallbacks.showTvPictureInPictureMenu();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].showTvPictureInPictureMenu();
+ }
break;
case MSG_ADD_QS_TILE:
- mCallbacks.addQsTile((ComponentName) msg.obj);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].addQsTile((ComponentName) msg.obj);
+ }
break;
case MSG_REMOVE_QS_TILE:
- mCallbacks.remQsTile((ComponentName) msg.obj);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].remQsTile((ComponentName) msg.obj);
+ }
break;
case MSG_CLICK_QS_TILE:
- mCallbacks.clickTile((ComponentName) msg.obj);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].clickTile((ComponentName) msg.obj);
+ }
break;
case MSG_TOGGLE_APP_SPLIT_SCREEN:
- mCallbacks.toggleSplitScreen();
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].toggleSplitScreen();
+ }
break;
case MSG_HANDLE_SYSNAV_KEY:
- mCallbacks.handleSystemNavigationKey(msg.arg1);
+ for (int i = 0; i < mCallbacks.length; i++) {
+ mCallbacks[i].handleSystemNavigationKey(msg.arg1);
+ }
break;
}
}
}
+
+ // Need this class since CommandQueue already extends IStatusBar.Stub, so CommandQueueStart
+ // is needed so it can extend SystemUI.
+ public static class CommandQueueStart extends SystemUI {
+ @Override
+ public void start() {
+ putComponent(CommandQueue.class, new CommandQueue());
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
deleted file mode 100644
index db46dc6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Log;
-
-import java.util.Arrays;
-
-/**
- * Manages a persistent connection to a service component defined in a secure setting.
- *
- * <p>If a valid service component is specified in the secure setting, starts it up and keeps it
- * running; handling setting changes, package updates, component disabling, and unexpected
- * process termination.
- *
- * <p>Clients can listen for important events using the supplied {@link Callbacks}.
- */
-public class ServiceMonitor {
- private static final int RECHECK_DELAY = 2000;
- private static final int WAIT_FOR_STOP = 500;
-
- public interface Callbacks {
- /** The service does not exist or failed to bind */
- void onNoService();
- /** The service is about to start, this is a chance to perform cleanup and
- * delay the start if necessary */
- long onServiceStartAttempt();
- }
-
- // internal handler + messages used to serialize access to internal state
- public static final int MSG_START_SERVICE = 1;
- public static final int MSG_CONTINUE_START_SERVICE = 2;
- public static final int MSG_STOP_SERVICE = 3;
- public static final int MSG_PACKAGE_INTENT = 4;
- public static final int MSG_CHECK_BOUND = 5;
- public static final int MSG_SERVICE_DISCONNECTED = 6;
-
- private final Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case MSG_START_SERVICE:
- startService();
- break;
- case MSG_CONTINUE_START_SERVICE:
- continueStartService();
- break;
- case MSG_STOP_SERVICE:
- stopService();
- break;
- case MSG_PACKAGE_INTENT:
- packageIntent((Intent)msg.obj);
- break;
- case MSG_CHECK_BOUND:
- checkBound();
- break;
- case MSG_SERVICE_DISCONNECTED:
- serviceDisconnected((ComponentName)msg.obj);
- break;
- }
- }
- };
-
- private final ContentObserver mSettingObserver = new ContentObserver(mHandler) {
- public void onChange(boolean selfChange) {
- onChange(selfChange, null);
- }
-
- public void onChange(boolean selfChange, Uri uri) {
- if (mDebug) Log.d(mTag, "onChange selfChange=" + selfChange + " uri=" + uri);
- ComponentName cn = getComponentNameFromSetting();
- if (cn == null && mServiceName == null || cn != null && cn.equals(mServiceName)) {
- if (mDebug) Log.d(mTag, "skipping no-op restart");
- return;
- }
- if (mBound) {
- mHandler.sendEmptyMessage(MSG_STOP_SERVICE);
- }
- mHandler.sendEmptyMessageDelayed(MSG_START_SERVICE, WAIT_FOR_STOP);
- }
- };
-
- private final class SC implements ServiceConnection, IBinder.DeathRecipient {
- private ComponentName mName;
- private IBinder mService;
-
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (mDebug) Log.d(mTag, "onServiceConnected name=" + name + " service=" + service);
- mName = name;
- mService = service;
- try {
- service.linkToDeath(this, 0);
- } catch (RemoteException e) {
- Log.w(mTag, "Error linking to death", e);
- }
- }
-
- public void onServiceDisconnected(ComponentName name) {
- if (mDebug) Log.d(mTag, "onServiceDisconnected name=" + name);
- boolean unlinked = mService.unlinkToDeath(this, 0);
- if (mDebug) Log.d(mTag, " unlinked=" + unlinked);
- mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
- }
-
- public void binderDied() {
- if (mDebug) Log.d(mTag, "binderDied");
- mHandler.sendMessage(mHandler.obtainMessage(MSG_SERVICE_DISCONNECTED, mName));
- }
- }
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- String pkg = intent.getData().getSchemeSpecificPart();
- if (mServiceName != null && mServiceName.getPackageName().equals(pkg)) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_PACKAGE_INTENT, intent));
- }
- }
- };
-
- private final String mTag;
- private final boolean mDebug;
-
- private final Context mContext;
- private final String mSettingKey;
- private final Callbacks mCallbacks;
-
- private ComponentName mServiceName;
- private SC mServiceConnection;
- private boolean mBound;
-
- public ServiceMonitor(String ownerTag, boolean debug,
- Context context, String settingKey, Callbacks callbacks) {
- mTag = ownerTag + ".ServiceMonitor";
- mDebug = debug;
- mContext = context;
- mSettingKey = settingKey;
- mCallbacks = callbacks;
- }
-
- public void start() {
- // listen for setting changes
- ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
- false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);
-
- // listen for package/component changes
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiver(mBroadcastReceiver, filter);
-
- mHandler.sendEmptyMessage(MSG_START_SERVICE);
- }
-
- private ComponentName getComponentNameFromSetting() {
- String cn = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- mSettingKey, UserHandle.USER_CURRENT);
- return cn == null ? null : ComponentName.unflattenFromString(cn);
- }
-
- // everything below is called on the handler
-
- private void packageIntent(Intent intent) {
- if (mDebug) Log.d(mTag, "packageIntent intent=" + intent
- + " extras=" + bundleToString(intent.getExtras()));
- if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
- mHandler.sendEmptyMessage(MSG_START_SERVICE);
- } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
- || Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
- final PackageManager pm = mContext.getPackageManager();
- final boolean serviceEnabled = isPackageAvailable()
- && pm.getApplicationEnabledSetting(mServiceName.getPackageName())
- != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- && pm.getComponentEnabledSetting(mServiceName)
- != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
- if (mBound && !serviceEnabled) {
- stopService();
- scheduleCheckBound();
- } else if (!mBound && serviceEnabled) {
- startService();
- }
- }
- }
-
- private void stopService() {
- if (mDebug) Log.d(mTag, "stopService");
- boolean stopped = mContext.stopService(new Intent().setComponent(mServiceName));
- if (mDebug) Log.d(mTag, " stopped=" + stopped);
- mContext.unbindService(mServiceConnection);
- mBound = false;
- }
-
- private void startService() {
- mServiceName = getComponentNameFromSetting();
- if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
- if (mServiceName == null) {
- mBound = false;
- mCallbacks.onNoService();
- } else {
- long delay = mCallbacks.onServiceStartAttempt();
- mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
- }
- }
-
- private void continueStartService() {
- if (mDebug) Log.d(mTag, "continueStartService");
- Intent intent = new Intent().setComponent(mServiceName);
- try {
- mServiceConnection = new SC();
- mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
- if (mDebug) Log.d(mTag, "mBound: " + mBound);
- } catch (Throwable t) {
- Log.w(mTag, "Error binding to service: " + mServiceName, t);
- }
- if (!mBound) {
- mCallbacks.onNoService();
- }
- }
-
- private void serviceDisconnected(ComponentName serviceName) {
- if (mDebug) Log.d(mTag, "serviceDisconnected serviceName=" + serviceName
- + " mServiceName=" + mServiceName);
- if (serviceName.equals(mServiceName)) {
- mBound = false;
- scheduleCheckBound();
- }
- }
-
- private void checkBound() {
- if (mDebug) Log.d(mTag, "checkBound mBound=" + mBound);
- if (!mBound) {
- startService();
- }
- }
-
- private void scheduleCheckBound() {
- mHandler.removeMessages(MSG_CHECK_BOUND);
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_BOUND, RECHECK_DELAY);
- }
-
- private static String bundleToString(Bundle bundle) {
- if (bundle == null) return null;
- StringBuilder sb = new StringBuilder("{");
- for (String key : bundle.keySet()) {
- if (sb.length() > 1) sb.append(',');
- Object v = bundle.get(key);
- v = (v instanceof String[]) ? Arrays.asList((String[]) v) : v;
- sb.append(key).append('=').append(v);
- }
- return sb.append('}').toString();
- }
-
- public ComponentName getComponent() {
- return getComponentNameFromSetting();
- }
-
- public void setComponent(ComponentName component) {
- final String setting = component == null ? null : component.flattenToShortString();
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- mSettingKey, setting, UserHandle.USER_CURRENT);
- }
-
- public boolean isPackageAvailable() {
- final ComponentName component = getComponent();
- if (component == null) return false;
- try {
- return mContext.getPackageManager().isPackageAvailable(component.getPackageName());
- } catch (RuntimeException e) {
- Log.w(mTag, "Error checking package availability", e);
- return false;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
index 8819c60..275fd70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java
@@ -27,47 +27,21 @@
import java.io.PrintWriter;
/**
- * Ensure a single status bar service implementation is running at all times.
- *
- * <p>The implementation either comes from a service component running in a remote process (defined
- * using a secure setting), else falls back to using the in-process implementation according
- * to the product config.
+ * Ensure a single status bar service implementation is running at all times, using the in-process
+ * implementation according to the product config.
*/
-public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
+public class SystemBars extends SystemUI {
private static final String TAG = "SystemBars";
private static final boolean DEBUG = false;
private static final int WAIT_FOR_BARS_TO_DIE = 500;
- // manages the implementation coming from the remote process
- private ServiceMonitor mServiceMonitor;
-
// in-process fallback implementation, per the product config
private BaseStatusBar mStatusBar;
@Override
public void start() {
if (DEBUG) Log.d(TAG, "start");
- mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
- mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
- mServiceMonitor.start(); // will call onNoService if no remote service is found
- }
-
- @Override
- public void onNoService() {
- if (DEBUG) Log.d(TAG, "onNoService");
- createStatusBarFromConfig(); // fallback to using an in-process implementation
- }
-
- @Override
- public long onServiceStartAttempt() {
- if (DEBUG) Log.d(TAG, "onServiceStartAttempt mStatusBar="+mStatusBar);
- if (mStatusBar != null) {
- // tear down the in-process version, we'll recreate it again if needed
- mStatusBar.destroy();
- mStatusBar = null;
- return WAIT_FOR_BARS_TO_DIE;
- }
- return 0;
+ createStatusBarFromConfig();
}
@Override
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 bb4b91e..4785ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -49,6 +49,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.util.UserIcons;
import com.android.settingslib.RestrictedLockUtils;
import com.android.systemui.GuestResumeSessionReceiver;
@@ -79,8 +80,6 @@
private static final String ACTION_LOGOUT_USER = "com.android.systemui.LOGOUT_USER";
private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000;
- private static final int ID_REMOVE_GUEST = 1010;
- private static final int ID_LOGOUT_USER = 1011;
private static final String TAG_REMOVE_GUEST = "remove_guest";
private static final String TAG_LOGOUT_USER = "logout_user";
@@ -572,8 +571,8 @@
mContext.getString(R.string.user_logout_notification_action),
logoutPI);
SystemUI.overrideNotificationAppName(mContext, builder);
- NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER, ID_LOGOUT_USER,
- builder.build(), new UserHandle(userId));
+ NotificationManager.from(mContext).notifyAsUser(TAG_LOGOUT_USER,
+ SystemMessage.NOTE_LOGOUT_USER, builder.build(), new UserHandle(userId));
}
};
@@ -595,8 +594,8 @@
mContext.getString(R.string.guest_notification_remove_action),
removeGuestPI);
SystemUI.overrideNotificationAppName(mContext, builder);
- NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
- builder.build(), new UserHandle(guestUserId));
+ NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST,
+ SystemMessage.NOTE_REMOVE_GUEST, builder.build(), new UserHandle(guestUserId));
}
private final Runnable mUnpauseRefreshUsers = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 97d5e10..2c90e62 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -41,6 +41,7 @@
import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SystemUI;
import java.util.List;
@@ -48,11 +49,6 @@
public class StorageNotification extends SystemUI {
private static final String TAG = "StorageNotification";
- private static final int PUBLIC_ID = 0x53505542; // SPUB
- private static final int PRIVATE_ID = 0x53505256; // SPRV
- private static final int DISK_ID = 0x5344534b; // SDSK
- private static final int MOVE_ID = 0x534d4f56; // SMOV
-
private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
private static final String ACTION_FINISH_WIZARD = "com.android.systemui.action.FINISH_WIZARD";
@@ -91,7 +87,8 @@
@Override
public void onVolumeForgotten(String fsUuid) {
// Stop annoying the user
- mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(fsUuid, SystemMessage.NOTE_STORAGE_PRIVATE,
+ UserHandle.ALL);
}
@Override
@@ -119,7 +116,8 @@
public void onReceive(Context context, Intent intent) {
// When finishing the adoption wizard, clean up any notifications
// for moving primary storage
- mNotificationManager.cancelAsUser(null, MOVE_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_STORAGE_MOVE,
+ UserHandle.ALL);
}
};
@@ -190,7 +188,8 @@
final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
if ((info != null && info.isMountedWritable()) || rec.isSnoozed()) {
// Yay, private volume is here, or user snoozed
- mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(fsUuid, SystemMessage.NOTE_STORAGE_PRIVATE,
+ UserHandle.ALL);
} else {
// Boo, annoy the user to reinsert the private volume
@@ -211,8 +210,8 @@
.setDeleteIntent(buildSnoozeIntent(fsUuid));
SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, builder
- .build(), UserHandle.ALL);
+ mNotificationManager.notifyAsUser(fsUuid, SystemMessage.NOTE_STORAGE_PRIVATE,
+ builder.build(), UserHandle.ALL);
}
}
}
@@ -237,12 +236,13 @@
.setCategory(Notification.CATEGORY_ERROR);
SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, builder.build(),
- UserHandle.ALL);
+ mNotificationManager.notifyAsUser(disk.getId(), SystemMessage.NOTE_STORAGE_DISK,
+ builder.build(), UserHandle.ALL);
} else {
// Yay, we have volumes!
- mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(disk.getId(), SystemMessage.NOTE_STORAGE_DISK,
+ UserHandle.ALL);
}
}
@@ -252,7 +252,8 @@
* @param disk The disk that went away.
*/
private void onDiskDestroyedInternal(@NonNull DiskInfo disk) {
- mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(disk.getId(), SystemMessage.NOTE_STORAGE_DISK,
+ UserHandle.ALL);
}
private void onVolumeStateChangedInternal(VolumeInfo vol) {
@@ -308,9 +309,11 @@
}
if (notif != null) {
- mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
+ mNotificationManager.notifyAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC,
+ notif, UserHandle.ALL);
} else {
- mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC,
+ UserHandle.ALL);
}
}
@@ -488,7 +491,7 @@
.setOngoing(true);
SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(move.packageName, MOVE_ID,
+ mNotificationManager.notifyAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
builder.build(), UserHandle.ALL);
}
@@ -496,7 +499,8 @@
if (move.packageName != null) {
// We currently ignore finished app moves; just clear the last
// published progress
- mNotificationManager.cancelAsUser(move.packageName, MOVE_ID, UserHandle.ALL);
+ mNotificationManager.cancelAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
+ UserHandle.ALL);
return;
}
@@ -537,8 +541,8 @@
.setAutoCancel(true);
SystemUI.overrideNotificationAppName(mContext, builder);
- mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, builder.build(),
- UserHandle.ALL);
+ mNotificationManager.notifyAsUser(move.packageName, SystemMessage.NOTE_STORAGE_MOVE,
+ builder.build(), UserHandle.ALL);
}
private int getSmallIcon(DiskInfo disk, int state) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 17dd8d6..0e5ff43 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -99,7 +99,6 @@
private final Vibrator mVibrator;
private final boolean mHasVibrator;
- private boolean mEnabled;
private boolean mDestroyed;
private VolumePolicy mVolumePolicy;
private boolean mShowDndTile = true;
@@ -198,7 +197,6 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(VolumeDialogController.class.getSimpleName() + " state:");
- pw.print(" mEnabled: "); pw.println(mEnabled);
pw.print(" mDestroyed: "); pw.println(mDestroyed);
pw.print(" mVolumePolicy: "); pw.println(mVolumePolicy);
pw.print(" mState: "); pw.println(mState.toString(4));
@@ -749,8 +747,6 @@
private final class SettingObserver extends ContentObserver {
- private final Uri SERVICE_URI = Settings.Secure.getUriFor(
- Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
private final Uri ZEN_MODE_URI =
Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
private final Uri ZEN_MODE_CONFIG_URI =
@@ -761,10 +757,8 @@
}
public void init() {
- mContext.getContentResolver().registerContentObserver(SERVICE_URI, false, this);
mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
- onChange(true, SERVICE_URI);
}
public void destroy() {
@@ -774,17 +768,6 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
boolean changed = false;
- if (SERVICE_URI.equals(uri)) {
- final String setting = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
- final boolean enabled = setting != null && mComponent != null
- && mComponent.equals(ComponentName.unflattenFromString(setting));
- if (enabled == mEnabled) return;
- if (enabled) {
- register();
- }
- mEnabled = enabled;
- }
if (ZEN_MODE_URI.equals(uri)) {
changed = updateZenModeW();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index c820302..73d9ea7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -16,31 +16,13 @@
package com.android.systemui.volume;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
-import android.media.AudioManager;
-import android.media.session.MediaSessionManager;
import android.os.Handler;
-import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.statusbar.ServiceMonitor;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
@@ -52,34 +34,18 @@
private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
private final Handler mHandler = new Handler();
- private final Receiver mReceiver = new Receiver();
- private final RestorationNotification mRestorationNotification = new RestorationNotification();
private boolean mEnabled;
- private AudioManager mAudioManager;
- private NotificationManager mNotificationManager;
- private MediaSessionManager mMediaSessionManager;
- private ServiceMonitor mVolumeControllerService;
-
private VolumeDialogComponent mVolumeComponent;
@Override
public void start() {
mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui);
if (!mEnabled) return;
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- mNotificationManager =
- (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- mMediaSessionManager = (MediaSessionManager) mContext
- .getSystemService(Context.MEDIA_SESSION_SERVICE);
final ZenModeController zenController = new ZenModeControllerImpl(mContext, mHandler);
mVolumeComponent = new VolumeDialogComponent(this, mContext, null, zenController);
putComponent(VolumeComponent.class, getVolumeComponent());
- mReceiver.start();
- mVolumeControllerService = new ServiceMonitor(TAG, LOGD,
- mContext, Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT,
- new ServiceMonitorCallbacks());
- mVolumeControllerService.start();
+ setDefaultVolumeController();
}
private VolumeComponent getVolumeComponent() {
@@ -97,154 +63,12 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print("mEnabled="); pw.println(mEnabled);
if (!mEnabled) return;
- pw.print("mVolumeControllerService="); pw.println(mVolumeControllerService.getComponent());
getVolumeComponent().dump(fd, pw, args);
}
- private void setDefaultVolumeController(boolean register) {
- if (register) {
- DndTile.setVisible(mContext, true);
- if (LOGD) Log.d(TAG, "Registering default volume controller");
- getVolumeComponent().register();
- } else {
- if (LOGD) Log.d(TAG, "Unregistering default volume controller");
- mAudioManager.setVolumeController(null);
- mMediaSessionManager.setRemoteVolumeController(null);
- }
- }
-
- private String getAppLabel(ComponentName component) {
- final String pkg = component.getPackageName();
- try {
- final ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(pkg, 0);
- final String rt = mContext.getPackageManager().getApplicationLabel(ai).toString();
- if (!TextUtils.isEmpty(rt)) {
- return rt;
- }
- } catch (Exception e) {
- Log.w(TAG, "Error loading app label", e);
- }
- return pkg;
- }
-
- private void showServiceActivationDialog(final ComponentName component) {
- final SystemUIDialog d = new SystemUIDialog(mContext);
- d.setMessage(mContext.getString(R.string.volumeui_prompt_message, getAppLabel(component)));
- d.setPositiveButton(R.string.volumeui_prompt_allow, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mVolumeControllerService.setComponent(component);
- }
- });
- d.setNegativeButton(R.string.volumeui_prompt_deny, null);
- d.show();
- }
-
- private final class ServiceMonitorCallbacks implements ServiceMonitor.Callbacks {
- @Override
- public void onNoService() {
- if (LOGD) Log.d(TAG, "onNoService");
- setDefaultVolumeController(true);
- mRestorationNotification.hide();
- if (!mVolumeControllerService.isPackageAvailable()) {
- mVolumeControllerService.setComponent(null);
- }
- }
-
- @Override
- public long onServiceStartAttempt() {
- if (LOGD) Log.d(TAG, "onServiceStartAttempt");
- // poke the setting to update the uid
- mVolumeControllerService.setComponent(mVolumeControllerService.getComponent());
- setDefaultVolumeController(false);
- getVolumeComponent().dismissNow();
- mRestorationNotification.show();
- return 0;
- }
- }
-
- private final class Receiver extends BroadcastReceiver {
- private static final String ENABLE = "com.android.systemui.vui.ENABLE";
- private static final String DISABLE = "com.android.systemui.vui.DISABLE";
- private static final String EXTRA_COMPONENT = "component";
-
- private static final String PREF = "com.android.systemui.PREF";
- private static final String EXTRA_KEY = "key";
- private static final String EXTRA_VALUE = "value";
-
- public void start() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(ENABLE);
- filter.addAction(DISABLE);
- filter.addAction(PREF);
- mContext.registerReceiver(this, filter, null, mHandler);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (PREF.equals(action)) {
- final String key = intent.getStringExtra(EXTRA_KEY);
- if (key != null && intent.getExtras() != null) {
- final Object value = intent.getExtras().get(EXTRA_VALUE);
- if (value == null) {
- Prefs.remove(mContext, key);
- } else if (value instanceof Boolean) {
- Prefs.putBoolean(mContext, key, (Boolean) value);
- } else if (value instanceof Integer) {
- Prefs.putInt(mContext, key, (Integer) value);
- } else if (value instanceof Long) {
- Prefs.putLong(mContext, key, (Long) value);
- }
- }
- return;
- }
- final ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
- final boolean current = component != null
- && component.equals(mVolumeControllerService.getComponent());
- if (ENABLE.equals(action) && component != null) {
- if (!current) {
- showServiceActivationDialog(component);
- }
- }
- if (DISABLE.equals(action) && component != null) {
- if (current) {
- mVolumeControllerService.setComponent(null);
- }
- }
- }
- }
-
- private final class RestorationNotification {
- public void hide() {
- mNotificationManager.cancel(R.id.notification_volumeui);
- }
-
- public void show() {
- final ComponentName component = mVolumeControllerService.getComponent();
- if (component == null) {
- Log.w(TAG, "Not showing restoration notification, component not active");
- return;
- }
- final Intent intent = new Intent(Receiver.DISABLE)
- .putExtra(Receiver.EXTRA_COMPONENT, component);
- Notification.Builder builder = new Notification.Builder(mContext)
- .setSmallIcon(R.drawable.ic_volume_media)
- .setWhen(0)
- .setShowWhen(false)
- .setOngoing(true)
- .setContentTitle(mContext.getString(
- R.string.volumeui_notification_title, getAppLabel(component)))
- .setContentText(mContext.getString(R.string.volumeui_notification_text))
- .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT))
- .setPriority(Notification.PRIORITY_MIN)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
- overrideNotificationAppName(mContext, builder);
- mNotificationManager.notify(R.id.notification_volumeui,
- builder.build());
- }
+ private void setDefaultVolumeController() {
+ DndTile.setVisible(mContext, true);
+ if (LOGD) Log.d(TAG, "Registering default volume controller");
+ getVolumeComponent().register();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index 66e617b..01fd97c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -42,6 +42,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SysuiTestCase;
import org.junit.After;
@@ -143,8 +144,8 @@
// Plugin shouldn't be connected because it is the wrong version.
verify(mMockListener, Mockito.never()).onPluginConnected(
ArgumentCaptor.forClass(Plugin.class).capture());
- verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(R.id.notification_plugin), any(),
- eq(UserHandle.ALL));
+ verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(SystemMessage.NOTE_PLUGIN),
+ any(), eq(UserHandle.ALL));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 63b1817..d5ada67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -27,6 +27,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.PluginManager.PluginInstanceManagerFactory;
@@ -132,7 +133,7 @@
Intent intent = new Intent(PluginManager.DISABLE_PLUGIN);
intent.setData(Uri.parse("package://" + testComponent.flattenToString()));
mPluginManager.onReceive(mContext, intent);
- verify(nm).cancel(eq(testComponent.getClassName()), eq(R.id.notification_plugin));
+ verify(nm).cancel(eq(testComponent.getClassName()), eq(SystemMessage.NOTE_PLUGIN));
verify(pm).setComponentEnabledSetting(eq(testComponent),
eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
eq(PackageManager.DONT_KILL_APP));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 7070961..34cfa7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -22,6 +22,7 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
@@ -34,6 +35,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -76,28 +78,34 @@
public void testShowInvalidChargerNotification_NotifyAsUser() {
mPowerNotificationWarnings.showInvalidChargerWarning();
verify(mMockNotificationManager, times(1))
- .notifyAsUser(anyString(), anyInt(), any(), any());
+ .notifyAsUser(anyString(), eq(SystemMessage.NOTE_BAD_CHARGER), any(), any());
+ verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+ eq(SystemMessage.NOTE_POWER_LOW), any());
}
@Test
public void testDismissInvalidChargerNotification_CancelAsUser() {
mPowerNotificationWarnings.showInvalidChargerWarning();
mPowerNotificationWarnings.dismissInvalidChargerWarning();
- verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+ verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+ eq(SystemMessage.NOTE_BAD_CHARGER), any());
}
@Test
public void testShowLowBatteryNotification_NotifyAsUser() {
mPowerNotificationWarnings.showLowBatteryWarning(false);
verify(mMockNotificationManager, times(1))
- .notifyAsUser(anyString(), anyInt(), any(), any());
+ .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW), any(), any());
+ verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+ eq(SystemMessage.NOTE_BAD_CHARGER), any());
}
@Test
public void testDismissLowBatteryNotification_CancelAsUser() {
mPowerNotificationWarnings.showLowBatteryWarning(false);
mPowerNotificationWarnings.dismissLowBatteryWarning();
- verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+ verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+ eq(SystemMessage.NOTE_POWER_LOW), any());
}
@Test
@@ -105,7 +113,8 @@
mPowerNotificationWarnings.showLowBatteryWarning(false);
ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
verify(mMockNotificationManager)
- .notifyAsUser(anyString(), anyInt(), captor.capture(), any());
+ .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW),
+ captor.capture(), any());
assertEquals(null, captor.getValue().sound);
}
@@ -114,7 +123,8 @@
mPowerNotificationWarnings.showLowBatteryWarning(true);
ArgumentCaptor<Notification> captor = ArgumentCaptor.forClass(Notification.class);
verify(mMockNotificationManager)
- .notifyAsUser(anyString(), anyInt(), captor.capture(), any());
+ .notifyAsUser(anyString(), eq(SystemMessage.NOTE_POWER_LOW),
+ captor.capture(), any());
assertNotEqual(null, captor.getValue().sound);
}
@@ -122,13 +132,14 @@
public void testShowTemperatureWarning_NotifyAsUser() {
mPowerNotificationWarnings.showTemperatureWarning();
verify(mMockNotificationManager, times(1))
- .notifyAsUser(anyString(), anyInt(), any(), any());
+ .notifyAsUser(anyString(), eq(SystemMessage.NOTE_HIGH_TEMP), any(), any());
}
@Test
public void testDismissTemperatureWarning_CancelAsUser() {
mPowerNotificationWarnings.showTemperatureWarning();
mPowerNotificationWarnings.dismissTemperatureWarning();
- verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(), any());
+ verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
+ eq(SystemMessage.NOTE_HIGH_TEMP), any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
new file mode 100644
index 0000000..43f8629
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.ComponentName;
+import android.graphics.Rect;
+import android.os.Bundle;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CommandQueueTest extends SysuiTestCase {
+
+ private CommandQueue mCommandQueue;
+ private Callbacks mCallbacks;
+
+ @Before
+ public void setup() {
+ mCommandQueue = new CommandQueue();
+ mCallbacks = mock(Callbacks.class);
+ mCommandQueue.addCallbacks(mCallbacks);
+ }
+
+ @After
+ public void tearDown() {
+ verifyNoMoreInteractions(mCallbacks);
+ }
+
+ @Test
+ public void testIcon() {
+ String slot = "testSlot";
+ StatusBarIcon icon = mock(StatusBarIcon.class);
+ mCommandQueue.setIcon(slot, icon);
+ waitForIdleSync();
+ verify(mCallbacks).setIcon(eq(slot), eq(icon));
+
+ mCommandQueue.removeIcon(slot);
+ waitForIdleSync();
+ verify(mCallbacks).removeIcon(eq(slot));
+ }
+
+ @Test
+ public void testDisable() {
+ int state1 = 14;
+ int state2 = 42;
+ mCommandQueue.disable(state1, state2);
+ waitForIdleSync();
+ verify(mCallbacks).disable(eq(state1), eq(state2), eq(true));
+ }
+
+ @Test
+ public void testExpandNotifications() {
+ mCommandQueue.animateExpandNotificationsPanel();
+ waitForIdleSync();
+ verify(mCallbacks).animateExpandNotificationsPanel();
+ }
+
+ @Test
+ public void testCollapsePanels() {
+ mCommandQueue.animateCollapsePanels();
+ waitForIdleSync();
+ verify(mCallbacks).animateCollapsePanels(eq(0));
+ }
+
+ @Test
+ public void testExpandSettings() {
+ String panel = "some_panel";
+ mCommandQueue.animateExpandSettingsPanel(panel);
+ waitForIdleSync();
+ verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
+ }
+
+ @Test
+ public void testSetSystemUiVisibility() {
+ Rect r = new Rect();
+ mCommandQueue.setSystemUiVisibility(1, 2, 3, 4, null, r);
+ waitForIdleSync();
+ verify(mCallbacks).setSystemUiVisibility(eq(1), eq(2), eq(3), eq(4), eq(null), eq(r));
+ }
+
+ @Test
+ public void testTopAppWindowChanged() {
+ mCommandQueue.topAppWindowChanged(true);
+ waitForIdleSync();
+ verify(mCallbacks).topAppWindowChanged(eq(true));
+ }
+
+ @Test
+ public void testShowImeButton() {
+ mCommandQueue.setImeWindowStatus(null, 1, 2, true);
+ waitForIdleSync();
+ verify(mCallbacks).setImeWindowStatus(eq(null), eq(1), eq(2), eq(true));
+ }
+
+ @Test
+ public void testShowRecentApps() {
+ mCommandQueue.showRecentApps(true, false);
+ waitForIdleSync();
+ verify(mCallbacks).showRecentApps(eq(true), eq(false));
+ }
+
+ @Test
+ public void testHideRecentApps() {
+ mCommandQueue.hideRecentApps(true, false);
+ waitForIdleSync();
+ verify(mCallbacks).hideRecentApps(eq(true), eq(false));
+ }
+
+ @Test
+ public void testToggleRecentApps() {
+ mCommandQueue.toggleRecentApps();
+ waitForIdleSync();
+ verify(mCallbacks).toggleRecentApps();
+ }
+
+ @Test
+ public void testPreloadRecentApps() {
+ mCommandQueue.preloadRecentApps();
+ waitForIdleSync();
+ verify(mCallbacks).preloadRecentApps();
+ }
+
+ @Test
+ public void testCancelPreloadRecentApps() {
+ mCommandQueue.cancelPreloadRecentApps();
+ waitForIdleSync();
+ verify(mCallbacks).cancelPreloadRecentApps();
+ }
+
+ @Test
+ public void testDismissKeyboardShortcuts() {
+ mCommandQueue.dismissKeyboardShortcutsMenu();
+ waitForIdleSync();
+ verify(mCallbacks).dismissKeyboardShortcutsMenu();
+ }
+
+ @Test
+ public void testToggleKeyboardShortcuts() {
+ mCommandQueue.toggleKeyboardShortcutsMenu(1);
+ waitForIdleSync();
+ verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
+ }
+
+ @Test
+ public void testSetWindowState() {
+ mCommandQueue.setWindowState(1, 2);
+ waitForIdleSync();
+ verify(mCallbacks).setWindowState(eq(1), eq(2));
+ }
+
+ @Test
+ public void testBuzzBeepBlink() {
+ mCommandQueue.buzzBeepBlinked();
+ waitForIdleSync();
+ verify(mCallbacks).buzzBeepBlinked();
+ }
+
+ @Test
+ public void testNotificationLightOff() {
+ mCommandQueue.notificationLightOff();
+ waitForIdleSync();
+ verify(mCallbacks).notificationLightOff();
+ }
+
+ @Test
+ public void testNotificationLightPulse() {
+ mCommandQueue.notificationLightPulse(1, 2, 3);
+ waitForIdleSync();
+ verify(mCallbacks).notificationLightPulse(eq(1), eq(2), eq(3));
+ }
+
+ @Test
+ public void testScreenPinRequest() {
+ mCommandQueue.showScreenPinningRequest(1);
+ waitForIdleSync();
+ verify(mCallbacks).showScreenPinningRequest(eq(1));
+ }
+
+ @Test
+ public void testAppTransitionPending() {
+ mCommandQueue.appTransitionPending();
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionPending();
+ }
+
+ @Test
+ public void testAppTransitionCancelled() {
+ mCommandQueue.appTransitionCancelled();
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionCancelled();
+ }
+
+ @Test
+ public void testAppTransitionStarting() {
+ mCommandQueue.appTransitionStarting(1, 2);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L));
+ }
+
+ @Test
+ public void testAppTransitionFinished() {
+ mCommandQueue.appTransitionFinished();
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionFinished();
+ }
+
+ @Test
+ public void testAssistDisclosure() {
+ mCommandQueue.showAssistDisclosure();
+ waitForIdleSync();
+ verify(mCallbacks).showAssistDisclosure();
+ }
+
+ @Test
+ public void testStartAssist() {
+ Bundle b = new Bundle();
+ mCommandQueue.startAssist(b);
+ waitForIdleSync();
+ verify(mCallbacks).startAssist(eq(b));
+ }
+
+ @Test
+ public void testCameraLaunchGesture() {
+ mCommandQueue.onCameraLaunchGestureDetected(1);
+ waitForIdleSync();
+ verify(mCallbacks).onCameraLaunchGestureDetected(eq(1));
+ }
+
+ @Test
+ public void testShowTvPipMenu() {
+ mCommandQueue.showTvPictureInPictureMenu();
+ waitForIdleSync();
+ verify(mCallbacks).showTvPictureInPictureMenu();
+ }
+
+ @Test
+ public void testAddQsTile() {
+ ComponentName c = new ComponentName("testpkg", "testcls");
+ mCommandQueue.addQsTile(c);
+ waitForIdleSync();
+ verify(mCallbacks).addQsTile(eq(c));
+ }
+
+ @Test
+ public void testRemoveQsTile() {
+ ComponentName c = new ComponentName("testpkg", "testcls");
+ mCommandQueue.remQsTile(c);
+ waitForIdleSync();
+ verify(mCallbacks).remQsTile(eq(c));
+ }
+
+ @Test
+ public void testClickQsTile() {
+ ComponentName c = new ComponentName("testpkg", "testcls");
+ mCommandQueue.clickQsTile(c);
+ waitForIdleSync();
+ verify(mCallbacks).clickTile(eq(c));
+ }
+
+ @Test
+ public void testToggleAppSplitScreen() {
+ mCommandQueue.toggleSplitScreen();
+ waitForIdleSync();
+ verify(mCallbacks).toggleSplitScreen();
+ }
+
+ @Test
+ public void testHandleSysnavKey() {
+ mCommandQueue.handleSystemNavigationKey(1);
+ waitForIdleSync();
+ verify(mCallbacks).handleSystemNavigationKey(eq(1));
+ }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index eed7e70..2048cc8 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3165,6 +3165,13 @@
// CATEGORY: Settings
DIALOG_SUPPORT_SYSTEM_INFORMATION = 756;
+ // These values should never appear in log outputs - they are reserved for
+ // internal Tron use.
+ RESERVED_FOR_LOGBUILDER_VIEW = 757;
+ RESERVED_FOR_LOGBUILDER_CATEGORY = 758;
+ RESERVED_FOR_LOGBUILDER_TYPE = 759;
+
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
new file mode 100644
index 0000000..5b91776
--- /dev/null
+++ b/proto/src/system_messages.proto
@@ -0,0 +1,79 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+
+option java_package = "com.android.internal.messages";
+option java_outer_classname = "SystemMessageProto";
+
+package com_android_notifications;
+
+// Descriptors for system messages: notifications, dialogs, toasts, etc.
+message SystemMessage {
+
+ // System message IDs
+ // These are non-consecutive in order to preserve some existing, ad hoc IDs.
+ enum ID {
+ // Unknown
+ NOTE_UNKNOWN = 0;
+
+ // Notify the user that a screenshot was captured.
+ // Package: com.android.systemui
+ NOTE_GLOBAL_SCREENSHOT = 1;
+
+ // Warn the user about an invalid charger.
+ // Package: com.android.systemui
+ NOTE_BAD_CHARGER = 2;
+
+ // Warn the user about low battery.
+ // Package: com.android.systemui
+ NOTE_POWER_LOW = 3;
+
+ // Warn the user that the device has gotten warm.
+ // Package: com.android.systemui
+ NOTE_HIGH_TEMP = 4;
+
+ // Warn the user that some notifications are hidden.
+ // Package: com.android.systemui
+ NOTE_HIDDEN_NOTIFICATIONS = 5;
+
+ // Notify the user of a problem with a plugin (dev devices only).
+ // Package: com.android.systemui
+ NOTE_PLUGIN = 6;
+
+ // Confirm that the user wants to remove the guest account.
+ // Package: com.android.systemui
+ NOTE_REMOVE_GUEST = 1010;
+
+ // Confirm that the user wants to log out of the device.
+ // Package: com.android.systemui
+ NOTE_LOGOUT_USER = 1011;
+
+ // Notify the user about public volume state changes..
+ // Package: com.android.systemui
+ NOTE_STORAGE_PUBLIC = 0x53505542;
+
+ // Notify the user about private volume state changes.
+ // Package: com.android.systemui
+ NOTE_STORAGE_PRIVATE = 0x53505256;
+
+ // Notify the user about an unsupported storage device..
+ // Package: com.android.systemui
+ NOTE_STORAGE_DISK = 0x5344534b;
+
+ // Notify the user that data or apps are being moved to external storage.
+ // Package: com.android.systemui
+ NOTE_STORAGE_MOVE = 0x534d4f56;
+ }
+}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 573ad63..dd550f2 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -347,13 +347,14 @@
+ ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
+ ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent
+ ", maxChargingVoltage" + mBatteryProps.maxChargingVoltage
- + ", chargeCounter" + mBatteryProps.batteryChargeCounter
+ ", batteryStatus=" + mBatteryProps.batteryStatus
+ ", batteryHealth=" + mBatteryProps.batteryHealth
+ ", batteryPresent=" + mBatteryProps.batteryPresent
+ ", batteryLevel=" + mBatteryProps.batteryLevel
+ ", batteryTechnology=" + mBatteryProps.batteryTechnology
+ ", batteryVoltage=" + mBatteryProps.batteryVoltage
+ + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter
+ + ", batteryFullCharge=" + mBatteryProps.batteryFullCharge
+ ", batteryTemperature=" + mBatteryProps.batteryTemperature
+ ", mBatteryLevelCritical=" + mBatteryLevelCritical
+ ", mPlugType=" + mPlugType);
@@ -363,7 +364,8 @@
try {
mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
- mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter);
+ mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter,
+ mBatteryProps.batteryFullCharge);
} catch (RemoteException e) {
// Should never happen.
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7572dfe..f271b08 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4597,9 +4597,28 @@
} catch (Exception e) {
loge("Exception in setDnsConfigurationForNetwork: " + e);
}
+ final NetworkAgentInfo defaultNai = getDefaultNetwork();
+ if (defaultNai != null && defaultNai.network.netId == netId) {
+ setDefaultDnsSystemProperties(dnses);
+ }
flushVmDnsCache();
}
+ private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
+ int last = 0;
+ for (InetAddress dns : dnses) {
+ ++last;
+ String key = "net.dns" + last;
+ String value = dns.getHostAddress();
+ SystemProperties.set(key, value);
+ }
+ for (int i = last + 1; i <= mNumDnsEntries; ++i) {
+ String key = "net.dns" + i;
+ SystemProperties.set(key, "");
+ }
+ mNumDnsEntries = last;
+ }
+
private String getNetworkPermission(NetworkCapabilities nc) {
// TODO: make these permission strings AIDL constants instead.
if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
@@ -4816,6 +4835,7 @@
notifyLockdownVpn(newNetwork);
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork);
+ setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
}
private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 983d039..cef459a 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -34,9 +34,9 @@
import android.net.INetworkScoreCache;
import android.net.INetworkScoreService;
import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
import android.net.NetworkScorerAppManager;
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
-import android.net.NetworkScoreManager;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -380,13 +380,16 @@
}
}
+ private boolean isCallerSystemUid() {
+ // REQUEST_NETWORK_SCORES is a signature only permission.
+ return mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES) ==
+ PackageManager.PERMISSION_GRANTED;
+ }
+
@Override
public boolean clearScores() {
- // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
- // should be allowed to flush all scores.
- if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
- mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
- PackageManager.PERMISSION_GRANTED) {
+ // Only the active scorer or the system should be allowed to flush all scores.
+ if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
final long token = Binder.clearCallingIdentity();
try {
clearInternal();
@@ -409,7 +412,6 @@
// In the future, should this API be opened to 3p apps, we will need to lock this down and
// figure out another way to streamline the UX.
- // mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG);
// Scorers (recommendation providers) are selected and no longer set.
@@ -418,11 +420,8 @@
@Override
public void disableScoring() {
- // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
- // should be allowed to disable scoring.
- if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
- mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
- PackageManager.PERMISSION_GRANTED) {
+ // Only the active scorer or the system should be allowed to disable scoring.
+ if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) || isCallerSystemUid()) {
// no-op for now but we could write to the setting if needed.
} else {
throw new SecurityException(
@@ -450,7 +449,7 @@
public void registerNetworkScoreCache(int networkType,
INetworkScoreCache scoreCache,
int filterType) {
- mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+ mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
final long token = Binder.clearCallingIdentity();
try {
synchronized (mScoreCaches) {
@@ -475,7 +474,7 @@
@Override
public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
- mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+ mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
final long token = Binder.clearCallingIdentity();
try {
synchronized (mScoreCaches) {
@@ -496,7 +495,7 @@
@Override
public RecommendationResult requestRecommendation(RecommendationRequest request) {
- mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+ mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
throwIfCalledOnMainThread();
final long token = Binder.clearCallingIdentity();
try {
@@ -526,7 +525,7 @@
@Override
public boolean requestScores(NetworkKey[] networks) {
- mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+ mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
final long token = Binder.clearCallingIdentity();
try {
final INetworkRecommendationProvider provider = getRecommendationProvider();
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 11e1a9d..14c6529 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -63,8 +63,8 @@
import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -76,6 +76,7 @@
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -111,15 +112,16 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
-import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
@@ -174,17 +176,18 @@
private static final String PRE_N_DATABASE_NAME = "accounts.db";
private static final Intent ACCOUNTS_CHANGED_INTENT;
+ private static final int SIGNATURE_CHECK_MISMATCH = 0;
+ private static final int SIGNATURE_CHECK_MATCH = 1;
+ private static final int SIGNATURE_CHECK_UID_MATCH = 2;
+
static {
ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
}
-
private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
private final AtomicInteger mNotificationIds = new AtomicInteger(1);
- private static final String NEW_ACCOUNT_VISIBLE = "android.accounts.NEW_ACCOUNT_VISIBLE";
-
static class UserAccounts {
private final int userId;
final AccountsDb accountsDb;
@@ -204,6 +207,10 @@
/** protected by the {@link #cacheLock} */
private final TokenCache accountTokenCaches = new TokenCache();
+ /** protected by the {@link #cacheLock} */
+ private final Map<String, LinkedHashSet<String>>
+ mApplicationAccountRequestMappings = new HashMap<>();
+
/**
* protected by the {@link #cacheLock}
*
@@ -285,7 +292,26 @@
@Override
public void run() {
purgeOldGrantsAll();
- // TODO remove visibility entries.
+ int uidOfUninstalledApplication =
+ intent.getIntExtra(Intent.EXTRA_UID, -1);
+ /* remove visibility data for UID */
+ if (uidOfUninstalledApplication != -1) {
+ UserAccounts ua = getUserAccounts(UserHandle
+ .getUserId(uidOfUninstalledApplication));
+ // Stop sending notifications about accounts change to uninstalled
+ // application.
+ Uri intentData = intent.getData();
+ String packageName = intentData != null
+ ? intentData.getSchemeSpecificPart() : null;
+ unregisterAccountTypesSupported(packageName, ua);
+ String[] allPackages = mPackageManager
+ .getPackagesForUid(uidOfUninstalledApplication);
+ // Check that there are no other packages that share uid.
+ if (allPackages == null) {
+ deleteAccountVisibilityForUid(uidOfUninstalledApplication, ua);
+ }
+ }
+
}
};
mHandler.post(purgingRunnable);
@@ -310,7 +336,8 @@
registerAccountTypesSupported(
uidOfInstalledApplication,
getUserAccounts(
- UserHandle.getUserId(uidOfInstalledApplication)));
+ UserHandle.getUserId(uidOfInstalledApplication)),
+ true /*notify*/);
}
}
});
@@ -380,11 +407,13 @@
final long identity = Binder.clearCallingIdentity();
try {
for (String packageName : packageNames) {
- if (mPackageManager.checkPermission(
- Manifest.permission.GET_ACCOUNTS, packageName)
- != PackageManager.PERMISSION_GRANTED) {
- continue;
- }
+ // if app asked for permission we need to cancel notification even
+ // for O+ applications.
+ if (mPackageManager.checkPermission(
+ Manifest.permission.GET_ACCOUNTS,
+ packageName) != PackageManager.PERMISSION_GRANTED) {
+ continue;
+ }
if (accounts == null) {
accounts = getAccountsAsUser(null, userId, "android");
@@ -405,6 +434,10 @@
});
}
+ private boolean deleteAccountVisibilityForUid(int uid, UserAccounts accounts) {
+ return accounts.accountsDb.deleteAccountVisibilityForUid(uid);
+ }
+
private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
boolean checkAccess) {
Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
@@ -443,22 +476,95 @@
}
@Override
- public boolean addAccountExplicitlyWithVisibility(Account account, String password, Bundle extras,
- Map uidToVisibility) {
- // TODO implementation
- return false;
+ public boolean addAccountExplicitlyWithVisibility(Account account, String password,
+ Bundle extras, Map uidToVisibility) {
+ Bundle.setDefusable(extras, true);
+
+ final int callingUid = Binder.getCallingUid();
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "addAccountExplicitly: " + account + ", caller's uid " + callingUid
+ + ", pid " + Binder.getCallingPid());
+ }
+ Preconditions.checkNotNull(account, "account cannot be null");
+ int userId = UserHandle.getCallingUserId();
+ if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
+ String msg = String.format("uid %s cannot explicitly add accounts of type: %s",
+ callingUid, account.type);
+ throw new SecurityException(msg);
+ }
+ /*
+ * Child users are not allowed to add accounts. Only the accounts that are shared by the
+ * parent profile can be added to child profile.
+ *
+ * TODO: Only allow accounts that were shared to be added by a limited user.
+ */
+ // fails if the account already exists
+ long identityToken = clearCallingIdentity();
+ try {
+ UserAccounts accounts = getUserAccounts(userId);
+ return addAccountInternal(accounts, account, password, extras, callingUid,
+ (Map<Integer, Integer>) uidToVisibility);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
}
@Override
public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
String accountType) {
- // TODO Implement.
- return new HashMap<Account, Integer>();
+ int callingUid = Binder.getCallingUid();
+ List<String> managedTypes =
+ getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
+ if ((accountType != null && !managedTypes.contains(accountType))
+ || (accountType == null && !UserHandle.isSameApp(callingUid, Process.SYSTEM_UID))) {
+ throw new SecurityException(
+ "getAccountsAndVisibilityForPackage() called from unauthorized uid "
+ + callingUid + " with packageName=" + packageName);
+ }
+ if (accountType != null) {
+ managedTypes = new ArrayList<String>();
+ managedTypes.add(accountType);
+ }
+
+ return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
+ getUserAccounts(UserHandle.getUserId(callingUid)));
}
+ /*
+ * accountTypes may not be null
+ */
+ private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
+ List<String> accountTypes, Integer callingUid, UserAccounts accounts) {
+ int uid = 0;
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName,
+ UserHandle.getUserId(callingUid));
+ } catch (NameNotFoundException e) {
+ Log.d("Package not found ", e.getMessage());
+ return new HashMap<>();
+ }
+
+ Map<Account, Integer> result = new HashMap<>();
+ for (String accountType : accountTypes) {
+ synchronized (accounts.cacheLock) {
+ final Account[] accountsOfType = accounts.accountCache.get(accountType);
+ if (accountsOfType != null) {
+ for (Account account : accountsOfType) {
+ result.put(account,
+ resolveAccountVisibility(account, uid, packageName, accounts));
+ }
+ }
+ }
+ }
+ return filterSharedAccounts(accounts, result, callingUid, packageName);
+ }
+
+
@Override
public int[] getRequestingUidsForType(String accountType) {
int callingUid = Binder.getCallingUid();
+ UserAccounts accounts = getUserAccounts(
+ UserHandle.getUserId(callingUid));
if (!isAccountManagedByCaller(accountType, callingUid, UserHandle.getUserId(callingUid))) {
String msg = String.format(
"uid %s cannot get secrets for accounts of type: %s",
@@ -466,33 +572,287 @@
accountType);
throw new SecurityException(msg);
}
- // TODO Implement.
- return new int[]{};
+ LinkedHashSet<String> allUidsForAccountType = getRequestingPackageNames(accountType, accounts);
+ LinkedHashSet<Integer> uids = new LinkedHashSet<Integer>();
+ for (String packageName : allUidsForAccountType) {
+ try {
+ int uid = mPackageManager.getPackageUid(packageName, 0);
+ uids.add(uid);
+ } catch (NameNotFoundException e) {
+ Log.d("Package not found ", e.getMessage());
+ // Skip bad package.
+ }
+ }
+ // Add UIDs for which visibility was saved in the database.
+ synchronized (accounts.cacheLock) {
+ final Account[] accountsOfType = accounts.accountCache.get(accountType);
+ if (accountsOfType != null) {
+ for (Account account : accountsOfType) {
+ final long accountId = accounts.accountsDb.findDeAccountId(account);
+ if (accountId < 0) {
+ continue;
+ }
+ Map<Integer, Integer> uidToVisibility =
+ accounts.accountsDb.findAccountVisibilityForAccountId(accountId);
+ uids.addAll(uidToVisibility.keySet());
+ }
+ }
+ }
+ uids.remove(AccountManager.DEFAULT_VISIBILITY);
+ uids.remove(AccountManager.DEFAULT_LEGACY_VISIBILITY);
+
+ // Some UIDs may contain many packages and we need to remove duplicates.
+ int[] result = new int[uids.size()];
+ int index = 0;
+ for (Integer uid : uids) {
+ result[index++] = uid;
+ }
+ return result;
+ }
+
+ /**
+ * Returns all UIDs for applications that requested the account type. This method
+ * is called indirectly by the Authenticator and AccountManager
+ *
+ * @param accountType authenticator would like to know the requesting apps of
+ * @param accounts UserAccount that currently hosts the account and application
+ *
+ * @return ArrayList of all UIDs that support accounts of this
+ * account type that seek approval (to be used to know which accounts for
+ * the authenticator to include in addAccountExplicitly). Null if none.
+ */
+ private LinkedHashSet<String> getRequestingPackageNames(
+ String accountType,
+ UserAccounts accounts) {
+ LinkedHashSet<String> apps = accounts.mApplicationAccountRequestMappings.get(accountType);
+ if (apps == null) {
+ apps = new LinkedHashSet<>();
+ }
+ return apps;
}
@Override
public int getAccountVisibility(Account a, int uid) {
- // TODO Implement.
- return 0;
- }
-
- @Override
- public boolean setAccountVisibility(Account a, int uid, int visibility) {
- // TODO Implement.
- return false;
+ int callingUid = Binder.getCallingUid();
+ if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+ && !isSystemUid(callingUid)) {
+ String msg = String.format(
+ "uid %s cannot get secrets for accounts of type: %s",
+ callingUid,
+ a.type);
+ throw new SecurityException(msg);
+ }
+ return getAccountVisibility(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)));
}
/**
- * Registers the requested login account types requested by all the applications already
- * installed on the device.
+ * Method gets visibility for given account and UID from the database
+ *
+ * @param account The account to check visibility of
+ * @param uid UID to check visibility of
+ * @param accounts UserAccount that currently hosts the account and application
+ *
+ * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored.
+ *
+ */
+ private int getAccountVisibility(Account account, int uid, UserAccounts accounts) {
+ final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ Integer visibility = accounts.accountsDb.findAccountVisibility(account, uid);
+ return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED;
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ /**
+ * Method which handles default values for Account visibility.
+ *
+ * @param account The account to check visibility.
+ * @param uid UID to check visibility.
+ * @param packageName Package name to check visibility - the method assumes that it has the same
+ * uid as specified in the parameter.
+ * @param accounts UserAccount that currently hosts the account and application
+ *
+ * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED
+ *
+ */
+ private Integer resolveAccountVisibility(Account account, int uid, String packageName,
+ UserAccounts accounts) {
+
+ // Always return stored value if it was set.
+ int visibility = getAccountVisibility(account, uid, accounts);
+ if (AccountManager.VISIBILITY_UNDEFINED != visibility) {
+ return visibility;
+ }
+ if (isPermittedForPackage(packageName, Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
+ return AccountManager.VISIBILITY_VISIBLE; // User can not revoke visibility for this
+ // apps.
+ }
+
+ if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) {
+ return AccountManager.VISIBILITY_VISIBLE;
+ }
+ int signatureCheckResult =
+ checkPackageSignature(account.type, uid, UserHandle.getUserId(uid), packageName);
+ if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) { // uid match
+ return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account
+ }
+
+ boolean preO = isPreOApplication(packageName);
+ if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH)
+ || (preO && checkGetAccountsPermission(account.type, uid, UserHandle.getUserId(uid),
+ packageName))) {
+ // use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature
+ // match.
+ visibility = getAccountVisibility(account, AccountManager.DEFAULT_LEGACY_VISIBILITY,
+ accounts);
+ if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
+ visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
+ }
+ } else {
+ visibility = getAccountVisibility(account, AccountManager.DEFAULT_VISIBILITY, accounts);
+ if (AccountManager.VISIBILITY_UNDEFINED == visibility) {
+ visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
+ }
+ }
+
+ return visibility;
+ }
+
+ /**
+ * Checks targetSdk for a package;
+ *
+ * @param packageName Package Name
+ *
+ * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or
+ * undefined
+ */
+ private boolean isPreOApplication(String packageName) {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
+ if (applicationInfo != null) {
+ int version = applicationInfo.targetSdkVersion;
+ return version < android.os.Build.VERSION_CODES.O;
+ }
+ return true;
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
+ return true;
+ }
+ }
+
+ @Override
+ public boolean setAccountVisibility(Account a, int uid, int newVisibility) {
+ int callingUid = Binder.getCallingUid();
+ if (!isAccountManagedByCaller(a.type, callingUid, UserHandle.getUserId(callingUid))
+ && !isSystemUid(callingUid)) {
+ String msg = String.format(
+ "uid %s cannot get secrets for accounts of type: %s",
+ callingUid,
+ a.type);
+ throw new SecurityException(msg);
+ }
+ return setAccountVisibility(a, uid, getUserAccounts(UserHandle.getUserId(callingUid)),
+ newVisibility);
+ }
+
+ /**
+ * Gives a certain UID, represented a application, access to an account. This method
+ * is called indirectly by the Authenticator.
+ *
+ * @param account Account to update visibility
+ * @param uid to add visibility of the Account
+ * @param accounts UserAccount that currently hosts the account and application
+ *
+ * @return True if account visibility was changed.
+ */
+ private boolean setAccountVisibility(Account account, int uid, UserAccounts accounts,
+ int newVisibility) {
+ synchronized (accounts.cacheLock) {
+ LinkedHashSet<String> interestedPackages;
+ if (uid < 0) {
+ interestedPackages = getRequestingPackageNames(account.type, accounts);
+ } else {
+ interestedPackages = new LinkedHashSet<String>();
+ String[] subPackages = mPackageManager.getPackagesForUid(uid);
+ if (subPackages != null) {
+ Collections.addAll(interestedPackages, subPackages);
+ }
+ }
+ Integer[] interestedPackagesVisibility = new Integer[interestedPackages.size()];
+
+ final long accountId = accounts.accountsDb.findDeAccountId(account);
+ if (accountId < 0) {
+ return false;
+ }
+ int index = 0;
+ for (String packageName : interestedPackages) {
+ interestedPackagesVisibility[index++] =
+ resolveAccountVisibility(account, uid, packageName, accounts);
+ }
+
+ final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+ try {
+ if (!accounts.accountsDb.setAccountVisibility(accountId, uid, newVisibility)) {
+ return false;
+ }
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+
+ index = 0;
+ for (String packageName : interestedPackages) {
+ int visibility = resolveAccountVisibility(account, uid, packageName, accounts);
+ if (visibility != interestedPackagesVisibility[index++]) {
+ sendNotification(packageName, account);
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Register application so it can receive
+ *
+ * @param accountTypes account types third party app is willing to support
+ * @param uid of application requesting account visibility.
+ * @param packageName Package name of the app requesting account updates.
+ * @param notifyAuthenticator if set to true than authenticators will be notified about the app
+ * via ACCOUNTS_LISTENER_PACKAGE_INSTALLED
+ * @param accounts UserAccount that hosts the account and application
+ */
+ private void addRequestedAccountsVisibility(String[] accountTypes, int uid, String packageName,
+ boolean notifyAuthenticator, UserAccounts accounts) {
+ synchronized (accounts.cacheLock) {
+ for (String accountType : accountTypes) {
+ LinkedHashSet<String> appSet =
+ accounts.mApplicationAccountRequestMappings.get(accountType);
+ if (appSet == null) {
+ appSet = new LinkedHashSet<>();
+ appSet.add(packageName);
+ accounts.mApplicationAccountRequestMappings.put(accountType, appSet);
+ } else if (!appSet.contains(packageName)) {
+ appSet.add(packageName);
+ }
+ if (notifyAuthenticator) {
+ notifyAuthenticator(uid, packageName, accountType, accounts);
+ }
+ }
+ }
+ }
+
+ /**
+ * Caches SUPPORTED_ACCOUNT_TYPES for already installed applications, so they may receive
+ * notifications about account changes.
*/
private void addRequestsForPreInstalledApplications() {
List<PackageInfo> allInstalledPackages = mPackageManager.getInstalledPackages(0);
- for(PackageInfo pi : allInstalledPackages) {
+ for (PackageInfo pi : allInstalledPackages) {
int currentUid = pi.applicationInfo.uid;
- if(currentUid != -1) {
+ if (currentUid != -1) {
registerAccountTypesSupported(currentUid,
- getUserAccounts(UserHandle.getUserId(currentUid)));
+ getUserAccounts(UserHandle.getUserId(currentUid)), false /* notify */);
}
}
}
@@ -502,49 +862,90 @@
* applications manifest as well as allowing it to opt for notifications.
*
* @param uid UID of application
- * @param ua UserAccount that currently hosts the account and application
+ * @param accounts UserAccount that currently hosts the account and application
*/
- private void registerAccountTypesSupported(int uid, UserAccounts ua) {
+ private void registerAccountTypesSupported(int uid, UserAccounts accounts, boolean notify) {
/* Account types supported are drawn from the Android Manifest of the Application */
- String interestedPackages = null;
+ String interestedTypes = null;
try {
String[] allPackages = mPackageManager.getPackagesForUid(uid);
if (allPackages != null) {
- for (String aPackage : allPackages) {
+ for(String aPackage : allPackages) {
ApplicationInfo ai = mPackageManager.getApplicationInfo(aPackage,
PackageManager.GET_META_DATA);
Bundle b = ai.metaData;
- if (b == null) {
+ if(b == null) {
return;
}
- interestedPackages = b.getString(AccountManager.SUPPORTED_ACCOUNT_TYPES);
+ interestedTypes = b.getString(AccountManager.SUPPORTED_ACCOUNT_TYPES);
+ if(interestedTypes != null) {
+ addRequestedAccountsVisibility(
+ interestedTypes.split(";"), uid, aPackage, notify, accounts);
+ }
+
}
}
- } catch (PackageManager.NameNotFoundException e) {
- Log.d("NameNotFoundException", e.getMessage());
+ } catch (NameNotFoundException e) {
+ Log.d("Package not found ", e.getMessage());
}
- if (interestedPackages != null) {
- // TODO request visibility
- // requestAccountVisibility(interestedPackages.split(";"), uid, ua);
+ }
+
+ private void unregisterAccountTypesSupported(String packageName, UserAccounts accounts) {
+ synchronized(accounts.cacheLock) {
+ for (HashSet<String> packages : accounts.mApplicationAccountRequestMappings.values()) {
+ packages.remove(packageName);
+ }
}
}
/**
* Sends a direct intent to a package, notifying it of a visible account change.
*
- * @param desiredPackage to send Account to
- * @param visibleAccount to send to package
+ * @param packageName to send Account to
+ * @param account to send to package
*/
- private void sendNotification(String desiredPackage, Account visibleAccount) {
+ private void sendNotification(String packageName, Account account) {
+ // TODO remove account param?
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setAction(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED);
- intent.setPackage(desiredPackage);
- // TODO update documentation, add account extra if new account became visible
- // intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) visibleAccount);
+ intent.setPackage(packageName);
+ // intent.putExtra("android.accounts.KEY_ACCOUNT", (Account) account);
mContext.sendBroadcast(intent);
}
+ /**
+ * Sends a direct intent to accountAuthenticator, signaling that new app with supported
+ * accountType is installed.
+ *
+ * @param uid UID
+ * @param newPackage Package Name
+ * @param accounts UserAccount that currently hosts the account and application
+ */
+ private void notifyAuthenticator(Integer uid, String newPackage, String accountType,
+ UserAccounts accounts) {
+ final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
+ mAuthenticatorCache.getServiceInfo(AuthenticatorDescription.newKey(accountType),
+ accounts.userId);
+ if (authenticatorInfo == null) {
+ return;
+ }
+ String[] allPackages = mPackageManager.getPackagesForUid(authenticatorInfo.uid);
+ // There may be packages with shared userId.
+ if (allPackages != null) {
+ for (String subPackage : allPackages) {
+ Intent intent =
+ new Intent(AccountManager.ACTION_ACCOUNTS_LISTENER_PACKAGE_INSTALLED);
+ intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ intent.setPackage(subPackage);
+ intent.putExtra("android.intent.extra.PACKAGE_NAME", newPackage);
+ mContext.sendBroadcastAsUser(intent,
+ UserHandle.getUserHandleForUid(accounts.userId));
+ }
+
+ }
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
@@ -786,7 +1187,7 @@
AccountsDb.TABLE_ACCOUNTS);
for (Account account : accountsToRemove) {
- removeAccountInternal(accounts, account, Process.myUid());
+ removeAccountInternal(accounts, account, Process.SYSTEM_UID);
}
}
}
@@ -1043,7 +1444,7 @@
private boolean isCrossUser(int callingUid, int userId) {
return (userId != UserHandle.getCallingUserId()
- && callingUid != Process.myUid()
+ && callingUid != Process.SYSTEM_UID
&& mContext.checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED);
@@ -1051,42 +1452,7 @@
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
- Bundle.setDefusable(extras, true);
- // clears the visible list functionality for this account because this method allows
- // default account access to all applications for account.
-
- final int callingUid = Binder.getCallingUid();
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "addAccountExplicitly: " + account
- + ", caller's uid " + callingUid
- + ", pid " + Binder.getCallingPid());
- }
- if (account == null) throw new IllegalArgumentException("account is null");
- int userId = UserHandle.getCallingUserId();
- if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
- String msg = String.format(
- "uid %s cannot explicitly add accounts of type: %s",
- callingUid,
- account.type);
- throw new SecurityException(msg);
- }
-
- /*
- * Child users are not allowed to add accounts. Only the accounts that are
- * shared by the parent profile can be added to child profile.
- *
- * TODO: Only allow accounts that were shared to be added by
- * a limited user.
- */
-
- // fails if the account already exists
- long identityToken = clearCallingIdentity();
- try {
- UserAccounts accounts = getUserAccounts(userId);
- return addAccountInternal(accounts, account, password, extras, callingUid);
- } finally {
- restoreCallingIdentity(identityToken);
- }
+ return addAccountExplicitlyWithVisibility(account, password, extras, null);
}
@Override
@@ -1227,6 +1593,8 @@
// TODO: Anything to do if if succedded?
// TODO: If it failed: Show error notification? Should we remove the shadow
// account to avoid retries?
+ // TODO: what we do with the visibility?
+
super.onResult(result);
}
@@ -1244,7 +1612,7 @@
}
private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
- Bundle extras, int callingUid) {
+ Bundle extras, int callingUid, Map<Integer, Integer> uidToVisibility) {
Bundle.setDefusable(extras, true);
if (account == null) {
return false;
@@ -1284,10 +1652,17 @@
}
}
}
+
+ if (uidToVisibility != null) {
+ for (Entry<Integer, Integer> entry : uidToVisibility.entrySet()) {
+ setAccountVisibility(account, entry.getKey() /* uid */,
+ entry.getValue() /* visibility */);
+ }
+ }
accounts.accountsDb.setTransactionSuccessful();
- logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
- accountId, accounts, callingUid);
+ logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, accountId,
+ accounts, callingUid);
insertAccountIntoCacheLocked(accounts, account);
} finally {
@@ -1300,6 +1675,23 @@
// Only send LOGIN_ACCOUNTS_CHANGED when the database changed.
sendAccountsChangedBroadcast(accounts.userId);
+
+ // Send ACTION_VISIBLE_ACCOUNT_CHANGE to apps interested in the account type.
+ LinkedHashSet<String> interestedPackages = getRequestingPackageNames(account.type,
+ getUserAccounts(UserHandle.getUserId(callingUid)));
+ for (String packageName : interestedPackages) {
+ try {
+ final int uid = mPackageManager.getPackageUidAsUser(packageName,
+ UserHandle.getUserId(callingUid));
+ int visibility = resolveAccountVisibility(account, uid, packageName, accounts);
+ if (visibility != AccountManager.VISIBILITY_NOT_VISIBLE) {
+ sendNotification(packageName, account);
+ }
+ } catch (NameNotFoundException e) {
+ // ignore
+ }
+
+ }
return true;
}
@@ -1727,6 +2119,24 @@
+ " is still locked. CE data will be removed later");
}
synchronized (accounts.cacheLock) {
+ LinkedHashSet<String> interestedPackages =
+ accounts.mApplicationAccountRequestMappings.get(account.type);
+ if (interestedPackages == null) {
+ interestedPackages = new LinkedHashSet<String>();
+ }
+ int[] visibilityForInterestedPackages = new int[interestedPackages.size()];
+ int index = 0;
+ for (String packageName : interestedPackages) {
+ int visibility = AccountManager.VISIBILITY_NOT_VISIBLE;
+ try {
+ final int uid = mPackageManager.getPackageUidAsUser(packageName,
+ UserHandle.getUserId(callingUid));
+ visibility = resolveAccountVisibility(account, uid, packageName, accounts);
+ } catch (NameNotFoundException e) {
+ // ignore
+ }
+ visibilityForInterestedPackages[index++] = visibility;
+ }
accounts.accountsDb.beginTransaction();
// Set to a dummy value, this will only be used if the database
// transaction succeeds.
@@ -1750,6 +2160,17 @@
}
if (isChanged) {
removeAccountFromCacheLocked(accounts, account);
+ index = 0;
+ for (String packageName : interestedPackages) {
+ if ((visibilityForInterestedPackages[index]
+ != AccountManager.VISIBILITY_NOT_VISIBLE)
+ && (visibilityForInterestedPackages[index]
+ != AccountManager.VISIBILITY_UNDEFINED)) {
+ sendNotification(packageName, account);
+ }
+ ++index;
+ }
+
// Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occured.
sendAccountsChangedBroadcast(accounts.userId);
String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
@@ -2406,8 +2827,10 @@
checkKeyIntent(
Binder.getCallingUid(),
intent);
- doNotification(mAccounts,
- account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
+ doNotification(
+ mAccounts,
+ account,
+ result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
intent, "android", accounts.userId);
}
}
@@ -3292,7 +3715,8 @@
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
int userId = UserHandle.getCallingUserId();
- if (!isAccountManagedByCaller(accountType, callingUid, userId) && !isSystemUid(callingUid)) {
+ if (!isAccountManagedByCaller(accountType, callingUid, userId)
+ && !isSystemUid(callingUid)) {
String msg = String.format(
"uid %s cannot edit authenticator properites for account type: %s",
callingUid,
@@ -3335,23 +3759,50 @@
Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete");
try {
- final int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ int uid = mPackageManager.getPackageUidAsUser(packageName, userId);
return hasAccountAccess(account, packageName, uid);
} catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
return false;
}
}
+ // Returns package with oldest target SDK for given UID.
+ private String getPackageNameForUid(int uid) {
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return null;
+ }
+ // For app op checks related to permissions all packages in the UID
+ // have the same app op state, so doesn't matter which one we pick.
+ // Update: due to visibility changes we want to use package with oldest target SDK,
+
+ String packageName = packageNames[0];
+ int oldestVersion = Integer.MAX_VALUE;
+ for (String name : packageNames) {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0);
+ if (applicationInfo != null) {
+ int version = applicationInfo.targetSdkVersion;
+ if (version < oldestVersion) {
+ oldestVersion = version;
+ packageName = name;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ // skip
+ }
+ }
+ return packageName;
+ }
+
private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName,
int uid) {
if (packageName == null) {
- String[] packageNames = mPackageManager.getPackagesForUid(uid);
- if (ArrayUtils.isEmpty(packageNames)) {
+ packageName = getPackageNameForUid(uid);
+ if (packageName == null) {
return false;
}
- // For app op checks related to permissions all packages in the UID
- // have the same app op state, so doesn't matter which one we pick.
- packageName = packageNames[0];
}
// Use null token which means any token. Having a token means the package
@@ -3360,9 +3811,12 @@
return true;
}
// In addition to the permissions required to get an auth token we also allow
- // the account to be accessed by holders of the get accounts permissions.
- return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName)
- || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName);
+ // the account to be accessed by apps for which user or authenticator granted visibility.
+
+ int visibility = resolveAccountVisibility(account, uid, packageName,
+ getUserAccounts(UserHandle.getUserId(uid)));
+ return (visibility == AccountManager.VISIBILITY_VISIBLE
+ || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
}
private boolean checkUidPermission(String permission, int uid, String opPackageName) {
@@ -3476,21 +3930,28 @@
private volatile ArrayList<Account> mAccountsWithFeatures = null;
private volatile int mCurrentAccount = 0;
private final int mCallingUid;
+ private final String mPackageName;
- public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
- IAccountManagerResponse response, String type, String[] features, int callingUid) {
+ public GetAccountsByTypeAndFeatureSession(
+ UserAccounts accounts,
+ IAccountManagerResponse response,
+ String type,
+ String[] features,
+ int callingUid,
+ String packageName) {
super(accounts, response, type, false /* expectActivityLaunch */,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */);
mCallingUid = callingUid;
mFeatures = features;
+ mPackageName = packageName;
}
@Override
public void run() throws RemoteException {
synchronized (mAccounts.cacheLock) {
mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType, mCallingUid,
- null);
+ mPackageName);
}
// check whether each account matches the requested features
mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length);
@@ -3589,7 +4050,7 @@
return getAccountsInternal(
accounts,
callingUid,
- null, // packageName
+ opPackageName,
visibleAccountTypes);
} finally {
restoreCallingIdentity(identityToken);
@@ -3632,7 +4093,7 @@
if (userAccounts == null) continue;
synchronized (userAccounts.cacheLock) {
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null,
- Binder.getCallingUid(), null);
+ Binder.getCallingUid(), null); //TODO check package
for (int a = 0; a < accounts.length; a++) {
runningAccounts.add(new AccountAndUser(accounts[a], userId));
}
@@ -3646,7 +4107,19 @@
@Override
@NonNull
public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
- return getAccountsAsUser(type, userId, null, -1, opPackageName);
+ return getAccountsAsUser(type, userId, null /* callingPackage */, -1, opPackageName);
+ }
+
+ @NonNull
+ private Account[] filterVisibleAccounts(Map<Account, Integer> accounts) {
+ ArrayList<Account> filteredAccounts = new ArrayList<>();
+ for (Map.Entry<Account, Integer> entry : accounts.entrySet()) {
+ if (entry.getValue() == AccountManager.VISIBILITY_VISIBLE
+ || entry.getValue() == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
+ filteredAccounts.add(entry.getKey());
+ }
+ }
+ return filteredAccounts.toArray(new Account[filteredAccounts.size()]);
}
@NonNull
@@ -3659,7 +4132,7 @@
int callingUid = Binder.getCallingUid();
// Only allow the system process to read accounts of other users
if (userId != UserHandle.getCallingUserId()
- && callingUid != Process.myUid()
+ && callingUid != Process.SYSTEM_UID
&& mContext.checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3672,9 +4145,17 @@
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
- // If the original calling app was using the framework account chooser activity, we'll
- // be passed in the original caller's uid here, which is what should be used for filtering.
- if (packageUid != -1 && UserHandle.isSameApp(callingUid, Process.myUid())) {
+
+ // If the original calling app was using account choosing activity
+ // provided by the framework or authenticator we'll passing in
+ // the original caller's uid here, which is what should be used for filtering.
+ List<String> managedTypes =
+ getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid));
+ if (packageUid != -1 &&
+ ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || (type != null && managedTypes.contains(type))))) {
+ Log.v(TAG, "getAccounts package was swithed to " + callingPackage + " from "
+ + opPackageName);
callingUid = packageUid;
opPackageName = callingPackage;
}
@@ -3682,7 +4163,7 @@
opPackageName);
if (visibleAccountTypes.isEmpty()
|| (type != null && !visibleAccountTypes.contains(type))) {
- return new Account[0];
+ return new Account[]{};
} else if (visibleAccountTypes.contains(type)) {
// Prune the list down to just the requested type.
visibleAccountTypes = new ArrayList<>();
@@ -3696,7 +4177,7 @@
return getAccountsInternal(
accounts,
callingUid,
- callingPackage,
+ opPackageName,
visibleAccountTypes);
} finally {
restoreCallingIdentity(identityToken);
@@ -3797,6 +4278,7 @@
@Override
@NonNull
public Account[] getAccounts(String type, String opPackageName) {
+ Log.v(TAG, "get accounts for package " + opPackageName + " type " + type);
return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
}
@@ -3804,7 +4286,7 @@
@NonNull
public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
int callingUid = Binder.getCallingUid();
- if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
+ if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
+ callingUid + " with uid=" + uid);
}
@@ -3816,17 +4298,18 @@
@NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName,
String opPackageName) {
+
int packageUid = -1;
try {
- packageUid = AppGlobals.getPackageManager().getPackageUid(
- packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
- UserHandle.getCallingUserId());
+ packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, UserHandle.getCallingUserId());
} catch (RemoteException re) {
Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
return new Account[0];
}
- return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName,
- packageUid, opPackageName);
+
+ return getAccountsAsUser(type, UserHandle.getCallingUserId(),
+ packageName, packageUid, opPackageName);
}
@Override
@@ -3866,7 +4349,8 @@
if (features == null || features.length == 0) {
Account[] accounts;
synchronized (userAccounts.cacheLock) {
- accounts = getAccountsFromCacheLocked(userAccounts, type, callingUid, null);
+ accounts = getAccountsFromCacheLocked(
+ userAccounts, type, callingUid, opPackageName);
}
Bundle result = new Bundle();
result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
@@ -3878,7 +4362,8 @@
response,
type,
features,
- callingUid).bind();
+ callingUid,
+ opPackageName).bind();
} finally {
restoreCallingIdentity(identityToken);
}
@@ -3897,6 +4382,7 @@
if (Objects.equals(account.getAccessId(), token)) {
// An app just accessed the account. At this point it knows about
// it and there is not need to hide this account from the app.
+ // Do we need to update account visibility here?
if (!hasAccountAccess(account, null, uid)) {
updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE,
uid, true);
@@ -4423,7 +4909,7 @@
userAccounts.accountsDb.dumpDeAccountsTable(fout);
} else {
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
- Process.myUid(), null);
+ Process.SYSTEM_UID, null);
fout.println("Accounts: " + accounts.length);
for (Account account : accounts) {
fout.println(" " + account);
@@ -4516,6 +5002,16 @@
}
}
+ private boolean isPermittedForPackage(String opPackageName, String... permissions) {
+ for (String perm : permissions) {
+ if (mPackageManager.checkPermission(perm, opPackageName)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
for (String perm : permissions) {
if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
@@ -4550,6 +5046,7 @@
userPackageManager = mContext.createPackageContextAsUser(
"android", 0, new UserHandle(callingUserId)).getPackageManager();
} catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
return false;
}
@@ -4563,6 +5060,7 @@
return true;
}
} catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
return false;
}
}
@@ -4617,6 +5115,58 @@
}
}
+ // Method checks visibility for applications targeing API level below {@link
+ // android.os.Build.VERSION_CODES#O},
+ // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVELEGED permission.
+ private boolean checkGetAccountsPermission(String accountType, int callingUid, int userId,
+ String opPackageName) {
+ if (accountType == null) {
+ return false;
+ }
+ if (isPermittedForPackage(opPackageName, Manifest.permission.GET_ACCOUNTS,
+ Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Method checks package uid and signature with Authenticator which manages accountType.
+ *
+ * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match,
+ * SIGNATURE_CHECK_MISMATCH otherwise.
+ */
+ private int checkPackageSignature(String accountType, int callingUid, int userId,
+ String opPackageName) {
+ if (accountType == null) {
+ return SIGNATURE_CHECK_MISMATCH;
+ }
+
+ long identityToken = Binder.clearCallingIdentity();
+ Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
+ try {
+ serviceInfos = mAuthenticatorCache.getAllServices(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ // Check for signtaure match with Authenticator.
+ for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo
+ : serviceInfos) {
+ if (accountType.equals(serviceInfo.type.type)) {
+ if (serviceInfo.uid == callingUid) {
+ return SIGNATURE_CHECK_UID_MATCH;
+ }
+ final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
+ if (sigChk == PackageManager.SIGNATURE_MATCH) {
+ return SIGNATURE_CHECK_MATCH;
+ }
+ }
+ }
+ return SIGNATURE_CHECK_MISMATCH;
+ }
+
+ // returns true for system apps and applications with the same signature as authenticator.
private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
if (accountType == null) {
return false;
@@ -4627,14 +5177,13 @@
private List<String> getTypesVisibleToCaller(int callingUid, int userId,
String opPackageName) {
- boolean isPermitted =
- isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
- return getTypesForCaller(callingUid, userId, isPermitted);
+ return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/);
}
private List<String> getTypesManagedByCaller(int callingUid, int userId) {
- return getTypesForCaller(callingUid, userId, false);
+ // System UID is considered priveleged, GET_ACCOUNTS_PRIVILEGED is not enough.
+ boolean isPrivileged = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID);
+ return getTypesForCaller(callingUid, userId, isPrivileged);
}
private List<String> getTypesForCaller(
@@ -4649,8 +5198,9 @@
}
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
serviceInfos) {
- final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
- if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) {
+ if (isOtherwisePermitted || (serviceInfo.uid == callingUid)
+ || (mPackageManager.checkSignatures(serviceInfo.uid, callingUid
+ ) == PackageManager.SIGNATURE_MATCH)) {
managedAccountTypes.add(serviceInfo.type.type);
}
}
@@ -4732,7 +5282,7 @@
!= 0) {
return true;
}
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (NameNotFoundException e) {
Log.w(TAG, String.format("Could not find package [%s]", name), e);
}
}
@@ -4923,10 +5473,31 @@
return newAccountsForType[oldLength];
}
- private Account[] filterSharedAccounts(UserAccounts userAccounts, Account[] unfiltered,
- int callingUid, String callingPackage) {
+ private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid,
+ String callingPackage) {
+ Map<Account, Integer> firstPass = new HashMap<>();
+ for (Account account : unfiltered) {
+ int visibility =
+ resolveAccountVisibility(account, callingUid, callingPackage, accounts);
+ if (visibility == AccountManager.VISIBILITY_VISIBLE
+ || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
+ firstPass.put(account, visibility);
+ }
+ }
+ Map<Account, Integer> secondPass =
+ filterSharedAccounts(accounts, firstPass, callingUid, callingPackage);
+
+ Account[] filtered = new Account[secondPass.size()];
+ filtered = secondPass.keySet().toArray(filtered);
+ return filtered;
+ }
+
+ private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts,
+ Map<Account, Integer> unfiltered, int callingUid, String callingPackage) {
+ // first part is to filter shared accounts.
+ // unfiltered type check is not necessary.
if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0
- || callingUid == Process.myUid()) {
+ || callingUid == Process.SYSTEM_UID) {
return unfiltered;
}
UserInfo user = getUserManager().getUserInfo(userAccounts.userId);
@@ -4944,7 +5515,9 @@
}
ArrayList<Account> allowed = new ArrayList<>();
Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId);
- if (sharedAccounts == null || sharedAccounts.length == 0) return unfiltered;
+ if (ArrayUtils.isEmpty(sharedAccounts)) {
+ return unfiltered;
+ }
String requiredAccountType = "";
try {
// If there's an explicit callingPackage specified, check if that package
@@ -4964,9 +5537,12 @@
}
}
}
- } catch (NameNotFoundException nnfe) {
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "Package not found " + e.getMessage());
}
- for (Account account : unfiltered) {
+ Map<Account, Integer> filtered = new HashMap<>();
+ for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) {
+ Account account = entry.getKey();
if (account.type.equals(requiredAccountType)) {
allowed.add(account);
} else {
@@ -4978,12 +5554,10 @@
}
}
if (!found) {
- allowed.add(account);
+ filtered.put(account, entry.getValue());
}
}
}
- Account[] filtered = new Account[allowed.size()];
- allowed.toArray(filtered);
return filtered;
} else {
return unfiltered;
@@ -5001,7 +5575,7 @@
if (accounts == null) {
return EMPTY_ACCOUNT_ARRAY;
} else {
- return filterSharedAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
+ return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length),
callingUid, callingPackage);
}
} else {
@@ -5019,7 +5593,7 @@
accountsOfType.length);
totalLength += accountsOfType.length;
}
- return filterSharedAccounts(userAccounts, accounts, callingUid, callingPackage);
+ return filterAccounts(userAccounts, accounts, callingUid, callingPackage);
}
}
@@ -5247,19 +5821,21 @@
if (userId == 0) {
// Migrate old file, if it exists, to the new location.
// Make sure the new file doesn't already exist. A dummy file could have been
- // accidentally created in the old location, causing the new one to become corrupted
- // as well.
+ // accidentally created in the old location,
+ // causing the new one to become corrupted as well.
File oldFile = new File(systemDir, PRE_N_DATABASE_NAME);
if (oldFile.exists() && !databaseFile.exists()) {
// Check for use directory; create if it doesn't exist, else renameTo will fail
File userDir = Environment.getUserSystemDirectory(userId);
if (!userDir.exists()) {
if (!userDir.mkdirs()) {
- throw new IllegalStateException("User dir cannot be created: " + userDir);
+ throw new IllegalStateException(
+ "User dir cannot be created: " + userDir);
}
}
if (!oldFile.renameTo(databaseFile)) {
- throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
+ throw new IllegalStateException(
+ "User dir cannot be migrated: " + databaseFile);
}
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
index 5ca74711..0ee20cc 100644
--- a/services/core/java/com/android/server/accounts/AccountsDb.java
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -355,7 +355,7 @@
boolean deleteAuthtokensByAccountIdAndType(long accountId, String authtokenType) {
SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
return db.delete(CE_TABLE_AUTHTOKENS,
- AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ AUTHTOKENS_ACCOUNTS_ID + "=?" + " AND " + AUTHTOKENS_TYPE + "=?",
new String[]{String.valueOf(accountId), authtokenType}) > 0;
}
@@ -1306,4 +1306,4 @@
return new AccountsDb(deDatabaseHelper, context, preNDatabaseFile);
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6625846..bdfdab1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -257,6 +257,7 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.CountDownLatch;
import dalvik.system.VMRuntime;
@@ -1465,6 +1466,7 @@
MONITOR_THREAD_CPU_USAGE);
final AtomicLong mLastCpuTime = new AtomicLong(0);
final AtomicBoolean mProcessCpuMutexFree = new AtomicBoolean(true);
+ final CountDownLatch mProcessCpuInitLatch = new CountDownLatch(1);
long mLastWriteTime = 0;
@@ -2647,13 +2649,9 @@
}
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
-
mTempConfig.setToDefaults();
mTempConfig.setLocales(LocaleList.getDefault());
mConfigurationSeq = mTempConfig.seq = 1;
-
- mProcessCpuTracker.init();
-
mStackSupervisor = new ActivityStackSupervisor(this);
mStackSupervisor.onConfigurationChanged(mTempConfig);
mKeyguardController = mStackSupervisor.mKeyguardController;
@@ -2667,6 +2665,10 @@
mProcessCpuThread = new Thread("CpuTracker") {
@Override
public void run() {
+ synchronized (mProcessCpuTracker) {
+ mProcessCpuInitLatch.countDown();
+ mProcessCpuTracker.init();
+ }
while (true) {
try {
try {
@@ -2714,6 +2716,16 @@
mAppOpsService.publish(mContext);
Slog.d("AppOps", "AppOpsService published");
LocalServices.addService(ActivityManagerInternal.class, new LocalService());
+ // Wait for the synchronized block started in mProcessCpuThread,
+ // so that any other acccess to mProcessCpuTracker from main thread
+ // will be blocked during mProcessCpuTracker initialization.
+ try {
+ mProcessCpuInitLatch.await();
+ } catch (InterruptedException e) {
+ Slog.wtf(TAG, "Interrupted wait during start", e);
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Interrupted wait during start");
+ }
}
void onUserStoppedLocked(int userId) {
@@ -4737,7 +4749,7 @@
if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- return mWindowManager.getAppOrientation(r.appToken);
+ return r.getRequestedOrientation();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 32dec96..3f166fe 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -17,6 +17,7 @@
import android.os.SystemClock;
import android.util.Slog;
+import com.android.internal.logging.LogBuilder;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -170,6 +171,13 @@
processRunning);
MetricsLogger.action(mContext, MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
(int) (SystemClock.uptimeMillis() / 1000));
+
+ LogBuilder builder = new LogBuilder();
+ builder.addTaggedData(MetricsEvent.APP_TRANSITION_COMPONENT_NAME, componentName);
+ builder.addTaggedData(MetricsEvent.APP_TRANSITION_PROCESS_RUNNING, processRunning ? 1 : 0);
+ builder.addTaggedData(MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS,
+ SystemClock.uptimeMillis() / 1000);
+ MetricsLogger.action(builder);
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ef19700..0e4ab96 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -21,17 +21,26 @@
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
+import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.os.Build.VERSION_CODES.HONEYCOMB;
+import static android.os.Process.SYSTEM_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
@@ -92,6 +101,8 @@
import com.android.server.AttributeCache;
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
+import com.android.server.wm.AppWindowContainerController;
+import com.android.server.wm.AppWindowContainerListener;
import java.io.File;
import java.io.IOException;
@@ -110,7 +121,7 @@
/**
* An entry in the history stack, representing an activity.
*/
-final class ActivityRecord {
+final class ActivityRecord implements AppWindowContainerListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
@@ -135,6 +146,7 @@
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
+ AppWindowContainerController mWindowContainerController;
final ActivityInfo info; // all about me
final ApplicationInfo appInfo; // information about activity's app
final int launchedFromUid; // always the uid who started the activity.
@@ -150,7 +162,7 @@
final boolean stateNotNeeded; // As per ActivityInfo.flags
boolean fullscreen; // covers the full screen?
final boolean noDisplay; // activity is not displayed?
- final boolean componentSpecified; // did caller specify an explicit component?
+ private final boolean componentSpecified; // did caller specify an explicit component?
final boolean rootVoiceInteraction; // was this the root activity of a voice interaction?
static final int APPLICATION_ACTIVITY_TYPE = 0;
@@ -158,18 +170,18 @@
static final int RECENTS_ACTIVITY_TYPE = 2;
int mActivityType;
- CharSequence nonLocalizedLabel; // the label information from the package mgr.
- int labelRes; // the label information from the package mgr.
- int icon; // resource identifier of activity's icon.
- int logo; // resource identifier of activity's logo.
- int theme; // resource identifier of activity's theme.
- int realTheme; // actual theme resource we will use, never 0.
- int windowFlags; // custom window flags for preview window.
+ private CharSequence nonLocalizedLabel; // the label information from the package mgr.
+ private int labelRes; // the label information from the package mgr.
+ private int icon; // resource identifier of activity's icon.
+ private int logo; // resource identifier of activity's logo.
+ private int theme; // resource identifier of activity's theme.
+ private int realTheme; // actual theme resource we will use, never 0.
+ private int windowFlags; // custom window flags for preview window.
TaskRecord task; // the task this is in.
- long createTime = System.currentTimeMillis();
+ private long createTime = System.currentTimeMillis();
long displayStartTime; // when we started launching this activity
long fullyDrawnStartTime; // when we started launching this activity
- long startTime; // last time this activity was started
+ private long startTime; // last time this activity was started
long lastVisibleTime; // last time this activity became visible
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
long pauseTime; // last time we started pausing the activity
@@ -542,70 +554,9 @@
static class Token extends IApplicationToken.Stub {
private final WeakReference<ActivityRecord> weakActivity;
- private final ActivityManagerService mService;
- Token(ActivityRecord activity, ActivityManagerService service) {
+ Token(ActivityRecord activity) {
weakActivity = new WeakReference<>(activity);
- mService = service;
- }
-
- @Override
- public void windowsDrawn() {
- synchronized (mService) {
- ActivityRecord r = tokenToActivityRecordLocked(this);
- if (r != null) {
- r.windowsDrawnLocked();
- }
- }
- }
-
- @Override
- public void windowsVisible() {
- synchronized (mService) {
- ActivityRecord r = tokenToActivityRecordLocked(this);
- if (r != null) {
- r.windowsVisibleLocked();
- }
- }
- }
-
- @Override
- public void windowsGone() {
- synchronized (mService) {
- ActivityRecord r = tokenToActivityRecordLocked(this);
- if (r != null) {
- if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
- r.nowVisible = false;
- }
- }
- }
-
- @Override
- public boolean keyDispatchingTimedOut(String reason) {
- ActivityRecord r;
- ActivityRecord anrActivity;
- ProcessRecord anrApp;
- synchronized (mService) {
- r = tokenToActivityRecordLocked(this);
- if (r == null) {
- return false;
- }
- anrActivity = r.getWaitingHistoryRecordLocked();
- anrApp = r.app;
- }
- return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
- }
-
- @Override
- public long getKeyDispatchingTimeout() {
- synchronized (mService) {
- ActivityRecord r = tokenToActivityRecordLocked(this);
- if (r == null) {
- return 0;
- }
- r = r.getWaitingHistoryRecordLocked();
- return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
- }
}
private static ActivityRecord tokenToActivityRecordLocked(Token token) {
@@ -652,7 +603,7 @@
ActivityStackSupervisor supervisor,
ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
service = _service;
- appToken = new Token(this, service);
+ appToken = new Token(this);
info = aInfo;
launchedFromUid = _launchedFromUid;
launchedFromPackage = _launchedFromPackage;
@@ -700,97 +651,110 @@
}
}
- // This starts out true, since the initial state of an activity
- // is that we have everything, and we shouldn't never consider it
- // lacking in state to be removed if it dies.
+ // This starts out true, since the initial state of an activity is that we have everything,
+ // and we shouldn't never consider it lacking in state to be removed if it dies.
haveState = true;
- if (aInfo != null) {
- // If the class name in the intent doesn't match that of the target, this is
- // probably an alias. We have to create a new ComponentName object to keep track
- // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
- if (aInfo.targetActivity == null
- || (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
- && (aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
- || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP))) {
- realActivity = _intent.getComponent();
- } else {
- realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity);
- }
- taskAffinity = aInfo.taskAffinity;
- stateNotNeeded = (aInfo.flags&
- ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
- appInfo = aInfo.applicationInfo;
- nonLocalizedLabel = aInfo.nonLocalizedLabel;
- labelRes = aInfo.labelRes;
- if (nonLocalizedLabel == null && labelRes == 0) {
- ApplicationInfo app = aInfo.applicationInfo;
- nonLocalizedLabel = app.nonLocalizedLabel;
- labelRes = app.labelRes;
- }
- icon = aInfo.getIconResource();
- logo = aInfo.getLogoResource();
- theme = aInfo.getThemeResource();
- realTheme = theme;
- if (realTheme == 0) {
- realTheme = aInfo.applicationInfo.targetSdkVersion
- < Build.VERSION_CODES.HONEYCOMB
- ? android.R.style.Theme
- : android.R.style.Theme_Holo;
- }
- if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
- windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
- }
- if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
- && _caller != null
- && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
- || aInfo.applicationInfo.uid == _caller.info.uid)) {
- processName = _caller.processName;
- } else {
- processName = aInfo.processName;
- }
-
- if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
- intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- }
-
- packageName = aInfo.applicationInfo.packageName;
- launchMode = aInfo.launchMode;
-
- AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
- realTheme, com.android.internal.R.styleable.Window, userId);
- final boolean translucent = ent != null && (ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false)
- || (!ent.array.hasValue(
- com.android.internal.R.styleable.Window_windowIsTranslucent)
- && ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowSwipeToDismiss,
- false)));
- fullscreen = ent != null && !ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsFloating, false)
- && !translucent;
- noDisplay = ent != null && ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowNoDisplay, false);
-
- setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord);
-
- immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
-
- requestedVrComponent = (aInfo.requestedVrComponent == null) ?
- null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
+ // If the class name in the intent doesn't match that of the target, this is
+ // probably an alias. We have to create a new ComponentName object to keep track
+ // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
+ if (aInfo.targetActivity == null
+ || (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
+ && (aInfo.launchMode == LAUNCH_MULTIPLE
+ || aInfo.launchMode == LAUNCH_SINGLE_TOP))) {
+ realActivity = _intent.getComponent();
} else {
- realActivity = null;
- taskAffinity = null;
- stateNotNeeded = false;
- appInfo = null;
- processName = null;
- packageName = null;
- fullscreen = true;
- noDisplay = false;
- mActivityType = APPLICATION_ACTIVITY_TYPE;
- immersive = false;
- requestedVrComponent = null;
+ realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity);
}
+ taskAffinity = aInfo.taskAffinity;
+ stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
+ appInfo = aInfo.applicationInfo;
+ nonLocalizedLabel = aInfo.nonLocalizedLabel;
+ labelRes = aInfo.labelRes;
+ if (nonLocalizedLabel == null && labelRes == 0) {
+ ApplicationInfo app = aInfo.applicationInfo;
+ nonLocalizedLabel = app.nonLocalizedLabel;
+ labelRes = app.labelRes;
+ }
+ icon = aInfo.getIconResource();
+ logo = aInfo.getLogoResource();
+ theme = aInfo.getThemeResource();
+ realTheme = theme;
+ if (realTheme == 0) {
+ realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB
+ ? android.R.style.Theme : android.R.style.Theme_Holo;
+ }
+ if ((aInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+ windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ }
+ if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null
+ && (aInfo.applicationInfo.uid == SYSTEM_UID
+ || aInfo.applicationInfo.uid == _caller.info.uid)) {
+ processName = _caller.processName;
+ } else {
+ processName = aInfo.processName;
+ }
+
+ if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) {
+ intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ }
+
+ packageName = aInfo.applicationInfo.packageName;
+ launchMode = aInfo.launchMode;
+
+ AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
+ realTheme, com.android.internal.R.styleable.Window, userId);
+ final boolean translucent = ent != null && (ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+ || (!ent.array.hasValue(
+ com.android.internal.R.styleable.Window_windowIsTranslucent)
+ && ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+ false)));
+ fullscreen = ent != null && !ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
+ noDisplay = ent != null && ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowNoDisplay, false);
+
+ setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord);
+
+ immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
+
+ requestedVrComponent = (aInfo.requestedVrComponent == null) ?
+ null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
+ }
+
+ void createWindowContainer() {
+ if (mWindowContainerController != null) {
+ throw new IllegalArgumentException("Window container=" + mWindowContainerController
+ + " already created for r=" + this);
+
+ }
+
+ inHistory = true;
+
+ task.updateOverrideConfigurationFromLaunchBounds();
+
+ mWindowContainerController = new AppWindowContainerController(appToken, this, task.taskId,
+ Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
+ (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
+ task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
+ appInfo.targetSdkVersion, mRotationAnimationHint,
+ ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L);
+
+ task.addActivityToTop(this);
+
+ onOverrideConfigurationSent();
+ }
+
+ void removeWindowContainer() {
+ mWindowContainerController.removeContainer(getDisplayId());
+ }
+
+ // TODO: Remove once task record is converted to use controller in which case we can use
+ // positionChildAt()
+ void positionWindowContainerAt(int index) {
+ mWindowContainerController.positionAt(task.taskId, index);
}
private boolean isHomeIntent(Intent intent) {
@@ -890,12 +854,6 @@
return true;
}
- void putInHistory() {
- if (!inHistory) {
- inHistory = true;
- }
- }
-
void takeFromHistory() {
if (inHistory) {
inHistory = false;
@@ -931,7 +889,7 @@
return (info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY ||
info.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS) &&
(intent == null ||
- (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
+ (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
}
boolean isFocusable() {
@@ -1222,14 +1180,14 @@
void pauseKeyDispatchingLocked() {
if (!keysPaused) {
keysPaused = true;
- service.mWindowManager.pauseKeyDispatching(appToken);
+ mWindowContainerController.pauseKeyDispatching();
}
}
void resumeKeyDispatchingLocked() {
if (keysPaused) {
keysPaused = false;
- service.mWindowManager.resumeKeyDispatching(appToken);
+ mWindowContainerController.resumeKeyDispatching();
}
}
@@ -1277,7 +1235,7 @@
return null;
}
- final float scale;
+ float scale = 0;
if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
// When this flag is set, we currently take the fullscreen screenshot of the activity but
@@ -1288,17 +1246,21 @@
scale = service.mFullscreenThumbnailScale;
}
- return service.mWindowManager.screenshotApplications(appToken, DEFAULT_DISPLAY, w, h,
- scale);
+ return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale);
}
+ void setVisibility(boolean visible) {
+ mWindowContainerController.setVisibility(visible);
+ }
+
+ // TODO: Look into merging with #setVisibility()
void setVisible(boolean newVisible) {
visible = newVisible;
if (!visible && mUpdateTaskThumbnailWhenHidden) {
updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
mUpdateTaskThumbnailWhenHidden = false;
}
- service.mWindowManager.setAppVisibility(appToken, visible);
+ mWindowContainerController.setVisibility(visible);
final ArrayList<ActivityContainer> containers = mChildContainers;
for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
final ActivityContainer container = containers.get(containerNdx);
@@ -1307,6 +1269,14 @@
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
+ void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
+ mWindowContainerController.notifyAppResumed(wasStopped, allowSavedSurface);
+ }
+
+ void notifyUnknownVisibilityLaunched() {
+ mWindowContainerController.notifyUnknownVisibilityLaunched();
+ }
+
/**
* @return true if the input activity should be made visible, ignoring any effect Keyguard
* might have on the visibility
@@ -1458,6 +1428,7 @@
service.notifyTaskPersisterLocked(task, false);
}
if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle);
+
if (newIcicle != null) {
// If icicle is null, this is happening due to a timeout, so we haven't really saved
// the state.
@@ -1472,7 +1443,7 @@
stopped = true;
state = ActivityState.STOPPED;
- service.mWindowManager.notifyAppStopped(appToken);
+ mWindowContainerController.notifyAppStopped();
if (stack.getVisibleBehindActivity() == this) {
mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */);
@@ -1536,14 +1507,14 @@
public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
if (mayFreezeScreenLocked(app)) {
- service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
+ mWindowContainerController.startFreezingScreen(configChanges);
}
}
public void stopFreezingScreenLocked(boolean force) {
if (force || frozenBeforeDestroy) {
frozenBeforeDestroy = false;
- service.mWindowManager.stopAppFreezingScreen(appToken, force);
+ mWindowContainerController.stopFreezingScreen(force);
}
}
@@ -1617,48 +1588,73 @@
stack.mLaunchStartTime = 0;
}
- void windowsDrawnLocked() {
- mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
- if (displayStartTime != 0) {
- reportLaunchTimeLocked(SystemClock.uptimeMillis());
- }
- mStackSupervisor.sendWaitingVisibleReportLocked(this);
- startTime = 0;
- finishLaunchTickingLocked();
- if (task != null) {
- task.hasBeenVisible = true;
- }
- }
-
- void windowsVisibleLocked() {
- mStackSupervisor.reportActivityVisibleLocked(this);
- if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
- if (!nowVisible) {
- nowVisible = true;
- lastVisibleTime = SystemClock.uptimeMillis();
- if (!idle) {
- // Instead of doing the full stop routine here, let's just hide any activities
- // we now can, and let them stop when the normal idle happens.
- mStackSupervisor.processStoppingActivitiesLocked(false);
- } else {
- // If this activity was already idle, then we now need to make sure we perform
- // the full stop of any activities that are waiting to do so. This is because
- // we won't do that while they are still waiting for this one to become visible.
- final int size = mStackSupervisor.mWaitingVisibleActivities.size();
- if (size > 0) {
- for (int i = 0; i < size; i++) {
- ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
- if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
- }
- mStackSupervisor.mWaitingVisibleActivities.clear();
- mStackSupervisor.scheduleIdleLocked();
- }
+ @Override
+ public void onWindowsDrawn() {
+ synchronized (service) {
+ mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn();
+ if (displayStartTime != 0) {
+ reportLaunchTimeLocked(SystemClock.uptimeMillis());
}
- service.scheduleAppGcsLocked();
+ mStackSupervisor.sendWaitingVisibleReportLocked(this);
+ startTime = 0;
+ finishLaunchTickingLocked();
+ if (task != null) {
+ task.hasBeenVisible = true;
+ }
}
}
- ActivityRecord getWaitingHistoryRecordLocked() {
+ @Override
+ public void onWindowsVisible() {
+ synchronized (service) {
+ mStackSupervisor.reportActivityVisibleLocked(this);
+ if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
+ if (!nowVisible) {
+ nowVisible = true;
+ lastVisibleTime = SystemClock.uptimeMillis();
+ if (!idle) {
+ // Instead of doing the full stop routine here, let's just hide any activities
+ // we now can, and let them stop when the normal idle happens.
+ mStackSupervisor.processStoppingActivitiesLocked(false);
+ } else {
+ // If this activity was already idle, then we now need to make sure we perform
+ // the full stop of any activities that are waiting to do so. This is because
+ // we won't do that while they are still waiting for this one to become visible.
+ final int size = mStackSupervisor.mWaitingVisibleActivities.size();
+ if (size > 0) {
+ for (int i = 0; i < size; i++) {
+ ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
+ if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
+ }
+ mStackSupervisor.mWaitingVisibleActivities.clear();
+ mStackSupervisor.scheduleIdleLocked();
+ }
+ }
+ service.scheduleAppGcsLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onWindowsGone() {
+ synchronized (service) {
+ if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
+ nowVisible = false;
+ }
+ }
+
+ @Override
+ public boolean keyDispatchingTimedOut(String reason) {
+ ActivityRecord anrActivity;
+ ProcessRecord anrApp;
+ synchronized (service) {
+ anrActivity = getWaitingHistoryRecordLocked();
+ anrApp = app;
+ }
+ return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
+ }
+
+ private ActivityRecord getWaitingHistoryRecordLocked() {
// First find the real culprit... if this activity is waiting for
// another activity to start or has stopped, then the key dispatching
// timeout should not be caused by this.
@@ -1800,25 +1796,40 @@
void showStartingWindow(ActivityRecord prev, boolean createIfNeeded) {
final CompatibilityInfo compatInfo =
service.compatibilityInfoForPackageLocked(info.applicationInfo);
- final boolean shown = service.mWindowManager.setAppStartingWindow(
- appToken, packageName, theme, compatInfo, nonLocalizedLabel, labelRes, icon,
- logo, windowFlags, prev != null ? prev.appToken : null, createIfNeeded);
+ final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
+ compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
+ prev != null ? prev.appToken : null, createIfNeeded);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
}
+ void removeOrphanedStartingWindow(boolean behindFullscreenActivity) {
+ if (state == ActivityState.INITIALIZING
+ && mStartingWindowState == STARTING_WINDOW_SHOWN
+ && behindFullscreenActivity) {
+ if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
+ mStartingWindowState = STARTING_WINDOW_REMOVED;
+ mWindowContainerController.removeStartingWindow();
+ }
+ }
+
+ int getRequestedOrientation() {
+ return mWindowContainerController.getOrientation();
+ }
+
void setRequestedOrientation(int requestedOrientation) {
if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) {
// Fixed screen orientation isn't supported when activities aren't in full screen mode.
return;
}
- service.mWindowManager.setAppOrientation(appToken, requestedOrientation);
final int displayId = getDisplayId();
- final Configuration config = service.mWindowManager.updateOrientationFromAppTokens(
- mStackSupervisor.getDisplayOverrideConfiguration(displayId),
- mayFreezeScreenLocked(app) ? appToken : null, displayId);
+ final Configuration displayConfig =
+ mStackSupervisor.getDisplayOverrideConfiguration(displayId);
+
+ final Configuration config = mWindowContainerController.setOrientation(requestedOrientation,
+ displayId, displayConfig, mayFreezeScreenLocked(app));
if (config != null) {
frozenBeforeDestroy = true;
if (!service.updateDisplayOverrideConfigurationLocked(config, this,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index beeadac..f7c3cea 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -61,8 +61,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
-import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -1392,24 +1390,6 @@
return null;
}
- ActivityStack getNextFocusableStackLocked() {
- ArrayList<ActivityStack> stacks = mStacks;
- final ActivityRecord parent = mActivityContainer.mParentActivity;
- if (parent != null) {
- stacks = parent.getStack().mStacks;
- }
- if (stacks != null) {
- for (int i = stacks.size() - 1; i >= 0; --i) {
- ActivityStack stack = stacks.get(i);
- if (stack != this && stack.isFocusable()
- && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
- return stack;
- }
- }
- }
- return null;
- }
-
/** Returns true if the stack contains a fullscreen task. */
private boolean hasFullscreenTask() {
for (int i = mTaskHistory.size() - 1; i >= 0; --i) {
@@ -2046,15 +2026,7 @@
continue;
}
- if (r.state == ActivityState.INITIALIZING
- && r.mStartingWindowState == STARTING_WINDOW_SHOWN
- && behindFullscreenActivity) {
- if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
- "Found orphaned starting window " + r);
- r.mStartingWindowState = STARTING_WINDOW_REMOVED;
- mWindowManager.removeAppStartingWindow(r.appToken);
- }
-
+ r.removeOrphanedStartingWindow(behindFullscreenActivity);
behindFullscreenActivity |= r.fullscreen;
}
}
@@ -2108,9 +2080,15 @@
return false;
}
- ActivityRecord parent = mActivityContainer.mParentActivity;
- if ((parent != null && parent.state != ActivityState.RESUMED) ||
- !mActivityContainer.isAttachedLocked()) {
+ // Find the topmost activity in this stack that is not finishing.
+ final ActivityRecord next = topRunningActivityLocked();
+
+ final boolean hasRunningActivity = next != null;
+
+ final ActivityRecord parent = mActivityContainer.mParentActivity;
+ final boolean isParentNotResumed = parent != null && parent.state != ActivityState.RESUMED;
+ if (hasRunningActivity
+ && (isParentNotResumed || !mActivityContainer.isAttachedLocked())) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
@@ -2118,33 +2096,14 @@
mStackSupervisor.cancelInitializingActivities();
- // Find the first activity that is not finishing.
- final ActivityRecord next = topRunningActivityLocked();
-
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
- final TaskRecord prevTask = prev != null ? prev.task : null;
- if (next == null) {
- // There are no more activities!
- final String reason = "noMoreActivities";
- if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
- // Try to move focus to the next visible stack with a running activity if this
- // stack is not covering the entire screen.
- return mStackSupervisor.resumeFocusedStackTopActivityLocked(
- mStackSupervisor.getFocusedStack(), prev, null);
- }
-
- // Let's just start up the Launcher...
- ActivityOptions.abort(options);
- if (DEBUG_STATES) Slog.d(TAG_STATES,
- "resumeTopActivityLocked: No more activities go home");
- if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
- // Only resume home if on home display
- return isOnHomeDisplay() &&
- mStackSupervisor.resumeHomeStackTask(prev, reason);
+ if (!hasRunningActivity) {
+ // There are no activities left in the stack, let's look somewhere else.
+ return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
}
next.delayedResume = false;
@@ -2162,6 +2121,7 @@
}
final TaskRecord nextTask = next.task;
+ final TaskRecord prevTask = prev != null ? prev.task : null;
if (prevTask != null && prevTask.getStack() == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2287,7 +2247,7 @@
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) {
- mWindowManager.setAppVisibility(prev.appToken, false);
+ prev.setVisibility(false);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Not waiting for visible to hide: " + prev + ", waitingVisible="
+ mStackSupervisor.mWaitingVisibleActivities.contains(prev)
@@ -2329,7 +2289,7 @@
? TRANSIT_ACTIVITY_CLOSE
: TRANSIT_TASK_CLOSE, false);
}
- mWindowManager.setAppVisibility(prev.appToken, false);
+ prev.setVisibility(false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: prev=" + prev);
@@ -2384,7 +2344,7 @@
// This activity is now becoming visible.
if (!next.visible || next.stopped || lastActivityTranslucent) {
- mWindowManager.setAppVisibility(next.appToken, true);
+ next.setVisibility(true);
}
// schedule launch ticks to collect information about slow apps.
@@ -2433,7 +2393,7 @@
mStackSupervisor.scheduleResumeTopActivities();
}
if (!next.visible || next.stopped) {
- mWindowManager.setAppVisibility(next.appToken, true);
+ next.setVisibility(true);
}
next.completeResumeLocked();
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2471,7 +2431,7 @@
// Well the app will no longer be stopped.
// Clear app token stopped state in window manager if needed.
- mWindowManager.notifyAppResumed(next.appToken, next.stopped, allowSavedSurface);
+ next.notifyAppResumed(next.stopped, allowSavedSurface);
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
System.identityHashCode(next), next.task.taskId, next.shortComponentName);
@@ -2537,6 +2497,27 @@
return true;
}
+ private boolean resumeTopActivityInNextFocusableStack(ActivityRecord prev,
+ ActivityOptions options, String reason) {
+ if ((!mFullscreen || !isOnHomeDisplay())
+ && adjustFocusToNextFocusableStackLocked(reason)) {
+ // Try to move focus to the next visible stack with a running activity if this
+ // stack is not covering the entire screen or is on a secondary display (with no home
+ // stack).
+ return mStackSupervisor.resumeFocusedStackTopActivityLocked(
+ mStackSupervisor.getFocusedStack(), prev, null);
+ }
+
+ // Let's just start up the Launcher...
+ ActivityOptions.abort(options);
+ if (DEBUG_STATES) Slog.d(TAG_STATES,
+ "resumeTopActivityInNextFocusableStack: " + reason + ", go home");
+ if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
+ // Only resume home if on home display
+ return isOnHomeDisplay() &&
+ mStackSupervisor.resumeHomeStackTask(prev, reason);
+ }
+
private TaskRecord getNextTask(TaskRecord targetTask) {
final int index = mTaskHistory.indexOf(targetTask);
if (index >= 0) {
@@ -2669,9 +2650,7 @@
if (!startIt) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to task "
+ task, new RuntimeException("here").fillInStackTrace());
- task.addActivityToTop(r);
- r.putInHistory();
- addConfigOverride(r, task);
+ r.createWindowContainer();
ActivityOptions.abort(options);
return;
}
@@ -2682,12 +2661,10 @@
}
}
- // Place a new activity at top of stack, so it is next to interact
- // with the user.
+ // Place a new activity at top of stack, so it is next to interact with the user.
- // If we are not placing the new activity frontmost, we do not want
- // to deliver the onUserLeaving callback to the actual frontmost
- // activity
+ // If we are not placing the new activity frontmost, we do not want to deliver the
+ // onUserLeaving callback to the actual frontmost activity
if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
mStackSupervisor.mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
@@ -2699,10 +2676,9 @@
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
- task.addActivityToTop(r);
+ r.createWindowContainer();
task.setFrontOfTask();
- r.putInHistory();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
@@ -2737,7 +2713,6 @@
mWindowManager.prepareAppTransition(transit, keepCurTransition);
mNoAnimActivities.remove(r);
}
- addConfigOverride(r, task);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -2756,7 +2731,7 @@
if (r.mLaunchTaskBehind) {
// Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
// tell WindowManager that r is visible even though it is at the back of the stack.
- mWindowManager.setAppVisibility(r.appToken, true);
+ r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
@@ -2780,7 +2755,6 @@
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
- addConfigOverride(r, task);
ActivityOptions.abort(options);
}
}
@@ -2865,8 +2839,6 @@
+ " out to new task " + target.task);
}
- setAppTask(target, targetTask);
-
boolean noOptions = canMoveOptions;
final int start = replyChainEnd < 0 ? i : replyChainEnd;
for (int srcPos = start; srcPos >= i; --srcPos) {
@@ -2889,8 +2861,6 @@
"Pushing next activity " + p + " out to target's task " + target.task);
p.setTask(targetTask, null);
targetTask.addActivityAtBottom(p);
-
- setAppTask(p, targetTask);
}
mWindowManager.moveTaskToBottom(targetTask.taskId);
@@ -3028,7 +2998,6 @@
+ " callers=" + Debug.getCallers(3));
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
+ " from " + srcPos + " in to resetting task " + task);
- setAppTask(p, task);
}
mWindowManager.moveTaskToTop(taskId);
@@ -3173,7 +3142,7 @@
}
private boolean adjustFocusToNextFocusableStackLocked(String reason) {
- final ActivityStack stack = getNextFocusableStackLocked();
+ final ActivityStack stack = mStackSupervisor.getNextFocusableStackLocked(this);
final String myReason = reason + " adjustFocusToNextFocusableStack";
if (stack == null) {
return false;
@@ -3223,7 +3192,7 @@
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
- mWindowManager.setAppVisibility(r.appToken, false);
+ r.setVisibility(false);
}
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
@@ -3457,7 +3426,7 @@
mWindowManager.prepareAppTransition(transit, false);
// Tell window manager to prepare for this one to be removed.
- mWindowManager.setAppVisibility(r.appToken, false);
+ r.setVisibility(false);
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
@@ -3475,7 +3444,7 @@
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
if (r.visible) {
mWindowManager.prepareAppTransition(transit, false);
- mWindowManager.setAppVisibility(r.appToken, false);
+ r.setVisibility(false);
mWindowManager.executeAppTransition();
if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) {
mStackSupervisor.mWaitingVisibleActivities.add(r);
@@ -3782,7 +3751,7 @@
r.state = ActivityState.DESTROYED;
if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
r.app = null;
- mWindowManager.removeAppToken(r.appToken, r.getDisplayId());
+ r.removeWindowContainer();
final TaskRecord task = r.task;
if (task != null && task.removeActivity(r)) {
if (DEBUG_STACK) Slog.i(TAG_STACK,
@@ -4981,17 +4950,6 @@
}
}
- void addConfigOverride(ActivityRecord r, TaskRecord task) {
- task.updateOverrideConfigurationFromLaunchBounds();
- // TODO: VI deal with activity
- mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
- r.task.taskId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.info.configChanges,
- task.voiceSession != null, r.mLaunchTaskBehind, r.isAlwaysFocusable(),
- r.appInfo.targetSdkVersion, r.mRotationAnimationHint);
- r.onOverrideConfigurationSent();
- }
-
void moveToFrontAndResumeStateIfNeeded(
ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
if (!moveToFront) {
@@ -5030,7 +4988,6 @@
r.info, r.intent, null, null, true, r.mActivityType);
r.setTask(task, null);
task.addActivityToTop(r);
- setAppTask(r, task);
mStackSupervisor.scheduleReportPictureInPictureModeChangedIfNeeded(task, prevStack);
moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
if (wasResumed) {
@@ -5038,12 +4995,6 @@
}
}
- private void setAppTask(ActivityRecord r, TaskRecord task) {
- task.updateOverrideConfigurationFromLaunchBounds();
- mWindowManager.addAppToTask(r.appToken, task.taskId);
- r.onOverrideConfigurationSent();
- }
-
public int getStackId() {
return mStackId;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 028c571..5def340 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -33,7 +33,6 @@
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -179,8 +178,7 @@
import java.util.Objects;
import java.util.Set;
-public class ActivityStackSupervisor extends ConfigurationContainer
- implements DisplayListener {
+public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -457,6 +455,13 @@
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
/**
+ * Temp storage for display ids sorted in focus order.
+ * Maps position to id. Using {@link SparseIntArray} instead of {@link ArrayList} because
+ * it's more efficient, as the number of displays is usually small.
+ */
+ private SparseIntArray mTmpOrderedDisplayIds = new SparseIntArray();
+
+ /**
* Used to keep track whether app visibilities got changed since the last pause. Useful to
* determine whether to invoke the task stack change listener after pausing.
*/
@@ -639,7 +644,7 @@
void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
if (!focusCandidate.isFocusable()) {
// The focus candidate isn't focusable. Move focus to the top stack that is focusable.
- focusCandidate = focusCandidate.getNextFocusableStackLocked();
+ focusCandidate = getNextFocusableStackLocked(focusCandidate);
}
if (focusCandidate != mFocusedStack) {
@@ -1204,7 +1209,7 @@
if (andResume) {
r.startFreezingScreenLocked(app, 0);
- mWindowManager.setAppVisibility(r.appToken, true);
+ r.setVisibility(true);
// schedule launch ticks to collect information about slow apps.
r.startLaunchTickingLocked();
@@ -1227,7 +1232,7 @@
}
if (mKeyguardController.isKeyguardLocked()) {
- mWindowManager.notifyUnknownAppVisibilityLaunched(r.appToken);
+ r.notifyUnknownVisibilityLaunched();
}
r.app = app;
@@ -2021,6 +2026,35 @@
return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks;
}
+ /**
+ * Get next focusable stack in the system. This will search across displays and stacks
+ * in last-focused order for a focusable and visible stack, different from the target stack.
+ *
+ * @param currentFocus The stack that previously had focus and thus needs to be ignored when
+ * searching for next candidate.
+ * @return Next focusable {@link ActivityStack}, null if not found.
+ */
+ ActivityStack getNextFocusableStackLocked(ActivityStack currentFocus) {
+ mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds);
+
+ for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
+ final int displayId = mTmpOrderedDisplayIds.get(i);
+ final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks;
+ if (stacks == null) {
+ continue;
+ }
+ for (int j = stacks.size() - 1; j >= 0; --j) {
+ final ActivityStack stack = stacks.get(j);
+ if (stack != currentFocus && stack.isFocusable()
+ && stack.getStackVisibilityLocked(null) != STACK_INVISIBLE) {
+ return stack;
+ }
+ }
+ }
+
+ return null;
+ }
+
ActivityRecord getHomeActivity() {
return getHomeActivityForUser(mCurrentUser);
}
@@ -2577,7 +2611,7 @@
"Added restored task=" + task + " to stack=" + stack);
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- stack.addConfigOverride(activities.get(activityNdx), task);
+ activities.get(activityNdx).createWindowContainer();
}
return true;
}
@@ -3169,7 +3203,7 @@
task.setLastThumbnailLocked(r.screenshotActivityLocked());
mRecentTasks.addLocked(task);
mService.mTaskChangeNotificationController.notifyTaskStackChanged();
- mWindowManager.setAppVisibility(r.appToken, false);
+ r.setVisibility(false);
// When launching tasks behind, update the last active time of the top task after the new
// task has been shown briefly
@@ -3360,7 +3394,7 @@
// normal flow and hide it once we determine that it is
// hidden by the activities in front of it.
if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
- mWindowManager.setAppVisibility(s.appToken, false);
+ s.setVisibility(false);
}
}
if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 3bb9ccc..09af941 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1238,7 +1238,7 @@
r.mTaskOverlay = true;
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
final ActivityRecord top = task != null ? task.getTopActivity() : null;
- if (top != null && !top.visible) {
+ if (top != null && top.state != RESUMED) {
// The caller specifies that we'd like to be avoided to be moved to the front, so be
// it!
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 0ea78b3..f1f8bb2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -991,7 +991,8 @@
@Override
public void setBatteryState(final int status, final int health, final int plugType,
- final int level, final int temp, final int volt, final int chargeUAh) {
+ final int level, final int temp, final int volt, final int chargeUAh,
+ final int chargeFullUAh) {
enforceCallingPermission();
// BatteryService calls us here and we may update external state. It would be wrong
@@ -1005,7 +1006,7 @@
// The battery state has not changed, so we don't need to sync external
// stats immediately.
mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
- chargeUAh);
+ chargeUAh, chargeFullUAh);
return;
}
}
@@ -1015,7 +1016,7 @@
updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
- chargeUAh);
+ chargeUAh, chargeFullUAh);
}
}
});
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index b6e35d2..fd248c6 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -90,6 +90,7 @@
case NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS:
forAllListeners((listener) -> listener.onActivityRequestedOrientationChanged(
msg.arg1, msg.arg2));
+ break;
case NOTIFY_TASK_REMOVAL_STARTED_LISTENERS:
forAllListeners((listener) -> listener.onTaskRemovalStarted(msg.arg1));
break;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9e28068..a17cf3b 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -849,6 +849,11 @@
if (r.isPersistable()) {
mService.notifyTaskPersisterLocked(this, false);
}
+
+ // Sync. with window manager
+ updateOverrideConfigurationFromLaunchBounds();
+ r.positionWindowContainerAt(index);
+ r.onOverrideConfigurationSent();
}
/** @return true if this was the last activity in the task */
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 2d42c33..0f3f9ce 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -191,7 +191,6 @@
/** The controller for the volume UI. */
private final VolumeController mVolumeController = new VolumeController();
- private final ControllerService mControllerService = new ControllerService();
// sendMsg() flags
/** If the msg is already queued, replace it with this one. */
@@ -782,7 +781,6 @@
SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
initA11yMonitoring(mContext);
- mControllerService.init();
onIndicateSystemReady();
}
@@ -6065,7 +6063,6 @@
pw.print(" mMcc="); pw.println(mMcc);
pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
pw.print(" mHasVibrator="); pw.println(mHasVibrator);
- pw.print(" mControllerService="); pw.println(mControllerService);
pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
dumpAudioPolicies(pw);
@@ -6093,9 +6090,6 @@
}
private void enforceVolumeController(String action) {
- if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
- return;
- }
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
"Only SystemUI can " + action);
}
@@ -6326,11 +6320,6 @@
}
@Override
- public int getVolumeControllerUid() {
- return mControllerService.mUid;
- }
-
- @Override
public void updateRingerModeAffectedStreamsInternal() {
synchronized (mSettingsLock) {
if (updateRingerModeAffectedStreams()) {
@@ -6591,42 +6580,4 @@
private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
new HashMap<IBinder, AudioPolicyProxy>();
private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
-
- private class ControllerService extends ContentObserver {
- private int mUid;
- private ComponentName mComponent;
-
- public ControllerService() {
- super(null);
- }
-
- @Override
- public String toString() {
- return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
- }
-
- public void init() {
- onChange(true);
- mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mUid = 0;
- mComponent = null;
- final String setting = Settings.Secure.getString(mContentResolver,
- Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
- if (setting == null) return;
- try {
- mComponent = ComponentName.unflattenFromString(setting);
- if (mComponent == null) return;
- mUid = mContext.getPackageManager()
- .getApplicationInfo(mComponent.getPackageName(), 0).uid;
- } catch (Exception e) {
- Log.w(TAG, "Error loading controller service", e);
- }
- if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
- }
- }
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4c58ffd..9b37f12 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -351,7 +351,7 @@
*/
private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
int resolvedUserId) {
- if (isCurrentVolumeController(uid)) return;
+ if (isCurrentVolumeController(uid, pid)) return;
if (getContext()
.checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
!= PackageManager.PERMISSION_GRANTED
@@ -361,20 +361,13 @@
}
}
- private boolean isCurrentVolumeController(int uid) {
- if (mAudioManagerInternal != null) {
- final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
- if (vcuid > 0 && uid == vcuid) {
- return true;
- }
- }
- return false;
+ private boolean isCurrentVolumeController(int uid, int pid) {
+ return getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+ pid, uid) == PackageManager.PERMISSION_GRANTED;
}
private void enforceSystemUiPermission(String action, int pid, int uid) {
- if (isCurrentVolumeController(uid)) return;
- if (getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
- pid, uid) != PackageManager.PERMISSION_GRANTED) {
+ if (!isCurrentVolumeController(uid, pid)) {
throw new SecurityException("Only system ui may " + action);
}
}
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 5d50f3b..d42c7c1 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -180,12 +180,12 @@
final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
ATTENDEE_PROJECTION, selection, selectionArgs, null);
try {
- if (cursor.getCount() == 0) {
+ if (cursor == null || cursor.getCount() == 0) {
if (DEBUG) Log.d(TAG, "No attendees found");
return true;
}
boolean rt = false;
- while (cursor.moveToNext()) {
+ while (cursor != null && cursor.moveToNext()) {
final long rowEventId = cursor.getLong(0);
final String rowEmail = cursor.getString(1);
final int status = cursor.getInt(2);
@@ -200,7 +200,9 @@
}
return rt;
} finally {
- cursor.close();
+ if (cursor != null) {
+ cursor.close();
+ }
if (DEBUG) Log.d(TAG, "meetsAttendee took " + (System.currentTimeMillis() - start));
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b08f800..dffe86a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1552,7 +1552,7 @@
public void updateNotificationChannelForPackage(String pkg, int uid,
NotificationChannel channel) {
enforceSystemOrSystemUI("Caller not system or systemui");
- if (!channel.isAllowed()) {
+ if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
// cancel
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
@@ -2021,13 +2021,13 @@
@Override
public ZenModeConfig getZenModeConfig() {
- enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
+ enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
return mZenModeHelper.getConfig();
}
@Override
public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
- enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
+ enforceSystemOrSystemUI("INotificationManager.setZenMode");
final long identity = Binder.clearCallingIdentity();
try {
mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
@@ -2149,16 +2149,6 @@
}
}
- private void enforceSystemOrSystemUIOrVolume(String message) {
- if (mAudioManagerInternal != null) {
- final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
- if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
- return;
- }
- }
- enforceSystemOrSystemUI(message);
- }
-
private void enforceSystemOrSystemUI(String message) {
if (isCallerSystem()) return;
getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -2261,7 +2251,7 @@
@Override
public boolean isSystemConditionProviderEnabled(String path) {
- enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
+ enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
return mConditionProviders.isSystemProviderEnabled(path);
}
@@ -2451,7 +2441,7 @@
public void updateNotificationChannelFromAssistant(INotificationListener token, String pkg,
NotificationChannel channel) throws RemoteException {
ManagedServiceInfo info = mNotificationAssistants.checkServiceTokenLocked(token);
- if (!channel.isAllowed()) {
+ if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
// cancel
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
info.userid, REASON_CHANNEL_BANNED, null);
@@ -2995,7 +2985,7 @@
}
final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
- || !r.getChannel().isAllowed()
+ || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
|| !noteNotificationOp(pkg, callingUid);
if (isBlocked) {
Slog.e(TAG, "Suppressing notification from package by user request.");
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 6474613..598ac2e 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -442,11 +442,9 @@
}
// Reset fields that apps aren't allowed to set.
if (fromTargetApp) {
- channel.setShowBadge(false);
channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
channel.setLockscreenVisibility(r.visibility);
}
- channel.setAllowed(true);
clearLockedFields(channel);
if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
channel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
@@ -517,9 +515,6 @@
channel.setLockscreenVisibility(updatedChannel.getLockscreenVisibility());
}
}
- if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_ALLOWED) == 0) {
- channel.setAllowed(updatedChannel.isAllowed());
- }
if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_SHOW_BADGE) == 0) {
channel.setShowBadge(updatedChannel.canShowBadge());
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 00e45fd..95023da 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -1000,7 +1000,7 @@
permissions.clear();
}
permissions.add(permissionGrant.name);
- grantRuntimePermissionsLPw(pkg, permissions, false,
+ grantRuntimePermissionsLPw(pkg, permissions,
permissionGrant.fixed, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2dd9503..5bb8c05 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,7 +102,6 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.IActivityManager;
@@ -566,6 +565,18 @@
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_NUMBER);
+
+ /**
+ * Version number for the package parser cache. Increment this whenever the format or
+ * extent of cached data changes. See {@code PackageParser#setCacheDir}.
+ */
+ private static final String PACKAGE_PARSER_CACHE_VERSION = "1";
+
+ /**
+ * Whether the package parser cache is enabled.
+ */
+ private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true;
+
final ServiceThread mHandlerThread;
final PackageHandler mHandler;
@@ -804,6 +815,8 @@
private UserManagerInternal mUserManagerInternal;
+ private File mCacheDir;
+
private static class IFVerificationParams {
PackageParser.Package pkg;
boolean replacing;
@@ -2353,6 +2366,8 @@
}
}
+ mCacheDir = preparePackageParserCache(mIsUpgrade);
+
// Set flag to monitor and not change apk file paths when
// scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
@@ -2625,19 +2640,6 @@
mPackageUsage.read(mPackages);
mCompilerStats.read();
- // Read and update the usage of dex files.
- // At this point we know the code paths of the packages, so we can validate
- // the disk file and build the internal cache.
- // The usage file is expected to be small so loading and verifying it
- // should take a fairly small time compare to the other activities (e.g. package
- // scanning).
- final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
- final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
- for (int userId : currentUserIds) {
- userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
- }
- mDexManager.load(userPackages);
-
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
@@ -2795,6 +2797,21 @@
}
mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
+
+ // Read and update the usage of dex files.
+ // Do this at the end of PM init so that all the packages have their
+ // data directory reconciled.
+ // At this point we know the code paths of the packages, so we can validate
+ // the disk file and build the internal cache.
+ // The usage file is expected to be small so loading and verifying it
+ // should take a fairly small time compare to the other activities (e.g. package
+ // scanning).
+ final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
+ final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+ for (int userId : currentUserIds) {
+ userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
+ }
+ mDexManager.load(userPackages);
} // synchronized (mPackages)
} // synchronized (mInstallLock)
@@ -2815,6 +2832,35 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ private static File preparePackageParserCache(boolean isUpgrade) {
+ if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
+ return null;
+ }
+
+ if (SystemProperties.getBoolean("ro.boot.disable_package_cache", false)) {
+ Slog.i(TAG, "Disabling package parser cache due to system property.");
+ return null;
+ }
+
+ // The base directory for the package parser cache lives under /data/system/.
+ final File cacheBaseDir = FileUtils.createDir(Environment.getDataSystemDirectory(),
+ "package_cache");
+ if (cacheBaseDir == null) {
+ return null;
+ }
+
+ // If this is a system upgrade scenario, delete the contents of the package cache dir.
+ // This also serves to "GC" unused entries when the package cache version changes (which
+ // can only happen during upgrades).
+ if (isUpgrade) {
+ FileUtils.deleteContents(cacheBaseDir);
+ }
+
+ // Return the versioned package cache directory. This is something like
+ // "/data/system/package_cache/1"
+ return FileUtils.createDir(cacheBaseDir, PACKAGE_PARSER_CACHE_VERSION);
+ }
+
@Override
public boolean isFirstBoot() {
return mFirstBoot;
@@ -6938,7 +6984,7 @@
+ " flags=0x" + Integer.toHexString(parseFlags));
}
ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
- mSeparateProcesses, mOnlyCore, mMetrics);
+ mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir);
// Submit files for parsing in parallel
int fileCount = 0;
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
index 7312547..6033855 100644
--- a/services/core/java/com/android/server/pm/ParallelPackageParser.java
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -45,6 +45,7 @@
private final String[] mSeparateProcesses;
private final boolean mOnlyCore;
private final DisplayMetrics mMetrics;
+ private final File mCacheDir;
private volatile String mInterruptedInThread;
private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
@@ -53,10 +54,11 @@
"package-parsing-thread", Process.THREAD_PRIORITY_FOREGROUND);
ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
- DisplayMetrics metrics) {
+ DisplayMetrics metrics, File cacheDir) {
mSeparateProcesses = separateProcesses;
mOnlyCore = onlyCoreApps;
mMetrics = metrics;
+ mCacheDir = cacheDir;
}
static class ParseResult {
@@ -107,6 +109,7 @@
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
+ pp.setCacheDir(mCacheDir);
pr.scanFile = scanFile;
pr.pkg = parsePackage(pp, scanFile, parseFlags);
} catch (Throwable e) {
@@ -129,7 +132,7 @@
@VisibleForTesting
protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
int parseFlags) throws PackageParser.PackageParserException {
- return packageParser.parsePackage(scanFile, parseFlags);
+ return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */);
}
@Override
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index b745062..ddbc5fa 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -259,11 +259,6 @@
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
- if (si.isFloating()) {
- si.setRank(0);
- si.setActivity(null);
- }
-
if (si.isAlive()) continue;
if (removeList == null) {
@@ -293,7 +288,6 @@
si.setTimestamp(now);
si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
si.setRank(0); // It may still be pinned, so clear the rank.
- si.setActivity(null);
}
}
if (changed) {
@@ -361,7 +355,6 @@
if (oldShortcut.isPinned()) {
oldShortcut.setRank(0);
- oldShortcut.setActivity(null);
oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
if (disable) {
oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
@@ -602,10 +595,6 @@
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
final ShortcutInfo si = mShortcuts.valueAt(i);
-
- if (si.isFloating()) {
- continue; // Ignore floating shortcuts, which are not tied to any activities.
- }
final ComponentName activity = si.getActivity();
if (checked.contains(activity)) {
@@ -1368,10 +1357,6 @@
case TAG_SHORTCUT:
final ShortcutInfo si = parseShortcut(parser, packageName,
shortcutUser.getUserId());
- // Floating shortcut used to have target activities, but not anymore.
- if (si.isFloating()) { // Not really needed by just in case.
- si.setActivity(null);
- }
// Don't use addShortcut(), we don't need to save the icon.
ret.mShortcuts.put(si.getId(), si);
@@ -1478,6 +1463,7 @@
intents.clear();
intents.add(intentLegacy);
}
+
return new ShortcutInfo(
userId, id, packageName, activityComponent, /* icon =*/ null,
title, titleResId, titleResName, text, textResId, textResName,
@@ -1568,17 +1554,12 @@
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " is both dynamic and manifest at the same time.");
}
- if (!si.isFloating() && si.getActivity() == null) {
+ if (si.getActivity() == null) {
failed = true;
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
- + " is not floating, but has null activity.");
+ + " has null activity.");
}
- if (si.isFloating() && si.getActivity() != null) {
- failed = true;
- Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
- + " is floating, but has non-null activity.");
- }
- if (!si.isFloating() && !si.isEnabled()) {
+ if ((si.isDynamic() || si.isManifestShortcut()) && !si.isEnabled()) {
failed = true;
Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId()
+ " is not floating, but is disabled.");
@@ -1601,7 +1582,7 @@
}
if (failed) {
- mShortcutUser.mService.verifyError();
+ throw new IllegalStateException("See logcat for errors");
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 86f7556..c02ce6e 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -129,7 +129,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -413,9 +412,6 @@
@VisibleForTesting
ShortcutService(Context context, Looper looper, boolean onlyForPackageManagerApis) {
- if (DEBUG) {
- Binder.LOG_RUNTIME_EXCEPTION = true;
- }
mContext = Preconditions.checkNotNull(context);
LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
mHandler = new Handler(looper);
@@ -1778,9 +1774,6 @@
// Note copyNonNullFieldsFrom() does the "updatable with?" check too.
target.copyNonNullFieldsFrom(source);
- if (target.isFloating()) {
- target.setActivity(null);
- }
target.setTimestamp(injectCurrentTimeMillis());
if (replacingIcon) {
@@ -2414,7 +2407,8 @@
return false;
}
if (componentName != null) {
- if (!Objects.equals(componentName, si.getActivity())) {
+ if (si.getActivity() != null
+ && !si.getActivity().equals(componentName)) {
return false;
}
}
@@ -3934,8 +3928,4 @@
forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
}
}
-
- void verifyError() {
- Slog.e(TAG, "See logcat for errors");
- }
}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index a1060dc..6d06838 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -265,19 +265,6 @@
public void mergeAppDataDirs(ApplicationInfo ai, int userId) {
Set<String> dataDirs = putIfAbsent(mAppDataDirs, userId, new HashSet<>());
dataDirs.add(ai.dataDir);
-
- // Compute and cache the real path as well since data dir may be a symlink.
- // e.g. /data/data/ -> /data/user/0/
- try {
- dataDirs.add(PackageManagerServiceUtils.realpath(new File(ai.dataDir)));
- } catch (IOException e) {
- if (DEBUG) {
- // Verify why we're getting spam at boot for some devices.
- // b/33807524
- Slog.w(TAG, "Error to get realpath of " + ai.dataDir, e);
- }
- }
-
}
public int searchDex(String dexPath, int userId) {
@@ -302,6 +289,20 @@
return DEX_SEARCH_FOUND_SECONDARY;
}
}
+
+ // TODO(calin): What if we get a symlink? e.g. data dir may be a symlink,
+ // /data/data/ -> /data/user/0/.
+ if (DEBUG) {
+ try {
+ String dexPathReal = PackageManagerServiceUtils.realpath(new File(dexPath));
+ if (dexPathReal != dexPath) {
+ Slog.d(TAG, "Dex loaded with symlink. dexPath=" +
+ dexPath + " dexPathReal=" + dexPathReal);
+ }
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
return DEX_SEARCH_NOT_FOUND;
}
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 1083e0a..84cf0c6 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -320,7 +320,6 @@
public void onEnabledComponentChanged() {
synchronized (mLock) {
int currentUser = ActivityManager.getCurrentUser();
-
// Update listeners
ArraySet<ComponentName> enabledListeners = mComponentObserver.getEnabled(currentUser);
@@ -338,7 +337,7 @@
}
// If there is a pending state change, we'd better deal with that first
- consumeAndApplyPendingStateLocked();
+ consumeAndApplyPendingStateLocked(false);
if (mCurrentVrService == null) {
return; // No active services
@@ -606,8 +605,9 @@
if (!goingIntoVrMode) {
// Not going into VR mode, unbind whatever is running
if (mCurrentVrService != null) {
- Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
- mCurrentVrService.getUserId());
+ Slog.i(TAG, "Leaving VR mode, disconnecting "
+ + mCurrentVrService.getComponent() + " for user "
+ + mCurrentVrService.getUserId());
mCurrentVrService.disconnect();
mCurrentVrService = null;
} else {
@@ -619,8 +619,9 @@
// Unbind any running service that doesn't match the latest component/user
// selection.
if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
- Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
- " for user " + mCurrentVrService.getUserId());
+ Slog.i(TAG, "VR mode component changed to " + component
+ + ", disconnecting " + mCurrentVrService.getComponent()
+ + " for user " + mCurrentVrService.getUserId());
createAndConnectService(component, userId);
sendUpdatedCaller = true;
} else {
@@ -868,16 +869,30 @@
sBinderChecker);
}
+ /**
+ * Apply the pending VR state. If no state is pending, disconnect any currently bound
+ * VR listener service.
+ */
private void consumeAndApplyPendingStateLocked() {
+ consumeAndApplyPendingStateLocked(true);
+ }
+
+ /**
+ * Apply the pending VR state.
+ *
+ * @param disconnectIfNoPendingState if {@code true}, then any currently bound VR listener
+ * service will be disconnected if no state is pending. If this is {@code false} then the
+ * nothing will be changed when there is no pending state.
+ */
+ private void consumeAndApplyPendingStateLocked(boolean disconnectIfNoPendingState) {
if (mPendingState != null) {
updateCurrentVrServiceLocked(mPendingState.enabled,
mPendingState.targetPackageName, mPendingState.userId,
mPendingState.callingPackage);
mPendingState = null;
- } else {
+ } else if (disconnectIfNoPendingState) {
updateCurrentVrServiceLocked(false, null, 0, null);
}
-
}
private void logStateLocked() {
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
new file mode 100644
index 0000000..35004c2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.ADD_STARTING;
+
+import android.graphics.Bitmap;
+import android.os.Trace;
+import com.android.server.AttributeCache;
+
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.Message;
+import android.util.Slog;
+import android.view.IApplicationToken;
+
+/**
+ * Controller for the app window token container. This is created by activity manager to link
+ * activity records to the app window token container they use in window manager.
+ *
+ * Test class: {@link AppWindowContainerControllerTests}
+ */
+public class AppWindowContainerController
+ extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
+
+ private final IApplicationToken mToken;
+
+ private final Runnable mOnWindowsDrawn = () -> {
+ if (mListener == null) {
+ return;
+ }
+ if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
+ + AppWindowContainerController.this.mToken);
+ mListener.onWindowsDrawn();
+ };
+
+ private final Runnable mOnWindowsVisible = () -> {
+ if (mListener == null) {
+ return;
+ }
+ if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
+ + AppWindowContainerController.this.mToken);
+ mListener.onWindowsVisible();
+ };
+
+ private final Runnable mOnWindowsGone = () -> {
+ if (mListener == null) {
+ return;
+ }
+ if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
+ + AppWindowContainerController.this.mToken);
+ mListener.onWindowsGone();
+ };
+
+ public AppWindowContainerController(IApplicationToken token,
+ AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
+ boolean fullscreen, boolean showForAllUsers, int configChanges,
+ boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
+ int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
+ this(token, listener, taskId, index, requestedOrientation, fullscreen, showForAllUsers,
+ configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
+ targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
+ WindowManagerService.getInstance());
+ }
+
+ public AppWindowContainerController(IApplicationToken token,
+ AppWindowContainerListener listener, int taskId, int index, int requestedOrientation,
+ boolean fullscreen, boolean showForAllUsers, int configChanges,
+ boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
+ int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
+ WindowManagerService service) {
+ super(listener, service);
+ mToken = token;
+ synchronized(mWindowMap) {
+ AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
+ if (atoken != null) {
+ // TODO: Should this throw an exception instead?
+ Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
+ return;
+ }
+
+ // TODO: Have the controller for the task passed in when task are changed to use
+ // controller.
+ final Task task = mService.mTaskIdToTask.get(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
+ }
+
+ atoken = new AppWindowToken(mService, token, voiceInteraction, task.getDisplayContent(),
+ inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
+ requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
+ alwaysFocusable, this);
+ if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+ + " task=" + taskId + " at " + index);
+ task.addChild(atoken, index);
+ }
+ }
+
+ public void removeContainer(int displayId) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized(mWindowMap) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
+ + mToken + " from non-existing displayId=" + displayId);
+ return;
+ }
+ dc.removeAppToken(mToken.asBinder());
+ super.removeContainer();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ // TODO: Move to task window controller when that is created and rename to positionChildAt()
+ public void positionAt(int taskId, int index) {
+ synchronized(mService.mWindowMap) {
+ if (mContainer == null) {
+ Slog.w(TAG_WM,
+ "Attempted to position of non-existing app token: " + mToken);
+ return;
+ }
+
+ // TODO: Should get the window container from this owner when the task owner stuff is
+ // hooked-up.
+ final Task task = mService.mTaskIdToTask.get(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("positionChildAt: invalid taskId=" + taskId);
+ }
+ task.addChild(mContainer, index);
+ }
+
+ }
+
+ public Configuration setOrientation(int requestedOrientation, int displayId,
+ Configuration displayConfig, boolean freezeScreenIfNeeded) {
+ synchronized(mWindowMap) {
+ if (mContainer == null) {
+ Slog.w(TAG_WM,
+ "Attempted to set orientation of non-existing app token: " + mToken);
+ return null;
+ }
+
+ mContainer.setOrientation(requestedOrientation);
+
+ final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
+ return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
+
+ }
+ }
+
+ public int getOrientation() {
+ synchronized(mWindowMap) {
+ if (mContainer == null) {
+ return SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
+ return mContainer.getOrientationIgnoreVisibility();
+ }
+ }
+
+ public void setVisibility(boolean visible) {
+ synchronized(mWindowMap) {
+ if (mContainer == null) {
+ Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
+ + mToken);
+ return;
+ }
+
+ final AppWindowToken wtoken = mContainer;
+
+ if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
+ + mToken + ", visible=" + visible + "): " + mService.mAppTransition
+ + " hidden=" + wtoken.hidden + " hiddenRequested="
+ + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
+
+ mService.mOpeningApps.remove(wtoken);
+ mService.mClosingApps.remove(wtoken);
+ wtoken.waitingToShow = false;
+ wtoken.hiddenRequested = !visible;
+
+ if (!visible) {
+ // If the app is dead while it was visible, we kept its dead window on screen.
+ // Now that the app is going invisible, we can remove it. It will be restarted
+ // if made visible again.
+ wtoken.removeDeadWindows();
+ wtoken.setVisibleBeforeClientHidden();
+ } else {
+ if (!mService.mAppTransition.isTransitionSet()
+ && mService.mAppTransition.isReady()) {
+ // Add the app mOpeningApps if transition is unset but ready. This means
+ // we're doing a screen freeze, and the unfreeze will wait for all opening
+ // apps to be ready.
+ mService.mOpeningApps.add(wtoken);
+ }
+ wtoken.startingMoved = false;
+ // If the token is currently hidden (should be the common case), or has been
+ // stopped, then we need to set up to wait for its windows to be ready.
+ if (wtoken.hidden || wtoken.mAppStopped) {
+ wtoken.clearAllDrawn();
+
+ // If the app was already visible, don't reset the waitingToShow state.
+ if (wtoken.hidden) {
+ wtoken.waitingToShow = true;
+ }
+
+ if (wtoken.clientHidden) {
+ // In the case where we are making an app visible
+ // but holding off for a transition, we still need
+ // to tell the client to make its windows visible so
+ // they get drawn. Otherwise, we will wait on
+ // performing the transition until all windows have
+ // been drawn, they never will be, and we are sad.
+ wtoken.clientHidden = false;
+ wtoken.sendAppVisibilityToClients();
+ }
+ }
+ wtoken.requestUpdateWallpaperIfNeeded();
+
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
+ wtoken.mAppStopped = false;
+ }
+
+ // If we are preparing an app transition, then delay changing
+ // the visibility of this token until we execute that transition.
+ if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
+ // A dummy animation is a placeholder animation which informs others that an
+ // animation is going on (in this case an application transition). If the animation
+ // was transferred from another application/animator, no dummy animator should be
+ // created since an animation is already in progress.
+ if (wtoken.mAppAnimator.usingTransferredAnimation
+ && wtoken.mAppAnimator.animation == null) {
+ Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
+ + ", using null transferred animation!");
+ }
+ if (!wtoken.mAppAnimator.usingTransferredAnimation &&
+ (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
+ TAG_WM, "Setting dummy animation on: " + wtoken);
+ wtoken.mAppAnimator.setDummyAnimation();
+ }
+ wtoken.inPendingTransaction = true;
+ if (visible) {
+ mService.mOpeningApps.add(wtoken);
+ wtoken.mEnteringAnimation = true;
+ } else {
+ mService.mClosingApps.add(wtoken);
+ wtoken.mEnteringAnimation = false;
+ }
+ if (mService.mAppTransition.getAppTransition()
+ == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
+ // We're launchingBehind, add the launching activity to mOpeningApps.
+ final WindowState win =
+ mService.getDefaultDisplayContentLocked().findFocusedWindow();
+ if (win != null) {
+ final AppWindowToken focusedToken = win.mAppToken;
+ if (focusedToken != null) {
+ if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
+ + " adding " + focusedToken + " to mOpeningApps");
+ // Force animation to be loaded.
+ focusedToken.hidden = true;
+ mService.mOpeningApps.add(focusedToken);
+ }
+ }
+ }
+ return;
+ }
+
+ wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
+ wtoken.updateReportedVisibilityLocked();
+ }
+ }
+
+ /**
+ * Notifies that we launched an app that might be visible or not visible depending on what kind
+ * of Keyguard flags it's going to set on its windows.
+ */
+ public void notifyUnknownVisibilityLaunched() {
+ synchronized(mWindowMap) {
+ if (mContainer != null) {
+ mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
+ }
+ }
+ }
+
+ public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
+ CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
+ IBinder transferFrom, boolean createIfNeeded) {
+ synchronized(mWindowMap) {
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
+ + " pkg=" + pkg + " transferFrom=" + transferFrom);
+
+ if (mContainer == null) {
+ Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
+ return false;
+ }
+
+ // If the display is frozen, we won't do anything until the actual window is
+ // displayed so there is no reason to put in the starting window.
+ if (!mService.okToDisplay()) {
+ return false;
+ }
+
+ if (mContainer.startingData != null) {
+ return false;
+ }
+
+ // If this is a translucent window, then don't show a starting window -- the current
+ // effect (a full-screen opaque starting window that fades away to the real contents
+ // when it is ready) does not work for this.
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
+ + Integer.toHexString(theme));
+ if (theme != 0) {
+ AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
+ com.android.internal.R.styleable.Window, mService.mCurrentUserId);
+ if (ent == null) {
+ // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
+ // see that.
+ return false;
+ }
+ final boolean windowIsTranslucent = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+ final boolean windowIsFloating = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowIsFloating, false);
+ final boolean windowShowWallpaper = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowShowWallpaper, false);
+ final boolean windowDisableStarting = ent.array.getBoolean(
+ com.android.internal.R.styleable.Window_windowDisablePreview, false);
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
+ + " Floating=" + windowIsFloating
+ + " ShowWallpaper=" + windowShowWallpaper);
+ if (windowIsTranslucent) {
+ return false;
+ }
+ if (windowIsFloating || windowDisableStarting) {
+ return false;
+ }
+ if (windowShowWallpaper) {
+ if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
+ == null) {
+ // If this theme is requesting a wallpaper, and the wallpaper
+ // is not currently visible, then this effectively serves as
+ // an opaque window and our starting window transition animation
+ // can still work. We just need to make sure the starting window
+ // is also showing the wallpaper.
+ windowFlags |= FLAG_SHOW_WALLPAPER;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ if (mContainer.transferStartingWindow(transferFrom)) {
+ return true;
+ }
+
+ // There is no existing starting window, and the caller doesn't
+ // want us to create one, so that's it!
+ if (!createIfNeeded) {
+ return false;
+ }
+
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
+ mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
+ labelRes, icon, logo, windowFlags);
+ final Message m = mService.mH.obtainMessage(ADD_STARTING, mContainer);
+ // Note: we really want to do sendMessageAtFrontOfQueue() because we
+ // want to process the message ASAP, before any other queued
+ // messages.
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
+ mService.mH.sendMessageAtFrontOfQueue(m);
+ }
+ return true;
+ }
+
+ public void removeStartingWindow() {
+ synchronized (mWindowMap) {
+ mService.scheduleRemoveStartingWindowLocked(mContainer);
+ }
+ }
+
+ public void pauseKeyDispatching() {
+ synchronized (mWindowMap) {
+ if (mContainer != null) {
+ mService.mInputMonitor.pauseDispatchingLw(mContainer);
+ }
+ }
+ }
+
+ public void resumeKeyDispatching() {
+ synchronized (mWindowMap) {
+ if (mContainer != null) {
+ mService.mInputMonitor.resumeDispatchingLw(mContainer);
+ }
+ }
+ }
+
+ public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
+ synchronized(mWindowMap) {
+ if (mContainer == null) {
+ Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
+ return;
+ }
+ mContainer.notifyAppResumed(wasStopped, allowSavedSurface);
+ }
+ }
+
+ public void notifyAppStopped() {
+ synchronized(mWindowMap) {
+ if (mContainer == null) {
+ Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
+ + mToken);
+ return;
+ }
+ mContainer.notifyAppStopped();
+ }
+ }
+
+ public void startFreezingScreen(int configChanges) {
+ synchronized(mWindowMap) {
+ if (configChanges == 0 && mService.okToDisplay()) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
+ return;
+ }
+
+ if (mContainer == null) {
+ Slog.w(TAG_WM,
+ "Attempted to freeze screen with non-existing app token: " + mContainer);
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ mContainer.startFreezingScreen();
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ public void stopFreezingScreen(boolean force) {
+ synchronized(mWindowMap) {
+ if (mContainer == null) {
+ return;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
+ + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
+ mContainer.stopFreezingScreen(true, force);
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ /**
+ * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
+ * In portrait mode, it grabs the full screenshot.
+ *
+ * @param displayId the Display to take a screenshot of.
+ * @param width the width of the target bitmap
+ * @param height the height of the target bitmap
+ * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
+ */
+ public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
+ final DisplayContent dc;
+ synchronized(mWindowMap) {
+ dc = mRoot.getDisplayContentOrCreate(displayId);
+ if (dc == null) {
+ if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
+ + ": returning null. No Display for displayId=" + displayId);
+ return null;
+ }
+ }
+ return dc.screenshotApplications(mToken.asBinder(), width, height,
+ false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
+ false /* wallpaperOnly */);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+
+
+ void reportWindowsDrawn() {
+ mService.mH.post(mOnWindowsDrawn);
+ }
+
+ void reportWindowsVisible() {
+ mService.mH.post(mOnWindowsVisible);
+ }
+
+ void reportWindowsGone() {
+ mService.mH.post(mOnWindowsGone);
+ }
+
+ /** Calls directly into activity manager so window manager lock shouldn't held. */
+ boolean keyDispatchingTimedOut(String reason) {
+ return mListener != null && mListener.keyDispatchingTimedOut(reason);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerListener.java b/services/core/java/com/android/server/wm/AppWindowContainerListener.java
new file mode 100644
index 0000000..12d4b2f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppWindowContainerListener.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+/** Interface used by the creator of the controller to listen to changes with the container. */
+public interface AppWindowContainerListener extends WindowContainerListener {
+ /** Called when the windows associated app window container are drawn. */
+ void onWindowsDrawn();
+ /** Called when the windows associated app window container are visible. */
+ void onWindowsVisible();
+ /** Called when the windows associated app window container are no longer visible. */
+ void onWindowsGone();
+ /**
+ * Called when the key dispatching to a window associated with the app window container
+ * timed-out.
+ */
+ boolean keyDispatchingTimedOut(String reason);
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 6147885..0a48758 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -47,7 +47,6 @@
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.logWithStack;
-import android.content.pm.ActivityInfo;
import android.os.Debug;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.input.InputApplicationHandle;
@@ -173,8 +172,10 @@
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
- int configChanges, boolean launchTaskBehind, boolean alwaysFocusable) {
+ int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
+ AppWindowContainerController controller) {
this(service, token, voiceInteraction, dc);
+ setController(controller);
mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
mFillsParent = fullscreen;
mShowForAllUsers = showForAllUsers;
@@ -251,9 +252,12 @@
}
if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
+ numInteresting + " visible=" + numVisible);
+ final AppWindowContainerController controller = getController();
if (nowDrawn != reportedDrawn) {
if (nowDrawn) {
- mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_DRAWN, this).sendToTarget();
+ if (controller != null) {
+ controller.reportWindowsDrawn();
+ }
}
reportedDrawn = nowDrawn;
}
@@ -261,8 +265,13 @@
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Visibility changed in " + this + ": vis=" + nowVisible);
reportedVisible = nowVisible;
- mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_WINDOWS,
- nowVisible ? 1 : 0, nowGone ? 1 : 0, this).sendToTarget();
+ if (controller != null) {
+ if (nowVisible) {
+ controller.reportWindowsVisible();
+ } else {
+ controller.reportWindowsGone();
+ }
+ }
}
}
@@ -399,6 +408,11 @@
return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
}
+ AppWindowContainerController getController() {
+ final WindowContainerController controller = super.getController();
+ return controller != null ? (AppWindowContainerController) controller : null;
+ }
+
@Override
boolean isVisible() {
// If the app token isn't hidden then it is considered visible and there is no need to check
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index da2c6a7..04ae72f 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -11,6 +11,7 @@
import android.util.Slog;
import android.util.TypedValue;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wm.DimLayer.DimLayerUser;
import java.io.PrintWriter;
@@ -310,6 +311,11 @@
}
}
+ @VisibleForTesting
+ boolean hasDimLayerUser(DimLayer.DimLayerUser dimLayerUser) {
+ return mState.containsKey(dimLayerUser);
+ }
+
void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
applyDim(dimLayerUser, animator, false /* aboveApp */);
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 3fbe36f..f754775 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -251,16 +251,14 @@
}
if (appWindowToken != null && appWindowToken.appToken != null) {
- try {
- // Notify the activity manager about the timeout and let it decide whether
- // to abort dispatching or keep waiting.
- boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
- if (! abort) {
- // The activity manager declined to abort dispatching.
- // Wait a bit longer and timeout again later.
- return appWindowToken.mInputDispatchingTimeoutNanos;
- }
- } catch (RemoteException ex) {
+ // Notify the activity manager about the timeout and let it decide whether
+ // to abort dispatching or keep waiting.
+ final AppWindowContainerController controller = appWindowToken.getController();
+ final boolean abort = controller != null && controller.keyDispatchingTimedOut(reason);
+ if (!abort) {
+ // The activity manager declined to abort dispatching.
+ // Wait a bit longer and timeout again later.
+ return appWindowToken.mInputDispatchingTimeoutNanos;
}
} else if (windowState != null) {
try {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 349740b..dc06d12 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -166,6 +166,19 @@
}
/**
+ * Get an array with display ids ordered by focus priority - last items should be given
+ * focus first. Sparse array just maps position to displayId.
+ */
+ void getDisplaysInFocusOrder(SparseIntArray displaysInFocusOrder) {
+ displaysInFocusOrder.clear();
+
+ final int size = mChildren.size();
+ for (int i = 0; i < size; ++i) {
+ displaysInFocusOrder.put(i, mChildren.get(i).getDisplayId());
+ }
+ }
+
+ /**
* Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
* there is a Display for the displayId.
*
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6005a99..a468598 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -144,14 +144,22 @@
mDeferRemoval = true;
return;
}
+ removeImmediately();
+ }
+
+ @Override
+ void removeImmediately() {
if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
mDeferRemoval = false;
+
+ // Make sure to remove dim layer user first before removing task its from parent.
DisplayContent content = getDisplayContent();
if (content != null) {
content.mDimLayerController.removeDimLayerUser(this);
}
- removeImmediately();
+
+ super.removeImmediately();
mService.mTaskIdToTask.delete(mTaskId);
}
@@ -170,7 +178,12 @@
/** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
void positionTaskInStack(TaskStack stack, int position, Rect bounds,
Configuration overrideConfig) {
- if (mStack != null && stack != mStack) {
+ if (mStack == null) {
+ // There is an assumption that task already has a stack at this point, so lets make
+ // sure we comply with it.
+ throw new IllegalStateException("Trying to position task that has no parent.");
+ }
+ if (stack != mStack) {
// Task is already attached to a different stack. First we need to remove it from there
// and add to top of the target stack. We will move it proper position afterwards.
if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index c9bf4fa..0e6ecde 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -75,6 +75,9 @@
private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
new Pools.SynchronizedPool<>(3);
+ // The owner/creator for this container. No controller if null.
+ private WindowContainerController mController;
+
final protected WindowContainer getParent() {
return mParent;
}
@@ -188,6 +191,10 @@
if (mParent != null) {
mParent.removeChild(this);
}
+
+ if (mController != null) {
+ setController(null);
+ }
}
/**
@@ -662,6 +669,23 @@
} while (current != null);
}
+ WindowContainerController getController() {
+ return mController;
+ }
+
+ void setController(WindowContainerController controller) {
+ if (mController != null && controller != null) {
+ throw new IllegalArgumentException("Can't set controller=" + mController
+ + " for container=" + this + " Already set to=" + mController);
+ }
+ if (controller != null) {
+ controller.setContainer(this);
+ } else if (mController != null) {
+ mController.setContainer(null);
+ }
+ mController = controller;
+ }
+
/**
* Dumps the names of this container children in the input print writer indenting each
* level with the input prefix.
diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java
new file mode 100644
index 0000000..84ffc35
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContainerController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.os.IBinder;
+
+import java.util.HashMap;
+
+/**
+ * Class that allows the owner/creator of a {@link WindowContainer} to communicate directly with the
+ * container and make changes.
+ * Note that public calls (mostly in sub-classes) into this class are assumed to be originating from
+ * outside the window manager so the window manager lock is held and appropriate permissions are
+ * checked before calls are allowed to proceed.
+ *
+ * Test class: {@link WindowContainerControllerTests}
+ */
+class WindowContainerController<E extends WindowContainer, I extends WindowContainerListener> {
+
+ final WindowManagerService mService;
+ final RootWindowContainer mRoot;
+ final HashMap<IBinder, WindowState> mWindowMap;
+
+ // The window container this controller owns.
+ E mContainer;
+ // Interface for communicating changes back to the owner.
+ final I mListener;
+
+ WindowContainerController(I listener, WindowManagerService service) {
+ mListener = listener;
+ mService = service;
+ mRoot = mService != null ? mService.mRoot : null;
+ mWindowMap = mService != null ? mService.mWindowMap : null;
+ }
+
+ void setContainer(E container) {
+ if (mContainer != null && container != null) {
+ throw new IllegalArgumentException("Can't set container=" + container
+ + " for controller=" + this + " Already set to=" + mContainer);
+ }
+ mContainer = container;
+ }
+
+ void removeContainer() {
+ // TODO: See if most uses cases should support removeIfPossible here.
+ //mContainer.removeIfPossible();
+ if (mContainer != null) {
+ mContainer.setController(null);
+ mContainer = null;
+ }
+ }
+
+ boolean checkCallingPermission(String permission, String func) {
+ return mService.checkCallingPermission(permission, func);
+ }
+}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/services/core/java/com/android/server/wm/WindowContainerListener.java
similarity index 69%
copy from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
copy to services/core/java/com/android/server/wm/WindowContainerListener.java
index a35e71d..ab9d71a 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/services/core/java/com/android/server/wm/WindowContainerListener.java
@@ -11,9 +11,15 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
*/
-package android.net.wifi.aware;
+package com.android.server.wm;
-parcelable WifiAwareCharacteristics;
+/**
+ * Interface used by the owner/creator of the container to listen to changes with the container.
+ * @see WindowContainerController
+ */
+public interface WindowContainerListener {
+
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2ade924..38cb543 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -90,7 +90,6 @@
import android.view.Gravity;
import android.view.PointerIcon;
import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IApplicationToken;
import android.view.IDockedStackListener;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
@@ -133,7 +132,6 @@
import com.android.internal.view.IInputMethodClient;
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.WindowManagerPolicyThread;
-import com.android.server.AttributeCache;
import com.android.server.DisplayThread;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
@@ -228,7 +226,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -240,7 +237,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static java.lang.Integer.MAX_VALUE;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -915,16 +911,19 @@
void onAppFreezeTimeout();
}
- public static WindowManagerService main(final Context context,
- final InputManagerService im,
- final boolean haveInputMethods, final boolean showBootMsgs,
- final boolean onlyCore, WindowManagerPolicy policy) {
- final WindowManagerService[] holder = new WindowManagerService[1];
- DisplayThread.getHandler().runWithScissors(() -> {
- holder[0] = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
- onlyCore, policy);
- }, 0);
- return holder[0];
+ private static WindowManagerService sInstance;
+
+ static WindowManagerService getInstance() {
+ return sInstance;
+ }
+
+ public static WindowManagerService main(final Context context, final InputManagerService im,
+ final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
+ WindowManagerPolicy policy) {
+ DisplayThread.getHandler().runWithScissors(() ->
+ sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
+ onlyCore, policy), 0);
+ return sInstance;
}
private void initPolicy() {
@@ -2369,7 +2368,7 @@
return atoken.mAppAnimator.animation != null;
}
- private boolean checkCallingPermission(String permission, String func) {
+ boolean checkCallingPermission(String permission, String func) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == Process.myPid()) {
return true;
@@ -2442,73 +2441,6 @@
}
}
- @Override
- public void addAppToken(int addPos, IApplicationToken token, int taskId,
- int requestedOrientation, boolean fullscreen, boolean showForAllUsers,
- int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- boolean alwaysFocusable, int targetSdkVersion, int rotationAnimationHint) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "addAppToken()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- // Get the dispatching timeout here while we are not holding any locks so that it
- // can be cached by the AppWindowToken. The timeout value is used later by the
- // input dispatcher in code that does hold locks. If we did not cache the value
- // here we would run the chance of introducing a deadlock between the window manager
- // (which holds locks while updating the input dispatcher state) and the activity manager
- // (which holds locks while querying the application token).
- long inputDispatchingTimeoutNanos;
- try {
- inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
- } catch (RemoteException ex) {
- Slog.w(TAG_WM, "Could not get dispatching timeout.", ex);
- inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- }
-
- synchronized(mWindowMap) {
- AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
- if (atoken != null) {
- Slog.w(TAG_WM, "Attempted to add existing app token: " + token);
- return;
- }
-
- Task task = mTaskIdToTask.get(taskId);
- if (task == null) {
- throw new IllegalArgumentException("addAppToken: invalid taskId=" + taskId);
- }
-
- atoken = new AppWindowToken(this, token, voiceInteraction, task.getDisplayContent(),
- inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
- requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
- alwaysFocusable);
- if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
- + " task=" + taskId + " at " + addPos);
-
- task.addChild(atoken, addPos);
- }
- }
-
- @Override
- public void addAppToTask(IBinder token, int taskId) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppTask()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- final AppWindowToken atoken = mRoot.getAppWindowToken(token);
- if (atoken == null) {
- Slog.w(TAG_WM, "Attempted to set task id of non-existing app token: " + token);
- return;
- }
-
- Task task = mTaskIdToTask.get(taskId);
- if (task == null) {
- throw new IllegalArgumentException("setAppTask: invalid taskId=" + taskId);
- }
- task.addChild(atoken, MAX_VALUE /* at top */);
- }
- }
-
public void addTask(int taskId, int stackId, int userId, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
boolean toTop, boolean showForAllUsers) {
@@ -2675,35 +2607,6 @@
}
}
- @Override
- public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppOrientation()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- final AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
- if (atoken == null) {
- Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + token);
- return;
- }
-
- atoken.setOrientation(requestedOrientation);
- }
- }
-
- @Override
- public int getAppOrientation(IApplicationToken token) {
- synchronized(mWindowMap) {
- final AppWindowToken wtoken = mRoot.getAppWindowToken(token.asBinder());
- if (wtoken == null) {
- return SCREEN_ORIENTATION_UNSPECIFIED;
- }
-
- return wtoken.getOrientationIgnoreVisibility();
- }
- }
-
void setFocusTaskRegionLocked() {
final Task focusedTask = mFocusedApp != null ? mFocusedApp.mTask : null;
if (focusedTask != null) {
@@ -2912,113 +2815,6 @@
}
}
- @Override
- public boolean setAppStartingWindow(IBinder token, String pkg,
- int theme, CompatibilityInfo compatInfo,
- CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
- int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppStartingWindow()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- if (DEBUG_STARTING_WINDOW) Slog.v(
- TAG_WM, "setAppStartingWindow: token=" + token + " pkg=" + pkg
- + " transferFrom=" + transferFrom);
-
- final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
- if (wtoken == null) {
- Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + token);
- return false;
- }
-
- // If the display is frozen, we won't do anything until the
- // actual window is displayed so there is no reason to put in
- // the starting window.
- if (!okToDisplay()) {
- return false;
- }
-
- if (wtoken.startingData != null) {
- return false;
- }
-
- // If this is a translucent window, then don't
- // show a starting window -- the current effect (a full-screen
- // opaque starting window that fades away to the real contents
- // when it is ready) does not work for this.
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
- + Integer.toHexString(theme));
- if (theme != 0) {
- AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
- com.android.internal.R.styleable.Window, mCurrentUserId);
- if (ent == null) {
- // Whoops! App doesn't exist. Um. Okay. We'll just
- // pretend like we didn't see that.
- return false;
- }
- final boolean windowIsTranslucent = ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsTranslucent, false);
- final boolean windowIsFloating = ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowIsFloating, false);
- final boolean windowShowWallpaper = ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowShowWallpaper, false);
- final boolean windowDisableStarting = ent.array.getBoolean(
- com.android.internal.R.styleable.Window_windowDisablePreview, false);
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
- + " Floating=" + windowIsFloating
- + " ShowWallpaper=" + windowShowWallpaper);
- if (windowIsTranslucent) {
- return false;
- }
- if (windowIsFloating || windowDisableStarting) {
- return false;
- }
- if (windowShowWallpaper) {
- if (wtoken.getDisplayContent().mWallpaperController.getWallpaperTarget()
- == null) {
- // If this theme is requesting a wallpaper, and the wallpaper
- // is not currently visible, then this effectively serves as
- // an opaque window and our starting window transition animation
- // can still work. We just need to make sure the starting window
- // is also showing the wallpaper.
- windowFlags |= FLAG_SHOW_WALLPAPER;
- } else {
- return false;
- }
- }
- }
-
- if (wtoken.transferStartingWindow(transferFrom)) {
- return true;
- }
-
- // There is no existing starting window, and the caller doesn't
- // want us to create one, so that's it!
- if (!createIfNeeded) {
- return false;
- }
-
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
- wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
- labelRes, icon, logo, windowFlags);
- Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
- // Note: we really want to do sendMessageAtFrontOfQueue() because we
- // want to process the message ASAP, before any other queued
- // messages.
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
- mH.sendMessageAtFrontOfQueue(m);
- }
- return true;
- }
-
- public void removeAppStartingWindow(IBinder token) {
- synchronized (mWindowMap) {
- final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
- scheduleRemoveStartingWindowLocked(wtoken);
- }
- }
-
public void setAppFullscreen(IBinder token, boolean toOpaque) {
synchronized (mWindowMap) {
final AppWindowToken atoken = mRoot.getAppWindowToken(token);
@@ -3055,233 +2851,6 @@
}
}
- @Override
- public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppResumed()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
- if (wtoken == null) {
- Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
- return;
- }
- wtoken.notifyAppResumed(wasStopped, allowSavedSurface);
- }
- }
-
- @Override
- public void notifyAppStopped(IBinder token) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppStopped()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- final AppWindowToken wtoken;
- wtoken = mRoot.getAppWindowToken(token);
- if (wtoken == null) {
- Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + token);
- return;
- }
- wtoken.notifyAppStopped();
- }
- }
-
- @Override
- public void setAppVisibility(IBinder token, boolean visible) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppVisibility()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- AppWindowToken wtoken;
-
- synchronized(mWindowMap) {
- wtoken = mRoot.getAppWindowToken(token);
- if (wtoken == null) {
- Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
- return;
- }
-
- if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility(" +
- token + ", visible=" + visible + "): " + mAppTransition +
- " hidden=" + wtoken.hidden + " hiddenRequested=" +
- wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
-
- mOpeningApps.remove(wtoken);
- mClosingApps.remove(wtoken);
- wtoken.waitingToShow = false;
- wtoken.hiddenRequested = !visible;
-
- if (!visible) {
- // If the app is dead while it was visible, we kept its dead window on screen.
- // Now that the app is going invisible, we can remove it. It will be restarted
- // if made visible again.
- wtoken.removeDeadWindows();
- wtoken.setVisibleBeforeClientHidden();
- } else if (visible) {
- if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
- // Add the app mOpeningApps if transition is unset but ready. This means
- // we're doing a screen freeze, and the unfreeze will wait for all opening
- // apps to be ready.
- mOpeningApps.add(wtoken);
- }
- wtoken.startingMoved = false;
- // If the token is currently hidden (should be the common case), or has been
- // stopped, then we need to set up to wait for its windows to be ready.
- if (wtoken.hidden || wtoken.mAppStopped) {
- wtoken.clearAllDrawn();
-
- // If the app was already visible, don't reset the waitingToShow state.
- if (wtoken.hidden) {
- wtoken.waitingToShow = true;
- }
-
- if (wtoken.clientHidden) {
- // In the case where we are making an app visible
- // but holding off for a transition, we still need
- // to tell the client to make its windows visible so
- // they get drawn. Otherwise, we will wait on
- // performing the transition until all windows have
- // been drawn, they never will be, and we are sad.
- wtoken.clientHidden = false;
- wtoken.sendAppVisibilityToClients();
- }
- }
- wtoken.requestUpdateWallpaperIfNeeded();
-
- if (DEBUG_ADD_REMOVE) Slog.v(
- TAG_WM, "No longer Stopped: " + wtoken);
- wtoken.mAppStopped = false;
- }
-
- // If we are preparing an app transition, then delay changing
- // the visibility of this token until we execute that transition.
- if (okToDisplay() && mAppTransition.isTransitionSet()) {
- // A dummy animation is a placeholder animation which informs others that an
- // animation is going on (in this case an application transition). If the animation
- // was transferred from another application/animator, no dummy animator should be
- // created since an animation is already in progress.
- if (wtoken.mAppAnimator.usingTransferredAnimation
- && wtoken.mAppAnimator.animation == null) {
- Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
- + ", using null transfered animation!");
- }
- if (!wtoken.mAppAnimator.usingTransferredAnimation &&
- (!wtoken.startingDisplayed || mSkipAppTransitionAnimation)) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(
- TAG_WM, "Setting dummy animation on: " + wtoken);
- wtoken.mAppAnimator.setDummyAnimation();
- }
- wtoken.inPendingTransaction = true;
- if (visible) {
- mOpeningApps.add(wtoken);
- wtoken.mEnteringAnimation = true;
- } else {
- mClosingApps.add(wtoken);
- wtoken.mEnteringAnimation = false;
- }
- if (mAppTransition.getAppTransition() == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
- // We're launchingBehind, add the launching activity to mOpeningApps.
- final WindowState win = getDefaultDisplayContentLocked().findFocusedWindow();
- if (win != null) {
- final AppWindowToken focusedToken = win.mAppToken;
- if (focusedToken != null) {
- if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, " +
- " adding " + focusedToken + " to mOpeningApps");
- // Force animation to be loaded.
- focusedToken.hidden = true;
- mOpeningApps.add(focusedToken);
- }
- }
- }
- return;
- }
-
- final long origId = Binder.clearCallingIdentity();
- wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
- wtoken.updateReportedVisibilityLocked();
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- /**
- * Notifies that we launched an app that might be visible or not visible depending on what kind
- * of Keyguard flags it's going to set on its windows.
- */
- public void notifyUnknownAppVisibilityLaunched(IBinder token) {
- synchronized(mWindowMap) {
- AppWindowToken appWindow = mRoot.getAppWindowToken(token);
- if (appWindow != null) {
- mUnknownAppVisibilityController.notifyLaunched(appWindow);
- }
- }
- }
-
- @Override
- public void startAppFreezingScreen(IBinder token, int configChanges) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- if (configChanges == 0 && okToDisplay()) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + token);
- return;
- }
-
- final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
- if (wtoken == null || wtoken.appToken == null) {
- Slog.w(TAG_WM, "Attempted to freeze screen with non-existing app token: " + wtoken);
- return;
- }
- final long origId = Binder.clearCallingIdentity();
- wtoken.startFreezingScreen();
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
- public void stopAppFreezingScreen(IBinder token, boolean force) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized(mWindowMap) {
- final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
- if (wtoken == null || wtoken.appToken == null) {
- return;
- }
- final long origId = Binder.clearCallingIdentity();
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token + ": hidden="
- + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
- wtoken.stopFreezingScreen(true, force);
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
- public void removeAppToken(IBinder binder, int displayId) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeAppToken()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized(mWindowMap) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: " + binder
- + " from non-existing displayId=" + displayId);
- return;
- }
- dc.removeAppToken(binder);
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) {
if (wtoken == null) {
return;
@@ -3850,9 +3419,9 @@
return;
}
- // If this isn't coming from the current user, ignore it.
- if (Binder.getCallingUserHandle().getIdentifier() != mCurrentUserId) {
- Log.d(TAG_WM, "non-current user, ignore disableKeyguard");
+ // If this isn't coming from the current profiles, ignore it.
+ if (!isCurrentProfileLocked(UserHandle.getCallingUserId())) {
+ Log.d(TAG_WM, "non-current profiles, ignore disableKeyguard");
return;
}
@@ -4523,7 +4092,7 @@
}
try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
- return screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
+ return screenshotApplications(null /* appToken */, DEFAULT_DISPLAY, -1 /* width */,
-1 /* height */, true /* includeFullDisplay */, 1f /* frameScale */,
Bitmap.Config.ARGB_8888, true /* wallpaperOnly */);
} finally {
@@ -4544,7 +4113,7 @@
}
FgThread.getHandler().post(() -> {
- Bitmap bm = screenshotApplicationsInner(null /* appToken */, DEFAULT_DISPLAY,
+ Bitmap bm = screenshotApplications(null /* appToken */, DEFAULT_DISPLAY,
-1 /* width */, -1 /* height */, true /* includeFullDisplay */,
1f /* frameScale */, Bitmap.Config.ARGB_8888, false /* wallpaperOnly */);
try {
@@ -4563,37 +4132,12 @@
* @param displayId the Display to take a screenshot of.
* @param width the width of the target bitmap
* @param height the height of the target bitmap
- * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
- */
- @Override
- public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height,
- float frameScale) {
- if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
- "screenshotApplications()")) {
- throw new SecurityException("Requires READ_FRAME_BUFFER permission");
- }
- try {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
- return screenshotApplicationsInner(appToken, displayId, width, height, false,
- frameScale, Bitmap.Config.RGB_565, false);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
- /**
- * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
- * In portrait mode, it grabs the full screenshot.
- *
- * @param displayId the Display to take a screenshot of.
- * @param width the width of the target bitmap
- * @param height the height of the target bitmap
* @param includeFullDisplay true if the screen should not be cropped before capture
* @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
* @param config of the output bitmap
* @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
*/
- private Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width,
+ private Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
int height, boolean includeFullDisplay, float frameScale, Bitmap.Config config,
boolean wallpaperOnly) {
final DisplayContent displayContent;
@@ -5907,34 +5451,6 @@
private boolean mEventDispatchingEnabled;
@Override
- public void pauseKeyDispatching(IBinder binder) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "pauseKeyDispatching()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized (mWindowMap) {
- WindowToken token = mRoot.getAppWindowToken(binder);
- if (token != null) {
- mInputMonitor.pauseDispatchingLw(token);
- }
- }
- }
-
- @Override
- public void resumeKeyDispatching(IBinder binder) {
- if (!checkCallingPermission(MANAGE_APP_TOKENS, "resumeKeyDispatching()")) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
-
- synchronized (mWindowMap) {
- WindowToken token = mRoot.getAppWindowToken(binder);
- if (token != null) {
- mInputMonitor.resumeDispatchingLw(token);
- }
- }
- }
-
- @Override
public void setEventDispatching(boolean enabled) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "setEventDispatching()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -6065,8 +5581,6 @@
public static final int ADD_STARTING = 5;
public static final int REMOVE_STARTING = 6;
public static final int FINISHED_STARTING = 7;
- public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
- public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
public static final int WINDOW_FREEZE_TIMEOUT = 11;
public static final int APP_TRANSITION_TIMEOUT = 13;
@@ -6328,37 +5842,6 @@
}
} break;
- case REPORT_APPLICATION_TOKEN_DRAWN: {
- final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-
- try {
- if (DEBUG_VISIBILITY) Slog.v(
- TAG_WM, "Reporting drawn in " + wtoken);
- wtoken.appToken.windowsDrawn();
- } catch (RemoteException ex) {
- }
- } break;
-
- case REPORT_APPLICATION_TOKEN_WINDOWS: {
- final AppWindowToken wtoken = (AppWindowToken)msg.obj;
-
- boolean nowVisible = msg.arg1 != 0;
- boolean nowGone = msg.arg2 != 0;
-
- try {
- if (DEBUG_VISIBILITY) Slog.v(
- TAG_WM, "Reporting visible in " + wtoken
- + " visible=" + nowVisible
- + " gone=" + nowGone);
- if (nowVisible) {
- wtoken.appToken.windowsVisible();
- } else {
- wtoken.appToken.windowsGone();
- }
- } catch (RemoteException ex) {
- }
- } break;
-
case WINDOW_FREEZE_TIMEOUT: {
// TODO(multidisplay): Can non-default displays rotate?
synchronized (mWindowMap) {
@@ -7155,6 +6638,16 @@
displayInfo.overscanRight, displayInfo.overscanBottom);
}
+ /**
+ * Get an array with display ids ordered by focus priority - last items should be given
+ * focus first. Sparse array just maps position to displayId.
+ */
+ public void getDisplaysInFocusOrder(SparseIntArray displaysInFocusOrder) {
+ synchronized(mWindowMap) {
+ mRoot.getDisplaysInFocusOrder(displaysInFocusOrder);
+ }
+ }
+
@Override
public void setOverscan(int displayId, int left, int top, int right, int bottom) {
if (mContext.checkCallingOrSelfPermission(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e5c8d02..0346e4c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4788,7 +4788,9 @@
}
}
- private void wipeDataLocked(boolean wipeExtRequested, String reason, boolean force) {
+ private void wipeDataNoLock(boolean wipeExtRequested, String reason, boolean force) {
+ wtfIfInLock();
+
if (wipeExtRequested) {
StorageManager sm = (StorageManager) mContext.getSystemService(
Context.STORAGE_SERVICE);
@@ -4808,13 +4810,14 @@
}
final int userHandle = mInjector.userHandleGetCallingUserId();
enforceFullCrossUsersPermission(userHandle);
+
+ final String source;
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
final ActiveAdmin admin = getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
-
- final String source = admin.info.getComponent().flattenToShortString();
+ source = admin.info.getComponent().flattenToShortString();
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -4844,45 +4847,47 @@
}
}
- boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
- wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
- "DevicePolicyManager.wipeData() from " + source, /*force=*/ true);
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
}
+ final boolean wipeExtRequested = (flags & WIPE_EXTERNAL_STORAGE) != 0;
+ wipeDeviceNoLock(wipeExtRequested, userHandle,
+ "DevicePolicyManager.wipeData() from " + source, /*force=*/ true);
}
- private void wipeDeviceOrUserLocked(
+ private void wipeDeviceNoLock(
boolean wipeExtRequested, final int userHandle, String reason, boolean force) {
- // TODO If split user is enabled and the device owner is set in the primary user (rather
- // than system), we should probably trigger factory reset. Current code just remove
- // that user (but still clears FRP...)
- if (userHandle == UserHandle.USER_SYSTEM) {
- wipeDataLocked(wipeExtRequested, reason, force);
- } else {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- IActivityManager am = mInjector.getIActivityManager();
- if (am.getCurrentUser().id == userHandle) {
- am.switchUser(UserHandle.USER_SYSTEM);
- }
+ wtfIfInLock();
- boolean userRemoved = force
- ? mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle)
- : mUserManager.removeUser(userHandle);
- if (!userRemoved) {
- Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
- } else if (isManagedProfile(userHandle)) {
- sendWipeProfileNotification();
- }
- } catch (RemoteException re) {
- // Shouldn't happen
+ long ident = mInjector.binderClearCallingIdentity();
+ try {
+ // TODO If split user is enabled and the device owner is set in the primary user (rather
+ // than system), we should probably trigger factory reset. Current code just remove
+ // that user (but still clears FRP...)
+ if (userHandle == UserHandle.USER_SYSTEM) {
+ wipeDataNoLock(wipeExtRequested, reason, force);
+ } else {
+ try {
+ IActivityManager am = mInjector.getIActivityManager();
+ if (am.getCurrentUser().id == userHandle) {
+ am.switchUser(UserHandle.USER_SYSTEM);
}
+
+ boolean userRemoved = force
+ ? mUserManagerInternal.removeUserEvenWhenDisallowed(userHandle)
+ : mUserManager.removeUser(userHandle);
+ if (!userRemoved) {
+ Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
+ } else if (isManagedProfile(userHandle)) {
+ sendWipeProfileNotification();
+ }
+ } catch (RemoteException re) {
+ // Shouldn't happen
}
- });
+ }
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
}
}
@@ -5047,8 +5052,7 @@
}
if (wipeData) {
// Call without holding lock.
- wipeDeviceOrUserLocked(false, identifier,
- "reportFailedPasswordAttempt()", false);
+ wipeDeviceNoLock(false, identifier, "reportFailedPasswordAttempt()", false);
}
} finally {
mInjector.binderRestoreCallingIdentity(ident);
@@ -6550,6 +6554,15 @@
}
/**
+ * Calls wtfStack() if called with the DPMS lock held.
+ */
+ private void wtfIfInLock() {
+ if (Thread.holdsLock(this)) {
+ Slog.wtfStack(LOG_TAG, "Shouldn't be called with DPMS lock held");
+ }
+ }
+
+ /**
* The profile owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
* permission.
* The profile owner can only be set before the user setup phase has completed,
@@ -9870,10 +9883,7 @@
if (!isAdb()) {
return true;
}
- if (Thread.holdsLock(this)) {
- Slog.wtf(LOG_TAG, "hasIncompatibleAccountsNoLock() called with the DPMS lock held.");
- return true;
- }
+ wtfIfInLock();
final long token = mInjector.binderClearCallingIdentity();
try {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5b46f51..f4b4230 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -165,6 +165,8 @@
"com.android.server.LockSettingsService$Lifecycle";
private static final String STORAGE_MANAGER_SERVICE_CLASS =
"com.android.server.StorageManagerService$Lifecycle";
+ private static final String STORAGE_STATS_SERVICE_CLASS =
+ "com.android.server.usage.StorageStatsService$Lifecycle";
private static final String SEARCH_MANAGER_SERVICE_CLASS =
"com.android.server.search.SearchManagerService$Lifecycle";
private static final String THERMAL_OBSERVER_CLASS =
@@ -795,7 +797,7 @@
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
if (!disableStorage &&
- !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+ !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
traceBeginAndSlog("StartStorageManagerService");
try {
/*
@@ -806,7 +808,15 @@
storageManager = IStorageManager.Stub.asInterface(
ServiceManager.getService("mount"));
} catch (Throwable e) {
- reportWtf("starting StorageManager Service", e);
+ reportWtf("starting StorageManagerService", e);
+ }
+ traceEnd();
+
+ traceBeginAndSlog("StartStorageStatsService");
+ try {
+ mSystemServiceManager.startService(STORAGE_STATS_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting StorageStatsService", e);
}
traceEnd();
}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index e1c0166..ef61ec2 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -126,7 +126,7 @@
NotificationChannel channel = new NotificationChannel("id", "name",
NotificationManager.IMPORTANCE_HIGH);
- channel.setAllowed(false);
+ channel.setImportance(NotificationManager.IMPORTANCE_NONE);
NotificationRecord r = generateNotificationRecord(channel);
NotificationManagerService.EnqueueNotificationRunnable enqueue =
mNotificationManagerService.new EnqueueNotificationRunnable(UserHandle.USER_SYSTEM,
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 5696a72..f8061f6 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -488,25 +488,6 @@
}
@Test
- public void testUpdate_userLockedAllowed() throws Exception {
- final NotificationChannel channel =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
- channel.setAllowed(true);
- channel.lockFields(NotificationChannel.USER_LOCKED_ALLOWED);
-
- mHelper.createNotificationChannel(pkg, uid, channel, false);
-
- final NotificationChannel channel2 =
- new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
- channel2.setAllowed(false);
-
- mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2);
-
- // no fields should be changed
- assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId()));
- }
-
- @Test
public void testUpdate_userLockedBadge() throws Exception {
final NotificationChannel channel =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_LOW);
@@ -567,7 +548,6 @@
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.setShowBadge(true);
- channel.setAllowed(false);
int lockMask = 0;
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -583,7 +563,7 @@
assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
assertFalse(savedChannel.canBypassDnd());
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
- assertFalse(savedChannel.canShowBadge());
+ assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
}
@Test
@@ -595,7 +575,6 @@
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
channel.setShowBadge(true);
- channel.setAllowed(false);
int lockMask = 0;
for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
@@ -611,6 +590,6 @@
assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
assertFalse(savedChannel.canBypassDnd());
assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
- assertFalse(savedChannel.canShowBadge());
+ assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
}
}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index ae5da78..f934d34 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -50,10 +50,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-# Code coverage puts us over the dex limit, so enable multi-dex for coverage-enabled builds
-ifeq (true,$(EMMA_INSTRUMENT))
LOCAL_JACK_FLAGS := --multi-dex native
-endif # EMMA_INSTRUMENT_STATIC
LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 9a9f81e..9c5c672 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -147,11 +147,11 @@
@Test
public void testRequestScores_noPermission() throws Exception {
doThrow(new SecurityException()).when(mContext)
- .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+ .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
anyString());
try {
mNetworkScoreService.requestScores(null);
- fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+ fail("REQUEST_NETWORK_SCORES not enforced.");
} catch (SecurityException e) {
// expected
}
@@ -184,11 +184,11 @@
@Test
public void testRequestRecommendation_noPermission() throws Exception {
doThrow(new SecurityException()).when(mContext)
- .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+ .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
anyString());
try {
mNetworkScoreService.requestRecommendation(mRecommendationRequest);
- fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+ fail("REQUEST_NETWORK_SCORES not enforced.");
} catch (SecurityException e) {
// expected
}
@@ -324,7 +324,7 @@
@Test
public void testClearScores_notActiveScorer_noBroadcastNetworkPermission() {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
- when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_DENIED);
try {
mNetworkScoreService.clearScores();
@@ -337,7 +337,7 @@
@Test
public void testClearScores_activeScorer_noBroadcastNetworkPermission() {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(true);
- when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_DENIED);
mNetworkScoreService.clearScores();
@@ -358,7 +358,7 @@
public void testClearScores_notActiveScorer_hasBroadcastNetworkPermission()
throws RemoteException {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
- when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_GRANTED);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
@@ -384,7 +384,7 @@
@Test
public void testDisableScoring_notActiveScorer_noBroadcastNetworkPermission() {
when(mNetworkScorerAppManager.isCallerActiveScorer(anyInt())).thenReturn(false);
- when(mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED))
+ when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_DENIED);
try {
@@ -398,7 +398,7 @@
@Test
public void testRegisterNetworkScoreCache_noBroadcastNetworkPermission() {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
- eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+ eq(permission.REQUEST_NETWORK_SCORES), anyString());
try {
mNetworkScoreService.registerNetworkScoreCache(
@@ -412,7 +412,7 @@
@Test
public void testUnregisterNetworkScoreCache_noBroadcastNetworkPermission() {
doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
- eq(permission.BROADCAST_NETWORK_PRIVILEGED), anyString());
+ eq(permission.REQUEST_NETWORK_SCORES), anyString());
try {
mNetworkScoreService.unregisterNetworkScoreCache(
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index dcaab76..10ca902 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -404,7 +404,6 @@
@Override
boolean injectIsActivityEnabledAndExported(ComponentName activity, @UserIdInt int userId) {
- assertNotNull(activity);
return mEnabledActivityChecker.test(activity, userId);
}
@@ -450,11 +449,6 @@
// During tests, WTF is fatal.
fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th));
}
-
- @Override
- void verifyError() {
- fail("Verify error");
- }
}
/** ShortcutManager with injection override methods. */
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
index d165b8b..6c6eb7e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -69,7 +69,7 @@
class TestParallelPackageParser extends ParallelPackageParser {
TestParallelPackageParser() {
- super(null, false, null);
+ super(null, false, null, null);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 97bcaf0..74c1ca5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1292,43 +1292,7 @@
/* activity =*/ null, /* flags */ 0), getCallingUser());
});
- // Make sure floating shortcuts don't match with an activity.
- // At this point, s1 is dynamic and pinned, so it still has a target activity.
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- assertWith(mLauncherApps.getShortcuts(buildQuery(
- /* time =*/ 0,
- CALLING_PACKAGE_2,
- /* activity =*/ new ComponentName(CALLING_PACKAGE_2,
- ShortcutActivity2.class.getName()),
- ShortcutQuery.FLAG_GET_PINNED),
- getCallingUser()))
- .haveIds("s3")
- .areAllPinned()
- .areAllDynamic()
- .areAllWithActivity(new ComponentName(CALLING_PACKAGE_2,
- ShortcutActivity2.class.getName()));
- });
-
- // Now remove as a dynamic, making it floating.
- runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
- mManager.removeDynamicShortcuts(list("s3"));
- assertWith(mManager.getPinnedShortcuts())
- .selectFloating()
- .areAllWithNoActivity();
- });
-
- runWithCaller(LAUNCHER_1, USER_0, () -> {
- // This shouldn't match now.
- assertWith(mLauncherApps.getShortcuts(buildQuery(
- /* time =*/ 0,
- CALLING_PACKAGE_2,
- /* activity =*/ new ComponentName(CALLING_PACKAGE_2,
- ShortcutActivity2.class.getName()),
- ShortcutQuery.FLAG_GET_PINNED),
- getCallingUser()))
- .isEmpty();
- });
-
+ // TODO More tests: pinned but dynamic.
}
public void testGetShortcuts_shortcutKinds() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 7486858..d25923c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -1052,7 +1052,7 @@
assertEquals(CALLING_PACKAGE_1, si.getPackage());
assertEquals("id", si.getId());
- assertNull(si.getActivity()); // It's now floating, so no target activity.
+ assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
assertEquals(null, si.getIcon());
assertEquals("title", si.getTitle());
assertEquals("text", si.getText());
@@ -1116,7 +1116,7 @@
assertEquals(CALLING_PACKAGE_1, si.getPackage());
assertEquals("id", si.getId());
- assertNull(si.getActivity()); // It's now floating, so no target activity.
+ assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
assertEquals(null, si.getIcon());
assertEquals(10, si.getTitleResId());
assertEquals("r10", si.getTitleResName());
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
new file mode 100644
index 0000000..8a962e7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import org.junit.Test;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link WindowContainerController}.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class AppWindowContainerControllerTests extends WindowTestsBase {
+// TODO Add tests once TaskWindowContainerController is created.
+ @Test
+ public void dummyTest() throws Exception {}
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index eca2500..1c69033 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -56,4 +56,20 @@
assertEquals(stack.mChildren.get(0), task2);
assertEquals(stack.mChildren.get(1), task1);
}
+
+ @Test
+ public void testStackRemoveImmediately() throws Exception {
+ final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
+ final Task task = createTaskInStack(stack, 0 /* userId */);
+ assertEquals(stack, task.mStack);
+ assertTrue(sDisplayContent.mDimLayerController.hasDimLayerUser(stack));
+ assertTrue(sDisplayContent.mDimLayerController.hasDimLayerUser(task));
+
+ // Remove stack and check if its child is also removed.
+ stack.removeImmediately();
+ assertNull(stack.getDisplayContent());
+ assertNull(task.mStack);
+ assertFalse(sDisplayContent.mDimLayerController.hasDimLayerUser(stack));
+ assertFalse(sDisplayContent.mDimLayerController.hasDimLayerUser(task));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 07f65bd..6129198 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -19,7 +19,6 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
import android.app.ActivityManagerInternal;
import android.content.Context;
@@ -27,7 +26,6 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.IApplicationToken;
import com.android.server.LocalServices;
@@ -114,7 +112,6 @@
}
private AppWindowToken createAppToken() {
- return new AppWindowToken(mWm, mock(IApplicationToken.class), false,
- mWm.getDefaultDisplayContentLocked());
+ return new AppWindowToken(mWm, null, false, mWm.getDefaultDisplayContentLocked());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
new file mode 100644
index 0000000..956735c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link WindowContainerController}.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests
+ */
+@SmallTest
+@Presubmit
+@org.junit.runner.RunWith(AndroidJUnit4.class)
+public class WindowContainerControllerTests extends WindowTestsBase {
+
+ @Test
+ public void testCreation() throws Exception {
+ final WindowContainerController controller = new WindowContainerController(null, sWm);
+ final WindowContainer container = new WindowContainer();
+
+ container.setController(controller);
+ assertEquals(controller, container.getController());
+ assertEquals(controller.mContainer, container);
+ }
+
+ @Test
+ public void testSetContainer() throws Exception {
+ final WindowContainerController controller = new WindowContainerController(null, sWm);
+ final WindowContainer container = new WindowContainer();
+
+ controller.setContainer(container);
+ assertEquals(controller.mContainer, container);
+
+ // Assert we can't change the container to another one once set
+ boolean gotException = false;
+ try {
+ controller.setContainer(new WindowContainer());
+ } catch (IllegalArgumentException e) {
+ gotException = true;
+ }
+ assertTrue(gotException);
+
+ // Assert that we can set the container to null.
+ controller.setContainer(null);
+ assertNull(controller.mContainer);
+ }
+
+ @Test
+ public void testRemoveContainer() throws Exception {
+ final WindowContainerController controller = new WindowContainerController(null, sWm);
+ final WindowContainer container = new WindowContainer();
+
+ controller.setContainer(container);
+ assertEquals(controller.mContainer, container);
+
+ controller.removeContainer();
+ assertNull(controller.mContainer);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index 7277ba4..b57329c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -52,7 +52,7 @@
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class WindowContainerTests {
+public class WindowContainerTests extends WindowTestsBase {
@Test
public void testCreation() throws Exception {
@@ -192,6 +192,44 @@
}
@Test
+ public void testRemoveImmediately_WithController() throws Exception {
+ final WindowContainer container = new WindowContainer();
+ final WindowContainerController controller = new WindowContainerController(null, sWm);
+
+ container.setController(controller);
+ assertEquals(controller, container.getController());
+ assertEquals(container, controller.mContainer);
+
+ container.removeImmediately();
+ assertNull(container.getController());
+ assertNull(controller.mContainer);
+ }
+
+ @Test
+ public void testSetController() throws Exception {
+ final WindowContainerController controller = new WindowContainerController(null, sWm);
+ final WindowContainer container = new WindowContainer();
+
+ container.setController(controller);
+ assertEquals(controller, container.getController());
+ assertEquals(container, controller.mContainer);
+
+ // Assert we can't change the controller to another one once set
+ boolean gotException = false;
+ try {
+ container.setController(new WindowContainerController(null, sWm));
+ } catch (IllegalArgumentException e) {
+ gotException = true;
+ }
+ assertTrue(gotException);
+
+ // Assert that we can set the controller to null.
+ container.setController(null);
+ assertNull(container.getController());
+ assertNull(controller.mContainer);
+ }
+
+ @Test
public void testPositionChildAt() throws Exception {
final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
final TestWindowContainer root = builder.setLayer(0).build();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 3985687..fb3beb3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -44,7 +44,7 @@
/**
* Common base class for window manager unit test classes.
*/
-public class WindowTestsBase {
+class WindowTestsBase {
static WindowManagerService sWm = null;
private final IWindow mIWindow = new TestIWindow();
private final Session mMockSession = mock(Session.class);
@@ -52,17 +52,17 @@
private static int sNextTaskId = 0;
private static boolean sOneTimeSetupDone = false;
- protected static DisplayContent sDisplayContent;
- protected static WindowLayersController sLayersController;
- protected static WindowState sWallpaperWindow;
- protected static WindowState sImeWindow;
- protected static WindowState sImeDialogWindow;
- protected static WindowState sStatusBarWindow;
- protected static WindowState sDockedDividerWindow;
- protected static WindowState sNavBarWindow;
- protected static WindowState sAppWindow;
- protected static WindowState sChildAppWindowAbove;
- protected static WindowState sChildAppWindowBelow;
+ static DisplayContent sDisplayContent;
+ static WindowLayersController sLayersController;
+ static WindowState sWallpaperWindow;
+ static WindowState sImeWindow;
+ static WindowState sImeDialogWindow;
+ static WindowState sStatusBarWindow;
+ static WindowState sDockedDividerWindow;
+ static WindowState sNavBarWindow;
+ static WindowState sAppWindow;
+ static WindowState sChildAppWindowAbove;
+ static WindowState sChildAppWindowBelow;
@Before
public void setUp() throws Exception {
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
new file mode 100644
index 0000000..cb9cb121
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usage;
+
+import android.app.AppOpsManager;
+import android.app.usage.IStorageStatsManager;
+import android.app.usage.StorageStats;
+import android.app.usage.StorageSummary;
+import android.content.Context;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+
+import com.android.server.SystemService;
+import com.android.server.pm.Installer;
+
+public class StorageStatsService extends IStorageStatsManager.Stub {
+ private static final String TAG = "StorageStatsService";
+
+ public static class Lifecycle extends SystemService {
+ private StorageStatsService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mService = new StorageStatsService(getContext());
+ publishBinderService(Context.STORAGE_STATS_SERVICE, mService);
+ }
+ }
+
+ private final Context mContext;
+ private final AppOpsManager mAppOps;
+ private final StorageManager mStorage;
+ private final Installer mInstaller;
+
+ public StorageStatsService(Context context) {
+ mContext = context;
+ mAppOps = context.getSystemService(AppOpsManager.class);
+ mStorage = context.getSystemService(StorageManager.class);
+ mInstaller = new Installer(context);
+ }
+
+ private void enforcePermission(int callingUid, String callingPackage) {
+ final int mode = mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
+ callingUid, callingPackage);
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ return;
+ case AppOpsManager.MODE_DEFAULT:
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
+ default:
+ throw new SecurityException("Blocked by mode " + mode);
+ }
+ }
+
+ @Override
+ public StorageStats queryStats(String volumeUuid, int uid, String callingPackage) {
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+ if (UserHandle.getUserId(uid) != UserHandle.getCallingUserId()) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, TAG);
+ }
+
+ // TODO: call installd to collect quota stats
+ return null;
+ }
+
+ @Override
+ public StorageSummary querySummary(String volumeUuid, String callingPackage) {
+ enforcePermission(Binder.getCallingUid(), callingPackage);
+
+ // TODO: call installd to collect quota stats
+ return null;
+ }
+}
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index 29154aa..0681b61 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -76,6 +76,14 @@
</intent-filter>
</activity>
<activity
+ android:name=".ResizeHWLayerActivity"
+ android:label="General/Resize HW Layer" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name=".TrivialAnimationActivity"
android:label="General/Trivial Animation" >
<intent-filter>
diff --git a/tests/UiBench/src/com/android/test/uibench/ResizeHWLayerActivity.java b/tests/UiBench/src/com/android/test/uibench/ResizeHWLayerActivity.java
new file mode 100644
index 0000000..23a2713
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ResizeHWLayerActivity.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+
+/**
+ * Tests resizing of a View backed by a hardware layer.
+ */
+public class ResizeHWLayerActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ DisplayMetrics metrics = getResources().getDisplayMetrics();
+ int width = metrics.widthPixels;
+ int height = metrics.heightPixels;
+ View child = new View(this);
+ child.setBackgroundColor(Color.BLUE);
+ child.setLayoutParams(new FrameLayout.LayoutParams(width, height));
+ child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ PropertyValuesHolder pvhWidth = PropertyValuesHolder.ofInt("width", width, 1);
+ PropertyValuesHolder pvhHeight = PropertyValuesHolder.ofInt("height", height, 1);
+ final LayoutParams params = child.getLayoutParams();
+ ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(pvhWidth, pvhHeight);
+ animator.setRepeatMode(ValueAnimator.REVERSE);
+ animator.setRepeatCount(ValueAnimator.INFINITE);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ params.width = (Integer)valueAnimator.getAnimatedValue("width");
+ params.height = (Integer)valueAnimator.getAnimatedValue("height");
+ child.requestLayout();
+ }
+ });
+ animator.start();
+ setContentView(child);
+ }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 28a2cb3..4aeae70 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -43,26 +43,6 @@
@SmallTest
public void testMANAGE_APP_TOKENS() {
try {
- mWm.pauseKeyDispatching(null);
- fail("IWindowManager.pauseKeyDispatching did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.resumeKeyDispatching(null);
- fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
mWm.setEventDispatching(true);
fail("IWindowManager.setEventDispatching did not throw SecurityException as"
+ " expected");
@@ -93,26 +73,6 @@
}
try {
- mWm.addAppToken(0, null, 0, 0, false, false, 0, false, false, false, 0, -1);
- fail("IWindowManager.addAppToken did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.addAppToTask(null, 0);
- fail("IWindowManager.setAppGroupId did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
mWm.updateOrientationFromAppTokens(new Configuration(),
null /* freezeThisOneIfNeeded */, DEFAULT_DISPLAY);
fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -124,17 +84,6 @@
}
try {
- mWm.setAppOrientation(null, 0);
- mWm.addWindowToken(null, 0, DEFAULT_DISPLAY);
- fail("IWindowManager.setAppOrientation did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
mWm.setFocusedApp(null, false);
fail("IWindowManager.setFocusedApp did not throw SecurityException as"
+ " expected");
@@ -163,56 +112,6 @@
} catch (RemoteException e) {
fail("Unexpected remote exception");
}
-
- try {
- mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
- fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.setAppVisibility(null, false);
- fail("IWindowManager.setAppVisibility did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.startAppFreezingScreen(null, 0);
- fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.stopAppFreezingScreen(null, false);
- fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- try {
- mWm.removeAppToken(null, DEFAULT_DISPLAY);
- fail("IWindowManager.removeAppToken did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
}
@SmallTest
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 2e34197..0e031e7 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -393,10 +393,14 @@
printf("\n");
}
-static void printUsesImpliedPermission(const String8& name, const String8& reason) {
- printf("uses-implied-permission: name='%s' reason='%s'\n",
- ResTable::normalizeForOutput(name.string()).string(),
- ResTable::normalizeForOutput(reason.string()).string());
+static void printUsesImpliedPermission(const String8& name, const String8& reason,
+ const int32_t maxSdkVersion = -1) {
+ printf("uses-implied-permission: name='%s'",
+ ResTable::normalizeForOutput(name.string()).string());
+ if (maxSdkVersion != -1) {
+ printf(" maxSdkVersion='%d'", maxSdkVersion);
+ }
+ printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.string()).string());
}
Vector<String8> getNfcAidCategories(AssetManager& assets, const String8& xmlPath, bool offHost,
@@ -1027,6 +1031,7 @@
// These two implement the implicit permissions that are granted
// to pre-1.6 applications.
bool hasWriteExternalStoragePermission = false;
+ int32_t writeExternalStoragePermissionMaxSdkVersion = -1;
bool hasReadPhoneStatePermission = false;
// If an app requests write storage, they will also get read storage.
@@ -1538,8 +1543,12 @@
addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
+ const int32_t maxSdkVersion =
+ AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, -1);
+
if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
hasWriteExternalStoragePermission = true;
+ writeExternalStoragePermissionMaxSdkVersion = maxSdkVersion;
} else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
hasReadExternalStoragePermission = true;
} else if (name == "android.permission.READ_PHONE_STATE") {
@@ -1556,7 +1565,7 @@
printUsesPermission(name,
AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
- AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+ maxSdkVersion);
} else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
@@ -2039,9 +2048,11 @@
// do this (regardless of target API version) because we can't have
// an app with write permission but not read permission.
if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
- printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"));
+ printUsesPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
+ false /* optional */, writeExternalStoragePermissionMaxSdkVersion);
printUsesImpliedPermission(String8("android.permission.READ_EXTERNAL_STORAGE"),
- String8("requested WRITE_EXTERNAL_STORAGE"));
+ String8("requested WRITE_EXTERNAL_STORAGE"),
+ writeExternalStoragePermissionMaxSdkVersion);
}
// Pre-JellyBean call log permission compatibility.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 2ae4654..9d9d71f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -62,7 +62,7 @@
public enum BitmapCreateFlags {
- PREMULTIPLIED, MUTABLE
+ NONE, PREMULTIPLIED, MUTABLE
}
// ---- delegate manager ----
@@ -616,6 +616,26 @@
// do nothing as Bitmap_Delegate does not have caches
}
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap) {
+ Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(nativeBitmap);
+ if (srcBmpDelegate == null) {
+ return null;
+ }
+
+ BufferedImage srcImage = srcBmpDelegate.getImage();
+
+ // create the image
+ BufferedImage image = new BufferedImage(srcImage.getColorModel(), srcImage.copyData(null),
+ srcImage.isAlphaPremultiplied(), null);
+
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, srcBmpDelegate.getConfig());
+
+ return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.NONE),
+ Bitmap.getDefaultDensity());
+ }
+
// ---- Private delegate/helper methods ----
private Bitmap_Delegate(BufferedImage image, Config config) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
deleted file mode 100644
index 10cc572..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.LayerRasterizer
- *
- * Through the layoutlib_create tool, the original native methods of LayerRasterizer have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original LayerRasterizer class.
- *
- * Because this extends {@link Rasterizer_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link Rasterizer_Delegate}.
- *
- * @see Rasterizer_Delegate
- *
- */
-public class LayerRasterizer_Delegate extends Rasterizer_Delegate {
-
- // ---- delegate data ----
-
- // ---- Public Helper methods ----
-
- @Override
- public boolean isSupported() {
- return false;
- }
-
- @Override
- public String getSupportMessage() {
- return "Layer Rasterizers are not supported.";
- }
-
- // ---- native methods ----
-
- @LayoutlibDelegate
- /*package*/ static long nativeConstructor() {
- LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
- return sManager.addNewDelegate(newDelegate);
- }
-
- @LayoutlibDelegate
- /*package*/ static void nativeAddLayer(long native_layer, long native_paint, float dx, float dy) {
-
- }
-
- // ---- Private delegate/helper methods ----
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index e68d8b3..9b8fa99 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -99,7 +99,6 @@
private Shader_Delegate mShader;
private PathEffect_Delegate mPathEffect;
private MaskFilter_Delegate mMaskFilter;
- private Rasterizer_Delegate mRasterizer;
private Locale mLocale = Locale.getDefault();
@@ -248,15 +247,6 @@
return mMaskFilter;
}
- /**
- * Returns the {@link Rasterizer} delegate or null if none have been set
- *
- * @return the delegate or null.
- */
- public Rasterizer_Delegate getRasterizer() {
- return mRasterizer;
- }
-
// ---- native methods ----
@LayoutlibDelegate
@@ -898,25 +888,6 @@
}
@LayoutlibDelegate
- /*package*/ static long nSetRasterizer(long native_object, long rasterizer) {
- // get the delegate from the native int.
- Paint_Delegate delegate = sManager.getDelegate(native_object);
- if (delegate == null) {
- return rasterizer;
- }
-
- delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
-
- // since none of those are supported, display a fidelity warning right away
- if (delegate.mRasterizer != null && !delegate.mRasterizer.isSupported()) {
- Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
- delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
- }
-
- return rasterizer;
- }
-
- @LayoutlibDelegate
/*package*/ static int nGetTextAlign(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -1235,7 +1206,6 @@
mShader = paint.mShader;
mPathEffect = paint.mPathEffect;
mMaskFilter = paint.mMaskFilter;
- mRasterizer = paint.mRasterizer;
mHintingMode = paint.mHintingMode;
if (needsFontUpdate) {
@@ -1262,7 +1232,6 @@
mShader = null;
mPathEffect = null;
mMaskFilter = null;
- mRasterizer = null;
updateFontObject();
mHintingMode = Paint.HINTING_ON;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
index fc9b4f7..7f707c9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathMeasure_Delegate.java
@@ -56,8 +56,8 @@
if (native_path != 0) {
if (forceClosed) {
// Copy the path and call close
- native_path = Path_Delegate.init2(native_path);
- Path_Delegate.native_close(native_path);
+ native_path = Path_Delegate.nInit(native_path);
+ Path_Delegate.nClose(native_path);
}
Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
@@ -108,8 +108,8 @@
if (native_path != 0) {
if (forceClosed) {
// Copy the path and call close
- native_path = Path_Delegate.init2(native_path);
- Path_Delegate.native_close(native_path);
+ native_path = Path_Delegate.nInit(native_path);
+ Path_Delegate.nClose(native_path);
}
Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
@@ -184,28 +184,28 @@
if (type != PathIterator.SEG_MOVETO) {
float[] lastPoint = new float[2];
iterator.getCurrentSegmentEnd(lastPoint);
- Path_Delegate.native_moveTo(native_dst_path, lastPoint[0], lastPoint[1]);
+ Path_Delegate.nMoveTo(native_dst_path, lastPoint[0], lastPoint[1]);
}
}
isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0;
switch (type) {
case PathIterator.SEG_MOVETO:
- Path_Delegate.native_moveTo(native_dst_path, points[0], points[1]);
+ Path_Delegate.nMoveTo(native_dst_path, points[0], points[1]);
break;
case PathIterator.SEG_LINETO:
- Path_Delegate.native_lineTo(native_dst_path, points[0], points[1]);
+ Path_Delegate.nLineTo(native_dst_path, points[0], points[1]);
break;
case PathIterator.SEG_CLOSE:
- Path_Delegate.native_close(native_dst_path);
+ Path_Delegate.nClose(native_dst_path);
break;
case PathIterator.SEG_CUBICTO:
- Path_Delegate.native_cubicTo(native_dst_path, points[0], points[1],
+ Path_Delegate.nCubicTo(native_dst_path, points[0], points[1],
points[2], points[3],
points[4], points[5]);
break;
case PathIterator.SEG_QUADTO:
- Path_Delegate.native_quadTo(native_dst_path, points[0], points[1],
+ Path_Delegate.nQuadTo(native_dst_path, points[0], points[1],
points[2],
points[3]);
break;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 219c487..579fce0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -98,7 +98,7 @@
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static long init1() {
+ /*package*/ static long nInit() {
// create the delegate
Path_Delegate newDelegate = new Path_Delegate();
@@ -106,7 +106,7 @@
}
@LayoutlibDelegate
- /*package*/ static long init2(long nPath) {
+ /*package*/ static long nInit(long nPath) {
// create the delegate
Path_Delegate newDelegate = new Path_Delegate();
@@ -120,7 +120,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_reset(long nPath) {
+ /*package*/ static void nReset(long nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -130,20 +130,20 @@
}
@LayoutlibDelegate
- /*package*/ static void native_rewind(long nPath) {
+ /*package*/ static void nRewind(long nPath) {
// call out to reset since there's nothing to optimize in
// terms of data structs.
- native_reset(nPath);
+ nReset(nPath);
}
@LayoutlibDelegate
- /*package*/ static void native_set(long native_dst, long native_src) {
+ /*package*/ static void nSet(long native_dst, long nSrc) {
Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
if (pathDstDelegate == null) {
return;
}
- Path_Delegate pathSrcDelegate = sManager.getDelegate(native_src);
+ Path_Delegate pathSrcDelegate = sManager.getDelegate(nSrc);
if (pathSrcDelegate == null) {
return;
}
@@ -152,14 +152,14 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_isConvex(long nPath) {
+ /*package*/ static boolean nIsConvex(long nPath) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Path.isConvex is not supported.", null, null);
return true;
}
@LayoutlibDelegate
- /*package*/ static int native_getFillType(long nPath) {
+ /*package*/ static int nGetFillType(long nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return 0;
@@ -169,7 +169,7 @@
}
@LayoutlibDelegate
- public static void native_setFillType(long nPath, int ft) {
+ public static void nSetFillType(long nPath, int ft) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -179,14 +179,14 @@
}
@LayoutlibDelegate
- /*package*/ static boolean native_isEmpty(long nPath) {
+ /*package*/ static boolean nIsEmpty(long nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
return pathDelegate == null || pathDelegate.isEmpty();
}
@LayoutlibDelegate
- /*package*/ static boolean native_isRect(long nPath, RectF rect) {
+ /*package*/ static boolean nIsRect(long nPath, RectF rect) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return false;
@@ -206,7 +206,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_computeBounds(long nPath, RectF bounds) {
+ /*package*/ static void nComputeBounds(long nPath, RectF bounds) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -216,13 +216,13 @@
}
@LayoutlibDelegate
- /*package*/ static void native_incReserve(long nPath, int extraPtCount) {
+ /*package*/ static void nIncReserve(long nPath, int extraPtCount) {
// since we use a java2D path, there's no way to pre-allocate new points,
// so we do nothing.
}
@LayoutlibDelegate
- /*package*/ static void native_moveTo(long nPath, float x, float y) {
+ /*package*/ static void nMoveTo(long nPath, float x, float y) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -232,7 +232,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_rMoveTo(long nPath, float dx, float dy) {
+ /*package*/ static void nRMoveTo(long nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -242,7 +242,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_lineTo(long nPath, float x, float y) {
+ /*package*/ static void nLineTo(long nPath, float x, float y) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -252,7 +252,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_rLineTo(long nPath, float dx, float dy) {
+ /*package*/ static void nRLineTo(long nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -262,7 +262,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_quadTo(long nPath, float x1, float y1, float x2, float y2) {
+ /*package*/ static void nQuadTo(long nPath, float x1, float y1, float x2, float y2) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -272,7 +272,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_rQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2) {
+ /*package*/ static void nRQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -282,7 +282,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_cubicTo(long nPath, float x1, float y1,
+ /*package*/ static void nCubicTo(long nPath, float x1, float y1,
float x2, float y2, float x3, float y3) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -293,7 +293,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_rCubicTo(long nPath, float x1, float y1,
+ /*package*/ static void nRCubicTo(long nPath, float x1, float y1,
float x2, float y2, float x3, float y3) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -304,7 +304,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_arcTo(long nPath, float left, float top, float right,
+ /*package*/ static void nArcTo(long nPath, float left, float top, float right,
float bottom,
float startAngle, float sweepAngle, boolean forceMoveTo) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -316,7 +316,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_close(long nPath) {
+ /*package*/ static void nClose(long nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -326,7 +326,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addRect(long nPath,
+ /*package*/ static void nAddRect(long nPath,
float left, float top, float right, float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -337,7 +337,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addOval(long nPath, float left, float top, float right,
+ /*package*/ static void nAddOval(long nPath, float left, float top, float right,
float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -349,7 +349,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addCircle(long nPath, float x, float y, float radius, int dir) {
+ /*package*/ static void nAddCircle(long nPath, float x, float y, float radius, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -361,7 +361,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addArc(long nPath, float left, float top, float right,
+ /*package*/ static void nAddArc(long nPath, float left, float top, float right,
float bottom, float startAngle, float sweepAngle) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -375,7 +375,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+ /*package*/ static void nAddRoundRect(long nPath, float left, float top, float right,
float bottom, float rx, float ry, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -388,7 +388,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addRoundRect(long nPath, float left, float top, float right,
+ /*package*/ static void nAddRoundRect(long nPath, float left, float top, float right,
float bottom, float[] radii, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -405,17 +405,17 @@
}
@LayoutlibDelegate
- /*package*/ static void native_addPath(long nPath, long src, float dx, float dy) {
+ /*package*/ static void nAddPath(long nPath, long src, float dx, float dy) {
addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
}
@LayoutlibDelegate
- /*package*/ static void native_addPath(long nPath, long src) {
+ /*package*/ static void nAddPath(long nPath, long src) {
addPath(nPath, src, null /*transform*/);
}
@LayoutlibDelegate
- /*package*/ static void native_addPath(long nPath, long src, long matrix) {
+ /*package*/ static void nAddPath(long nPath, long src, long matrix) {
Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
if (matrixDelegate == null) {
return;
@@ -425,7 +425,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_offset(long nPath, float dx, float dy) {
+ /*package*/ static void nOffset(long nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -435,7 +435,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_setLastPoint(long nPath, float dx, float dy) {
+ /*package*/ static void nSetLastPoint(long nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return;
@@ -446,7 +446,7 @@
}
@LayoutlibDelegate
- /*package*/ static void native_transform(long nPath, long matrix,
+ /*package*/ static void nTransform(long nPath, long matrix,
long dst_path) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -465,23 +465,23 @@
}
@LayoutlibDelegate
- /*package*/ static void native_transform(long nPath, long matrix) {
- native_transform(nPath, matrix, 0);
+ /*package*/ static void nTransform(long nPath, long matrix) {
+ nTransform(nPath, matrix, 0);
}
@LayoutlibDelegate
- /*package*/ static boolean native_op(long nPath1, long nPath2, int op, long result) {
+ /*package*/ static boolean nOp(long nPath1, long nPath2, int op, long result) {
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.op() not supported", null);
return false;
}
@LayoutlibDelegate
- /*package*/ static void finalizer(long nPath) {
+ /*package*/ static void nFinalize(long nPath) {
sManager.removeJavaReferenceFor(nPath);
}
@LayoutlibDelegate
- /*package*/ static float[] native_approximate(long nPath, float error) {
+ /*package*/ static float[] nApproximate(long nPath, float error) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return null;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
deleted file mode 100644
index a742840..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.Rasterizer
- *
- * Through the layoutlib_create tool, the original native methods of Rasterizer have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Rasterizer class.
- *
- * This also serve as a base class for all Rasterizer delegate classes.
- *
- * @see DelegateManager
- *
- */
-public abstract class Rasterizer_Delegate {
-
- // ---- delegate manager ----
- protected static final DelegateManager<Rasterizer_Delegate> sManager =
- new DelegateManager<Rasterizer_Delegate>(Rasterizer_Delegate.class);
-
- // ---- delegate helper data ----
-
- // ---- delegate data ----
-
- // ---- Public Helper methods ----
-
- public static Rasterizer_Delegate getDelegate(long nativeShader) {
- return sManager.getDelegate(nativeShader);
- }
-
- public abstract boolean isSupported();
- public abstract String getSupportMessage();
-
- // ---- native methods ----
-
- @LayoutlibDelegate
- /*package*/ static void finalizer(long native_instance) {
- sManager.removeJavaReferenceFor(native_instance);
- }
-
- // ---- Private delegate/helper methods ----
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
index cee679a..430607a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
@@ -1197,7 +1197,7 @@
assert fillPaintDelegate != null;
fillPaintDelegate.setColorFilter(filterPtr);
fillPaintDelegate.setShader(fullPath.mFillGradient);
- Path_Delegate.native_setFillType(mRenderPath.mNativePath, fullPath.mFillType);
+ Path_Delegate.nSetFillType(mRenderPath.mNativePath, fullPath.mFillType);
BaseCanvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
.getNativeInstance());
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4b9815d..71c1117 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -77,14 +77,6 @@
// ---- unused implementation of IWindowManager ----
@Override
- public void addAppToken(int addPos, IApplicationToken token, int taskId,
- int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int configChanges,
- boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
- int targetSdkVersion, int rotationAnimationHint) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
public void addWindowToken(IBinder arg0, int arg1, int arg2) throws RemoteException {
// TODO Auto-generated method stub
@@ -159,12 +151,6 @@
}
@Override
- public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- @Override
public int getPendingAppTransition() throws RemoteException {
// TODO Auto-generated method stub
return 0;
@@ -258,12 +244,6 @@
}
@Override
- public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
@@ -276,24 +256,12 @@
}
@Override
- public void removeAppToken(IBinder arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
public void removeWindowToken(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
@Override
- public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
public boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver)
throws RemoteException {
// TODO Auto-generated method stub
@@ -301,13 +269,6 @@
}
@Override
- public Bitmap screenshotApplications(IBinder appToken, int displayId, int maxWidth,
- int maxHeight, float frameScale) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
public void setAnimationScale(int arg0, float arg1) throws RemoteException {
// TODO Auto-generated method stub
@@ -325,41 +286,6 @@
}
@Override
- public void addAppToTask(IBinder arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
- public boolean setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
- CharSequence arg4, int arg5, int arg6, int arg7, int arg8, IBinder arg9, boolean arg10)
- throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface)
- throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void notifyAppStopped(IBinder token) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
public void setEventDispatching(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
@@ -443,11 +369,6 @@
}
@Override
- public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
public boolean startViewServer(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
@@ -469,11 +390,6 @@
}
@Override
- public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
public boolean stopViewServer() throws RemoteException {
// TODO Auto-generated method stub
return false;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index a23bad6..92fd75c 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -263,7 +263,6 @@
"android.graphics.DrawFilter",
"android.graphics.EmbossMaskFilter",
"android.graphics.FontFamily",
- "android.graphics.LayerRasterizer",
"android.graphics.LightingColorFilter",
"android.graphics.LinearGradient",
"android.graphics.MaskFilter",
@@ -277,7 +276,6 @@
"android.graphics.PathMeasure",
"android.graphics.PorterDuffColorFilter",
"android.graphics.RadialGradient",
- "android.graphics.Rasterizer",
"android.graphics.Region",
"android.graphics.Shader",
"android.graphics.SumPathEffect",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 9e897bf..18c1245 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -59,7 +59,7 @@
int addOrUpdateNetwork(in WifiConfiguration config);
- boolean addPasspointConfiguration(in PasspointConfiguration config);
+ boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config);
boolean removePasspointConfiguration(in String fqdn);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3b7f721..958279b 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -608,6 +608,7 @@
* if there has been a report of it having no internet access, and, it never have had
* internet access in the past.
*/
+ @SystemApi
public boolean hasNoInternetAccess() {
return numNoInternetAccessReports > 0 && !validatedInternetAccess;
}
@@ -621,6 +622,17 @@
public boolean noInternetAccessExpected;
/**
+ * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
+ * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
+ * this configuration and selects "don't ask again".
+ * @hide
+ */
+ @SystemApi
+ public boolean isNoInternetAccessExpected() {
+ return noInternetAccessExpected;
+ }
+
+ /**
* @hide
* Last time the system was connected to this configuration.
*/
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 674c161..88820cd 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -842,31 +842,31 @@
}
/**
- * Add a Passpoint configuration. The configuration provides a credential
+ * Add or update a Passpoint configuration. The configuration provides a credential
* for connecting to Passpoint networks that are operated by the Passpoint
* service provider specified in the configuration.
*
* Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
- * Name). In the case when there is an existing configuration with the same base
- * domain, the new configuration will replace the existing configuration.
+ * Name). In the case when there is an existing configuration with the same
+ * FQDN, the new configuration will replace the existing configuration.
*
* @param config The Passpoint configuration to be added
- * @return true on success or false on failure
+ * @return true on success
* @hide
*/
- public boolean addPasspointConfiguration(PasspointConfiguration config) {
+ public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
try {
- return mService.addPasspointConfiguration(config);
+ return mService.addOrUpdatePasspointConfiguration(config);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Remove a Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
+ * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
*
* @param fqdn The FQDN of the passpoint configuration to be removed
- * @return true on success or false on failure
+ * @return true on success
* @hide
*/
public boolean removePasspointConfiguration(String fqdn) {
@@ -880,7 +880,9 @@
/**
* Return the list of installed Passpoint configurations.
*
- * @return A list of PasspointConfiguration or null
+ * An empty list will be returned when no configurations are installed.
+ *
+ * @return A list of {@link PasspointConfiguration}
* @hide
*/
public List<PasspointConfiguration> getPasspointConfigurations() {
@@ -1763,6 +1765,7 @@
* Interface for callback invocation on an application action
* @hide
*/
+ @SystemApi
public interface ActionListener {
/** The operation succeeded */
public void onSuccess();
@@ -1974,6 +1977,7 @@
*
* @hide
*/
+ @SystemApi
public void connect(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
// Use INVALID_NETWORK_ID for arg1 when passing a config object
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java b/wifi/java/android/net/wifi/aware/AttachCallback.java
similarity index 78%
rename from wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
rename to wifi/java/android/net/wifi/aware/AttachCallback.java
index 1e8dbd9..90216f3 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAttachCallback.java
+++ b/wifi/java/android/net/wifi/aware/AttachCallback.java
@@ -18,16 +18,16 @@
/**
* Base class for Aware attach callbacks. Should be extended by applications and set when calling
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}. These are callbacks
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}. These are callbacks
* applying to the Aware connection as a whole - not to specific publish or subscribe sessions -
- * for that see {@link WifiAwareDiscoverySessionCallback}.
+ * for that see {@link DiscoverySessionCallback}.
*
* @hide PROPOSED_AWARE_API
*/
-public class WifiAwareAttachCallback {
+public class AttachCallback {
/**
* Called when Aware attach operation
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}
* is completed and that we can now start discovery sessions or connections.
*
* @param session The Aware object on which we can execute further Aware operations - e.g.
@@ -39,7 +39,7 @@
/**
* Called when Aware attach operation
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)} failed.
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)} failed.
*/
public void onAttachFailed() {
/* empty */
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl b/wifi/java/android/net/wifi/aware/Characteristics.aidl
similarity index 94%
rename from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
rename to wifi/java/android/net/wifi/aware/Characteristics.aidl
index a35e71d..77305e9 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.aidl
+++ b/wifi/java/android/net/wifi/aware/Characteristics.aidl
@@ -16,4 +16,4 @@
package android.net.wifi.aware;
-parcelable WifiAwareCharacteristics;
+parcelable Characteristics;
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/Characteristics.java
similarity index 83%
rename from wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
rename to wifi/java/android/net/wifi/aware/Characteristics.java
index 092aa34..1c3e390 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/Characteristics.java
@@ -25,7 +25,7 @@
*
* @hide PROPOSED_AWARE_API
*/
-public class WifiAwareCharacteristics implements Parcelable {
+public class Characteristics implements Parcelable {
/** @hide */
public static final String KEY_MAX_SERVICE_NAME_LENGTH = "key_max_service_name_length";
/** @hide */
@@ -37,7 +37,7 @@
private Bundle mCharacteristics = new Bundle();
/** @hide : should not be created by apps */
- public WifiAwareCharacteristics(Bundle characteristics) {
+ public Characteristics(Bundle characteristics) {
mCharacteristics = characteristics;
}
@@ -58,7 +58,7 @@
* message exchange. Restricts the parameters of the
* {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])},
* {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and
- * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
+ * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}
* variants.
*
* @return A positive integer, maximum length of byte array for Aware messaging.
@@ -89,17 +89,17 @@
return 0;
}
- public static final Creator<WifiAwareCharacteristics> CREATOR =
- new Creator<WifiAwareCharacteristics>() {
+ public static final Creator<Characteristics> CREATOR =
+ new Creator<Characteristics>() {
@Override
- public WifiAwareCharacteristics createFromParcel(Parcel in) {
- WifiAwareCharacteristics c = new WifiAwareCharacteristics(in.readBundle());
+ public Characteristics createFromParcel(Parcel in) {
+ Characteristics c = new Characteristics(in.readBundle());
return c;
}
@Override
- public WifiAwareCharacteristics[] newArray(int size) {
- return new WifiAwareCharacteristics[size];
+ public Characteristics[] newArray(int size) {
+ return new Characteristics[size];
}
};
}
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 4b21b15..6a5957b 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -22,7 +22,7 @@
/**
* Defines a request object to configure a Wi-Fi Aware network. Built using
* {@link ConfigRequest.Builder}. Configuration is requested using
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}.
+ * {@link WifiAwareManager#attach(AttachCallback, android.os.Handler)}.
* Note that the actual achieved configuration may be different from the
* requested configuration - since different applications may request different
* configurations.
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
similarity index 79%
rename from wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
rename to wifi/java/android/net/wifi/aware/DiscoverySession.java
index 2812ad4..c89718f 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -29,21 +29,21 @@
/**
* A class representing a single publish or subscribe Aware session. This object
* will not be created directly - only its child classes are available:
- * {@link WifiAwarePublishDiscoverySession} and {@link WifiAwareSubscribeDiscoverySession}. This
+ * {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
* class provides functionality common to both publish and subscribe discovery sessions:
* <ul>
- * <li>Sending messages: {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[])} or
- * {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} methods.
+ * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
+ * {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
* <li>Creating a network-specifier when requesting a Aware connection:
- * {@link #createNetworkSpecifier(WifiAwareManager.PeerHandle, byte[])}.
+ * {@link #createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
* The {@link #destroy()} method must be called to destroy discovery sessions once they are
* no longer needed.
*
* @hide PROPOSED_AWARE_API
*/
-public class WifiAwareDiscoveryBaseSession {
- private static final String TAG = "WifiAwareDiscBaseSsn";
+public class DiscoverySession {
+ private static final String TAG = "DiscoverySession";
private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
@@ -62,7 +62,7 @@
/**
* Return the maximum permitted retry count when sending messages using
- * {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}.
+ * {@link #sendMessage(PeerHandle, int, byte[], int)}.
*
* @return Maximum retry count when sending messages.
*/
@@ -71,7 +71,7 @@
}
/** @hide */
- public WifiAwareDiscoveryBaseSession(WifiAwareManager manager, int clientId, int sessionId) {
+ public DiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
if (VDBG) {
Log.v(TAG, "New discovery session created: manager=" + manager + ", clientId="
+ clientId + ", sessionId=" + sessionId);
@@ -93,7 +93,7 @@
* This operation must be done on a session which is no longer needed. Otherwise system
* resources will continue to be utilized until the application exits. The only
* exception is a session for which we received a termination callback,
- * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}.
+ * {@link DiscoverySessionCallback#onSessionTerminated()}.
*/
public void destroy() {
WifiAwareManager mgr = mMgr.get();
@@ -139,23 +139,23 @@
/**
* Sends a message to the specified destination. Aware messages are transmitted in the context
* of a discovery session - executed subsequent to a publish/subscribe
- * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
* byte[], java.util.List)} event.
* <p>
* Aware messages are not guaranteed delivery. Callbacks on
- * {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
- * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+ * {@link DiscoverySessionCallback} indicate message was transmitted successfully,
+ * {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
* failed (possibly after several retries) -
- * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
+ * {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
* <p>
* The peer will get a callback indicating a message was received using
- * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}.
*
* @param peerHandle The peer's handle for the message. Must be a result of an
- * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
* byte[], java.util.List)} or
- * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])} events.
* @param messageId An arbitrary integer used by the caller to identify the message. The same
* integer ID will be returned in the callbacks indicating message send success or
@@ -167,7 +167,7 @@
* (note: no retransmissions are attempted in other failure cases). A value of 0
* indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
*/
- public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+ public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
@Nullable byte[] message, int retryCount) {
if (mTerminated) {
Log.w(TAG, "sendMessage: called on terminated session");
@@ -186,25 +186,25 @@
/**
* Sends a message to the specified destination. Aware messages are transmitted in the context
* of a discovery session - executed subsequent to a publish/subscribe
- * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
* byte[], java.util.List)} event.
* <p>
* Aware messages are not guaranteed delivery. Callbacks on
- * {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
- * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
+ * {@link DiscoverySessionCallback} indicate message was transmitted successfully,
+ * {@link DiscoverySessionCallback#onMessageSendSucceeded(int)}, or transmission
* failed (possibly after several retries) -
- * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)}.
+ * {@link DiscoverySessionCallback#onMessageSendFailed(int)}.
* <p>
* The peer will get a callback indicating a message was received using
- * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}.
- * Equivalent to {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)}
+ * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
* with a {@code retryCount} of 0.
*
* @param peerHandle The peer's handle for the message. Must be a result of an
- * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
* byte[], java.util.List)} or
- * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])} events.
* @param messageId An arbitrary integer used by the caller to identify the message. The same
* integer ID will be returned in the callbacks indicating message send success or
@@ -212,16 +212,16 @@
* can be arbitrary and non-unique.
* @param message The message to be transmitted.
*/
- public void sendMessage(@NonNull WifiAwareManager.PeerHandle peerHandle, int messageId,
+ public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
@Nullable byte[] message) {
sendMessage(peerHandle, messageId, message, 0);
}
/**
* Start a ranging operation with the specified peers. The peer IDs are obtained from an
- * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
* byte[], java.util.List)} or
- * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])} operation - can
* only range devices which are part of an ongoing discovery session.
*
@@ -265,9 +265,9 @@
* and a Publisher is a RESPONDER.
*
* @param peerHandle The peer's handle obtained through
- * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
* byte[], java.util.List)} or
- * {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
* from only that peer. A RESPONDER may specified a null - indicating that
* it will accept connection requests from any device.
@@ -283,7 +283,7 @@
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
- public String createNetworkSpecifier(@Nullable WifiAwareManager.PeerHandle peerHandle,
+ public String createNetworkSpecifier(@Nullable PeerHandle peerHandle,
@Nullable byte[] token) {
if (mTerminated) {
Log.w(TAG, "createNetworkSpecifier: called on terminated session");
@@ -295,7 +295,7 @@
return null;
}
- int role = this instanceof WifiAwareSubscribeDiscoverySession
+ int role = this instanceof SubscribeDiscoverySession
? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
new file mode 100644
index 0000000..1fe449f
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.aware;
+
+import android.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Base class for Aware session events callbacks. Should be extended by
+ * applications wanting notifications. The callbacks are set when a
+ * publish or subscribe session is created using
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+ * android.os.Handler)} or
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+ * android.os.Handler)}.
+ * <p>
+ * A single callback is set at session creation - it cannot be replaced.
+ *
+ * @hide PROPOSED_AWARE_API
+ */
+public class DiscoverySessionCallback {
+ /**
+ * Called when a publish operation is started successfully in response to a
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+ * android.os.Handler)} operation.
+ *
+ * @param session The {@link PublishDiscoverySession} used to control the
+ * discovery session.
+ */
+ public void onPublishStarted(@NonNull PublishDiscoverySession session) {
+ /* empty */
+ }
+
+ /**
+ * Called when a subscribe operation is started successfully in response to a
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+ * android.os.Handler)} operation.
+ *
+ * @param session The {@link SubscribeDiscoverySession} used to control the
+ * discovery session.
+ */
+ public void onSubscribeStarted(@NonNull SubscribeDiscoverySession session) {
+ /* empty */
+ }
+
+ /**
+ * Called when a publish or subscribe discovery session configuration update request
+ * succeeds. Called in response to
+ * {@link PublishDiscoverySession#updatePublish(PublishConfig)} or
+ * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+ */
+ public void onSessionConfigUpdated() {
+ /* empty */
+ }
+
+ /**
+ * Called when a publish or subscribe discovery session cannot be created:
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
+ * android.os.Handler)} or
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
+ * android.os.Handler)}, or when a configuration update fails:
+ * {@link PublishDiscoverySession#updatePublish(PublishConfig)} or
+ * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+ * <p>
+ * For discovery session updates failure leaves the session running with its previous
+ * configuration - the discovery session is not terminated.
+ */
+ public void onSessionConfigFailed() {
+ /* empty */
+ }
+
+ /**
+ * Called when a discovery session (publish or subscribe) terminates. Termination may be due
+ * to user-request (either directly through {@link DiscoverySession#destroy()} or
+ * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
+ * or {@link SubscribeConfig.Builder#setTtlSec(int)}).
+ */
+ public void onSessionTerminated() {
+ /* empty */
+ }
+
+ /**
+ * Called when a discovery (publish or subscribe) operation results in a
+ * service discovery.
+ *
+ * @param peerHandle An opaque handle to the peer matching our discovery operation.
+ * @param serviceSpecificInfo The service specific information (arbitrary
+ * byte array) provided by the peer as part of its discovery
+ * configuration.
+ * @param matchFilter The filter which resulted in this service discovery.
+ */
+ public void onServiceDiscovered(PeerHandle peerHandle,
+ byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
+ /* empty */
+ }
+
+ /**
+ * Called in response to
+ * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}
+ * when a message is transmitted successfully - i.e. when it was received successfully by the
+ * peer (corresponds to an ACK being received).
+ * <p>
+ * Note that either this callback or
+ * {@link DiscoverySessionCallback#onMessageSendFailed(int)} will be
+ * received - never both.
+ *
+ * @param messageId The arbitrary message ID specified when sending the message.
+ */
+ public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) {
+ /* empty */
+ }
+
+ /**
+ * Called when message transmission fails - when no ACK is received from the peer.
+ * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
+ * the {@link DiscoverySession#sendMessage(PeerHandle, int,
+ * byte[], int)} method) - this event is received after all retries are exhausted.
+ * <p>
+ * Note that either this callback or
+ * {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
+ * - never both.
+ *
+ * @param messageId The arbitrary message ID specified when sending the message.
+ */
+ public void onMessageSendFailed(@SuppressWarnings("unused") int messageId) {
+ /* empty */
+ }
+
+ /**
+ * Called when a message is received from a discovery session peer - in response to the
+ * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
+ * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
+ * int, byte[], int)}.
+ *
+ * @param peerHandle An opaque handle to the peer matching our discovery operation.
+ * @param message A byte array containing the message.
+ */
+ public void onMessageReceived(PeerHandle peerHandle, byte[] message) {
+ /* empty */
+ }
+}
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 9c92807..794c142 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -23,7 +23,7 @@
import android.net.wifi.aware.IWifiAwareEventCallback;
import android.net.wifi.aware.PublishConfig;
import android.net.wifi.aware.SubscribeConfig;
-import android.net.wifi.aware.WifiAwareCharacteristics;
+import android.net.wifi.aware.Characteristics;
import android.net.wifi.RttManager;
/**
@@ -37,7 +37,7 @@
void enableUsage();
void disableUsage();
boolean isUsageEnabled();
- WifiAwareCharacteristics getCharacteristics();
+ Characteristics getCharacteristics();
// client API
void connect(in IBinder binder, in String callingPackage, in IWifiAwareEventCallback callback,
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
similarity index 97%
rename from wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
rename to wifi/java/android/net/wifi/aware/IdentityChangedListener.java
index e8f52cd4..b0f97bd 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareIdentityChangedListener.java
+++ b/wifi/java/android/net/wifi/aware/IdentityChangedListener.java
@@ -28,7 +28,7 @@
*
* @hide PROPOSED_AWARE_API
*/
-public class WifiAwareIdentityChangedListener {
+public class IdentityChangedListener {
/**
* @param mac The MAC address of the Aware discovery interface. The application must have the
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to get the actual MAC address,
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
new file mode 100644
index 0000000..777d9a3
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.aware;
+
+/**
+ * Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}, used
+ * when sending messages e,g, {@link PublishDiscoverySession#sendMessage(PeerHandle, int, byte[])},
+ * or when configuring a network link to a peer, e.g.
+ * {@link PublishDiscoverySession#createNetworkSpecifier(PeerHandle, byte[])}.
+ *
+ * @hide PROPOSED_AWARE_API
+ */
+public class PeerHandle {
+ /** @hide */
+ public PeerHandle(int peerId) {
+ this.peerId = peerId;
+ }
+
+ /** @hide */
+ public int peerId;
+}
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index 3925bd7..1b8ef84 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -33,9 +33,9 @@
/**
* Defines the configuration of a Aware publish session. Built using
* {@link PublishConfig.Builder}. A publish session is created using
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
* android.os.Handler)} or updated using
- * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
+ * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
*
* @hide PROPOSED_AWARE_API
*/
@@ -184,7 +184,7 @@
*
* @hide
*/
- public void assertValid(WifiAwareCharacteristics characteristics)
+ public void assertValid(Characteristics characteristics)
throws IllegalArgumentException {
WifiAwareUtils.validateServiceName(mServiceName);
@@ -322,12 +322,11 @@
* Sets the number of times an unsolicited (configured using
* {@link PublishConfig.Builder#setPublishType(int)}) publish session
* will be broadcast. When the count is reached an event will be
- * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
- * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
- * {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
+ * generated for {@link DiscoverySessionCallback#onSessionTerminated()}
+ * [unless {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+ * Session will be terminated when {@link DiscoverySession#destroy()} is
* called.
*
* @param publishCount Number of publish packets to broadcast.
@@ -348,12 +347,11 @@
* {@link PublishConfig.Builder#setPublishType(int)}) publish session
* will be alive - broadcasting a packet. When the TTL is reached
* an event will be generated for
- * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
- * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE} [unless
+ * {@link DiscoverySessionCallback#onSessionTerminated()} [unless
* {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+ * Session will be terminated when {@link DiscoverySession#destroy()} is
* called.
*
* @param ttlSec Lifetime of a publish session in seconds.
@@ -371,7 +369,7 @@
/**
* Configure whether a publish terminate notification
- * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} is reported
+ * {@link DiscoverySessionCallback#onSessionTerminated()} is reported
* back to the callback.
*
* @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java b/wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
similarity index 70%
rename from wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
index 68786d1..f2355b3 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwarePublishDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/PublishDiscoverySession.java
@@ -21,32 +21,32 @@
/**
* A class representing a Aware publish session. Created when
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback,
* android.os.Handler)} is called and a discovery session is created and returned in
- * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}. See
- * baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}. This
+ * {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)}. See
+ * baseline functionality of all discovery sessions in {@link DiscoverySession}. This
* object allows updating an existing/running publish discovery session using
* {@link #updatePublish(PublishConfig)}.
*
* @hide PROPOSED_AWARE_API
*/
-public class WifiAwarePublishDiscoverySession extends WifiAwareDiscoveryBaseSession {
- private static final String TAG = "WifiAwarePublishDiscSsn";
+public class PublishDiscoverySession extends DiscoverySession {
+ private static final String TAG = "PublishDiscoverySession";
/** @hide */
- public WifiAwarePublishDiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
+ public PublishDiscoverySession(WifiAwareManager manager, int clientId, int sessionId) {
super(manager, clientId, sessionId);
}
/**
* Re-configure the currently active publish session. The
- * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
+ * {@link DiscoverySessionCallback} is not replaced - the same listener used
* at creation is still used. The results of the configuration are returned using
- * {@link WifiAwareDiscoverySessionCallback}:
+ * {@link DiscoverySessionCallback}:
* <ul>
- * <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+ * <li>{@link DiscoverySessionCallback#onSessionConfigUpdated()}: configuration
* update succeeded.
- * <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+ * <li>{@link DiscoverySessionCallback#onSessionConfigFailed()}: configuration
* update failed. The publish discovery session is still running using its previous
* configuration (i.e. update failure does not terminate the session).
* </ul>
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 0fe69a8..a54a4f5 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -33,9 +33,9 @@
/**
* Defines the configuration of a Aware subscribe session. Built using
* {@link SubscribeConfig.Builder}. Subscribe is done using
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
* android.os.Handler)} or
- * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+ * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
*
* @hide PROPOSED_AWARE_API
*/
@@ -212,7 +212,7 @@
*
* @hide
*/
- public void assertValid(WifiAwareCharacteristics characteristics)
+ public void assertValid(Characteristics characteristics)
throws IllegalArgumentException {
WifiAwareUtils.validateServiceName(mServiceName);
@@ -355,11 +355,10 @@
* Sets the number of times an active (
* {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
* will broadcast. When the count is reached an event will be
- * generated for {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)}
- * with {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+ * generated for {@link DiscoverySessionCallback#onSessionTerminated()}.
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+ * Session will be terminated when {@link DiscoverySession#destroy()} is
* called.
*
* @param subscribeCount Number of subscribe packets to broadcast.
@@ -380,11 +379,10 @@
* {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe session
* will be alive - i.e. broadcasting a packet. When the TTL is reached
* an event will be generated for
- * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} with
- * {@link WifiAwareDiscoverySessionCallback#TERMINATE_REASON_DONE}.
+ * {@link DiscoverySessionCallback#onSessionTerminated()}.
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link WifiAwareDiscoveryBaseSession#destroy()} is
+ * Session will be terminated when {@link DiscoverySession#destroy()} is
* called.
*
* @param ttlSec Lifetime of a subscribe session in seconds.
@@ -404,8 +402,8 @@
* Sets the match style of the subscription - how are matches from a
* single match session (corresponding to the same publish action on the
* peer) reported to the host (using the
- * {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
- * byte[], List)}). The options are: only report the first match and ignore the rest
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[],
+ * java.util.List)}). The options are: only report the first match and ignore the rest
* {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
* match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
*
@@ -424,7 +422,7 @@
/**
* Configure whether a subscribe terminate notification
- * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} is reported
+ * {@link DiscoverySessionCallback#onSessionTerminated()} is reported
* back to the callback.
*
* @param enable If true the terminate callback will be called when the
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java b/wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
similarity index 75%
rename from wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
rename to wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
index a0ec809..39db1c7 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSubscribeDiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeDiscoverySession.java
@@ -22,35 +22,35 @@
/**
* A class representing a Aware subscribe session. Created when
* {@link WifiAwareSession#subscribe(SubscribeConfig,
- * WifiAwareDiscoverySessionCallback, android.os.Handler)}
+ * DiscoverySessionCallback, android.os.Handler)}
* is called and a discovery session is created and returned in
- * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(WifiAwareSubscribeDiscoverySession)}.
- * See baseline functionality of all discovery sessions in {@link WifiAwareDiscoveryBaseSession}.
+ * {@link DiscoverySessionCallback#onSubscribeStarted(SubscribeDiscoverySession)}.
+ * See baseline functionality of all discovery sessions in {@link DiscoverySession}.
* This object allows updating an existing/running subscribe discovery session using
* {@link #updateSubscribe(SubscribeConfig)}.
*
* @hide PROPOSED_AWARE_API
*/
-public class WifiAwareSubscribeDiscoverySession extends WifiAwareDiscoveryBaseSession {
- private static final String TAG = "WifiAwareSubsDiscSsn";
+public class SubscribeDiscoverySession extends DiscoverySession {
+ private static final String TAG = "SubscribeDiscSession";
/**
* {@hide}
*/
- public WifiAwareSubscribeDiscoverySession(WifiAwareManager manager, int clientId,
+ public SubscribeDiscoverySession(WifiAwareManager manager, int clientId,
int sessionId) {
super(manager, clientId, sessionId);
}
/**
* Re-configure the currently active subscribe session. The
- * {@link WifiAwareDiscoverySessionCallback} is not replaced - the same listener used
+ * {@link DiscoverySessionCallback} is not replaced - the same listener used
* at creation is still used. The results of the configuration are returned using
- * {@link WifiAwareDiscoverySessionCallback}:
+ * {@link DiscoverySessionCallback}:
* <ul>
- * <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigUpdated()}: configuration
+ * <li>{@link DiscoverySessionCallback#onSessionConfigUpdated()}: configuration
* update succeeded.
- * <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()}: configuration
+ * <li>{@link DiscoverySessionCallback#onSessionConfigFailed()}: configuration
* update failed. The subscribe discovery session is still running using its previous
* configuration (i.e. update failure does not terminate the session).
* </ul>
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
deleted file mode 100644
index fdf0d01..0000000
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.aware;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * Base class for Aware session events callbacks. Should be extended by
- * applications wanting notifications. The callbacks are set when a
- * publish or subscribe session is created using
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)} or
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)}.
- * <p>
- * A single callback is set at session creation - it cannot be replaced.
- *
- * @hide PROPOSED_AWARE_API
- */
-public class WifiAwareDiscoverySessionCallback {
- /** @hide */
- @IntDef({
- TERMINATE_REASON_DONE, TERMINATE_REASON_FAIL })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SessionTerminateCodes {
- }
-
- /**
- * Indicates that publish or subscribe session is done - all the
- * requested operations (per {@link PublishConfig} or
- * {@link SubscribeConfig}) have been executed. Failure reason flag for
- * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} callback.
- */
- public static final int TERMINATE_REASON_DONE = 100;
-
- /**
- * Indicates that publish or subscribe session is terminated due to a
- * failure.
- * Failure reason flag for
- * {@link WifiAwareDiscoverySessionCallback#onSessionTerminated(int)} callback.
- */
- public static final int TERMINATE_REASON_FAIL = 101;
-
- /**
- * Called when a publish operation is started successfully in response to a
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)} operation.
- *
- * @param session The {@link WifiAwarePublishDiscoverySession} used to control the
- * discovery session.
- */
- public void onPublishStarted(@NonNull WifiAwarePublishDiscoverySession session) {
- /* empty */
- }
-
- /**
- * Called when a subscribe operation is started successfully in response to a
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)} operation.
- *
- * @param session The {@link WifiAwareSubscribeDiscoverySession} used to control the
- * discovery session.
- */
- public void onSubscribeStarted(@NonNull WifiAwareSubscribeDiscoverySession session) {
- /* empty */
- }
-
- /**
- * Called when a publish or subscribe discovery session configuration update request
- * succeeds. Called in response to
- * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
- * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
- */
- public void onSessionConfigUpdated() {
- /* empty */
- }
-
- /**
- * Called when a publish or subscribe discovery session cannot be created:
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)} or
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
- * android.os.Handler)}, or when a configuration update fails:
- * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} or
- * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
- * <p>
- * For discovery session updates failure leaves the session running with its previous
- * configuration - the discovery session is not terminated.
- */
- public void onSessionConfigFailed() {
- /* empty */
- }
-
- /**
- * Called when a discovery session (publish or subscribe) terminates. Termination may be due
- * to user-request (either directly through {@link WifiAwareDiscoveryBaseSession#destroy()} or
- * application-specified expiration, e.g. {@link PublishConfig.Builder#setPublishCount(int)}
- * or {@link SubscribeConfig.Builder#setTtlSec(int)}) or due to a failure.
- *
- * @param reason The termination reason using
- * {@code WifiAwareDiscoverySessionCallback.TERMINATE_*} codes.
- */
- public void onSessionTerminated(@SessionTerminateCodes int reason) {
- /* empty */
- }
-
- /**
- * Called when a discovery (publish or subscribe) operation results in a
- * service discovery.
- *
- * @param peerHandle An opaque handle to the peer matching our discovery operation.
- * @param serviceSpecificInfo The service specific information (arbitrary
- * byte array) provided by the peer as part of its discovery
- * configuration.
- * @param matchFilter The filter which resulted in this service discovery.
- */
- public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle,
- byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
- /* empty */
- }
-
- /**
- * Called in response to
- * {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int, byte[])}
- * when a message is transmitted successfully - i.e. when it was received successfully by the
- * peer (corresponds to an ACK being received).
- * <p>
- * Note that either this callback or
- * {@link WifiAwareDiscoverySessionCallback#onMessageSendFailed(int)} will be
- * received - never both.
- *
- * @param messageId The arbitrary message ID specified when sending the message.
- */
- public void onMessageSendSucceeded(@SuppressWarnings("unused") int messageId) {
- /* empty */
- }
-
- /**
- * Called when message transmission fails - when no ACK is received from the peer.
- * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
- * the {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
- * byte[], int)} method) - this event is received after all retries are exhausted.
- * <p>
- * Note that either this callback or
- * {@link WifiAwareDiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
- * - never both.
- *
- * @param messageId The arbitrary message ID specified when sending the message.
- */
- public void onMessageSendFailed(@SuppressWarnings("unused") int messageId) {
- /* empty */
- }
-
- /**
- * Called when a message is received from a discovery session peer - in response to the
- * peer's {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle, int,
- * byte[])} or {@link WifiAwareDiscoveryBaseSession#sendMessage(WifiAwareManager.PeerHandle,
- * int, byte[], int)}.
- *
- * @param peerHandle An opaque handle to the peer matching our discovery operation.
- * @param message A byte array containing the message.
- */
- public void onMessageReceived(WifiAwareManager.PeerHandle peerHandle, byte[] message) {
- /* empty */
- }
-}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 029794d..8c0a3a0 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -58,14 +58,14 @@
* The class provides access to:
* <ul>
* <li>Initialize a Aware cluster (peer-to-peer synchronization). Refer to
- * {@link #attach(WifiAwareAttachCallback, Handler)}.
+ * {@link #attach(AttachCallback, Handler)}.
* <li>Create discovery sessions (publish or subscribe sessions). Refer to
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)} and
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback, Handler)}.
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)} and
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}.
* <li>Create a Aware network specifier to be used with
* {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
* to set-up a Aware connection with a peer. Refer to
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])} and
+ * {@link DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])} and
* {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
* </ul>
* <p>
@@ -75,37 +75,37 @@
* broadcast. Note that this broadcast is not sticky - you should register for it and then
* check the above API to avoid a race condition.
* <p>
- * An application must use {@link #attach(WifiAwareAttachCallback, Handler)} to initialize a
+ * An application must use {@link #attach(AttachCallback, Handler)} to initialize a
* Aware cluster - before making any other Aware operation. Aware cluster membership is a
* device-wide operation - the API guarantees that the device is in a cluster or joins a
* Aware cluster (or starts one if none can be found). Information about attach success (or
- * failure) are returned in callbacks of {@link WifiAwareAttachCallback}. Proceed with Aware
+ * failure) are returned in callbacks of {@link AttachCallback}. Proceed with Aware
* discovery or connection setup only after receiving confirmation that Aware attach
- * succeeded - {@link WifiAwareAttachCallback#onAttached(WifiAwareSession)}. When an
+ * succeeded - {@link AttachCallback#onAttached(WifiAwareSession)}. When an
* application is finished using Aware it <b>must</b> use the
* {@link WifiAwareSession#destroy()} API to indicate to the Aware service that the device
* may detach from the Aware cluster. The device will actually disable Aware once the last
* application detaches.
* <p>
* Once a Aware attach is confirmed use the
- * {@link WifiAwareSession#publish(PublishConfig, WifiAwareDiscoverySessionCallback, Handler)}
+ * {@link WifiAwareSession#publish(PublishConfig, DiscoverySessionCallback, Handler)}
* or
- * {@link WifiAwareSession#subscribe(SubscribeConfig, WifiAwareDiscoverySessionCallback,
+ * {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback,
* Handler)} to create publish or subscribe Aware discovery sessions. Events are called on the
- * provided callback object {@link WifiAwareDiscoverySessionCallback}. Specifically, the
- * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(WifiAwarePublishDiscoverySession)}
+ * provided callback object {@link DiscoverySessionCallback}. Specifically, the
+ * {@link DiscoverySessionCallback#onPublishStarted(PublishDiscoverySession)}
* and
- * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
- * WifiAwareSubscribeDiscoverySession)}
- * return {@link WifiAwarePublishDiscoverySession} and
- * {@link WifiAwareSubscribeDiscoverySession}
+ * {@link DiscoverySessionCallback#onSubscribeStarted(
+ *SubscribeDiscoverySession)}
+ * return {@link PublishDiscoverySession} and
+ * {@link SubscribeDiscoverySession}
* objects respectively on which additional session operations can be performed, e.g. updating
- * the session {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)} and
- * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
+ * the session {@link PublishDiscoverySession#updatePublish(PublishConfig)} and
+ * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}. Sessions can
* also be used to send messages using the
- * {@link WifiAwareDiscoveryBaseSession#sendMessage(PeerHandle, int, byte[])} APIs. When an
+ * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} APIs. When an
* application is finished with a discovery session it <b>must</b> terminate it using the
- * {@link WifiAwareDiscoveryBaseSession#destroy()} API.
+ * {@link DiscoverySession#destroy()} API.
* <p>
* Creating connections between Aware devices is managed by the standard
* {@link ConnectivityManager#requestNetwork(NetworkRequest,
@@ -116,7 +116,7 @@
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
* {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])}.
+ * {@link DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
*
* @hide PROPOSED_AWARE_API
@@ -226,7 +226,7 @@
* Connection creation role is that of INITIATOR. Used to create a network specifier string
* when requesting a Aware network.
*
- * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
+ * @see DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])
* @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
*/
public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
@@ -235,7 +235,7 @@
* Connection creation role is that of RESPONDER. Used to create a network specifier string
* when requesting a Aware network.
*
- * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
+ * @see DiscoverySession#createNetworkSpecifier(PeerHandle, byte[])
* @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
*/
public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
@@ -307,7 +307,7 @@
* @return An object specifying configuration limitations of Aware.
* @hide PROPOSED_AWARE_API
*/
- public WifiAwareCharacteristics getCharacteristics() {
+ public Characteristics getCharacteristics() {
try {
return mService.getCharacteristics();
} catch (RemoteException e) {
@@ -328,12 +328,12 @@
* attachCallback}.
*
* @param attachCallback A callback for attach events, extended from
- * {@link WifiAwareAttachCallback}.
+ * {@link AttachCallback}.
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* attachCallback} object. If a null is provided then the application's main thread will be
* used.
*/
- public void attach(@NonNull WifiAwareAttachCallback attachCallback, @Nullable Handler handler) {
+ public void attach(@NonNull AttachCallback attachCallback, @Nullable Handler handler) {
attach(handler, null, attachCallback, null);
}
@@ -353,28 +353,28 @@
* on startup and whenever it is updated (it is randomized at regular intervals for privacy).
* The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
* permission to execute this attach request. Otherwise, use the
- * {@link #attach(WifiAwareAttachCallback, Handler)} version. Note that aside from permission
+ * {@link #attach(AttachCallback, Handler)} version. Note that aside from permission
* requirements this listener will wake up the host at regular intervals causing higher power
* consumption, do not use it unless the information is necessary (e.g. for OOB discovery).
*
* @param attachCallback A callback for attach events, extended from
- * {@link WifiAwareAttachCallback}.
+ * {@link AttachCallback}.
* @param identityChangedListener A listener for changed identity, extended from
- * {@link WifiAwareIdentityChangedListener}.
+ * {@link IdentityChangedListener}.
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* attachCallback} and {@code identityChangedListener} objects. If a null is provided then the
* application's main thread will be used.
*/
- public void attach(@NonNull WifiAwareAttachCallback attachCallback,
- @NonNull WifiAwareIdentityChangedListener identityChangedListener,
+ public void attach(@NonNull AttachCallback attachCallback,
+ @NonNull IdentityChangedListener identityChangedListener,
@Nullable Handler handler) {
attach(handler, null, attachCallback, identityChangedListener);
}
/** @hide */
public void attach(Handler handler, ConfigRequest configRequest,
- WifiAwareAttachCallback attachCallback,
- WifiAwareIdentityChangedListener identityChangedListener) {
+ AttachCallback attachCallback,
+ IdentityChangedListener identityChangedListener) {
if (VDBG) {
Log.v(TAG, "attach(): handler=" + handler + ", callback=" + attachCallback
+ ", configRequest=" + configRequest + ", identityChangedListener="
@@ -409,7 +409,7 @@
/** @hide */
public void publish(int clientId, Looper looper, PublishConfig publishConfig,
- WifiAwareDiscoverySessionCallback callback) {
+ DiscoverySessionCallback callback) {
if (VDBG) Log.v(TAG, "publish(): clientId=" + clientId + ", config=" + publishConfig);
try {
@@ -437,7 +437,7 @@
/** @hide */
public void subscribe(int clientId, Looper looper, SubscribeConfig subscribeConfig,
- WifiAwareDiscoverySessionCallback callback) {
+ DiscoverySessionCallback callback) {
if (VDBG) {
if (VDBG) {
Log.v(TAG,
@@ -672,14 +672,14 @@
}
/**
- * Constructs a {@link WifiAwareAttachCallback} using the specified looper.
+ * Constructs a {@link AttachCallback} using the specified looper.
* All callbacks will delivered on the thread of the specified looper.
*
* @param looper The looper on which to execute the callbacks.
*/
WifiAwareEventCallbackProxy(WifiAwareManager mgr, Looper looper, Binder binder,
- final WifiAwareAttachCallback attachCallback,
- final WifiAwareIdentityChangedListener identityChangedListener) {
+ final AttachCallback attachCallback,
+ final IdentityChangedListener identityChangedListener) {
mAwareManager = new WeakReference<>(mgr);
mLooper = looper;
mBinder = binder;
@@ -828,14 +828,14 @@
private final WeakReference<WifiAwareManager> mAwareManager;
private final boolean mIsPublish;
- private final WifiAwareDiscoverySessionCallback mOriginalCallback;
+ private final DiscoverySessionCallback mOriginalCallback;
private final int mClientId;
private final Handler mHandler;
- private WifiAwareDiscoveryBaseSession mSession;
+ private DiscoverySession mSession;
WifiAwareDiscoverySessionCallbackProxy(WifiAwareManager mgr, Looper looper,
- boolean isPublish, WifiAwareDiscoverySessionCallback originalCallback,
+ boolean isPublish, DiscoverySessionCallback originalCallback,
int clientId) {
mAwareManager = new WeakReference<>(mgr);
mIsPublish = isPublish;
@@ -1006,13 +1006,13 @@
}
if (mIsPublish) {
- WifiAwarePublishDiscoverySession session = new WifiAwarePublishDiscoverySession(mgr,
+ PublishDiscoverySession session = new PublishDiscoverySession(mgr,
mClientId, sessionId);
mSession = session;
mOriginalCallback.onPublishStarted(session);
} else {
- WifiAwareSubscribeDiscoverySession
- session = new WifiAwareSubscribeDiscoverySession(mgr, mClientId, sessionId);
+ SubscribeDiscoverySession
+ session = new SubscribeDiscoverySession(mgr, mClientId, sessionId);
mSession = session;
mOriginalCallback.onSubscribeStarted(session);
}
@@ -1027,18 +1027,7 @@
Log.w(TAG, "Proxy: onSessionTerminated called but mSession is null!?");
}
mAwareManager.clear();
- mOriginalCallback.onSessionTerminated(reason);
+ mOriginalCallback.onSessionTerminated();
}
}
-
- /** @hide PROPOSED_AWARE_API */
- public static class PeerHandle {
- /** @hide */
- public PeerHandle(int peerId) {
- this.peerId = peerId;
- }
-
- /** @hide */
- public int peerId;
- }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 005895a..e3ebe86 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -65,7 +65,7 @@
* session-wide destroy.
* <p>
* An application may re-attach after a destroy using
- * {@link WifiAwareManager#attach(WifiAwareAttachCallback, Handler)} .
+ * {@link WifiAwareManager#attach(AttachCallback, Handler)} .
*/
public void destroy() {
WifiAwareManager mgr = mMgr.get();
@@ -95,22 +95,22 @@
/**
* Issue a request to the Aware service to create a new Aware publish discovery session, using
* the specified {@code publishConfig} configuration. The results of the publish operation
- * are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
+ * are routed to the callbacks of {@link DiscoverySessionCallback}:
* <ul>
* <li>
- * {@link WifiAwareDiscoverySessionCallback#onPublishStarted(
- * WifiAwarePublishDiscoverySession)}
+ * {@link DiscoverySessionCallback#onPublishStarted(
+ *PublishDiscoverySession)}
* is called when the publish session is created and provides a handle to the session.
* Further operations on the publish session can be executed on that object.
- * <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+ * <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
* publish operation failed.
* </ul>
* <p>
* Other results of the publish session operations will also be routed to callbacks
* on the {@code callback} object. The resulting publish session can be modified using
- * {@link WifiAwarePublishDiscoverySession#updatePublish(PublishConfig)}.
+ * {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
* <p>
- * An application must use the {@link WifiAwareDiscoveryBaseSession#destroy()} to
+ * An application must use the {@link DiscoverySession#destroy()} to
* terminate the publish discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
* <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -118,13 +118,13 @@
*
* @param publishConfig The {@link PublishConfig} specifying the
* configuration of the requested publish session.
- * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
+ * @param callback A {@link DiscoverySessionCallback} derived object to be used for
* session event callbacks.
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* callback} object. If a null is provided then the application's main thread will be used.
*/
public void publish(@NonNull PublishConfig publishConfig,
- @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
+ @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -141,22 +141,22 @@
/**
* Issue a request to the Aware service to create a new Aware subscribe discovery session, using
* the specified {@code subscribeConfig} configuration. The results of the subscribe
- * operation are routed to the callbacks of {@link WifiAwareDiscoverySessionCallback}:
+ * operation are routed to the callbacks of {@link DiscoverySessionCallback}:
* <ul>
* <li>
- * {@link WifiAwareDiscoverySessionCallback#onSubscribeStarted(
- * WifiAwareSubscribeDiscoverySession)}
+ * {@link DiscoverySessionCallback#onSubscribeStarted(
+ *SubscribeDiscoverySession)}
* is called when the subscribe session is created and provides a handle to the session.
* Further operations on the subscribe session can be executed on that object.
- * <li>{@link WifiAwareDiscoverySessionCallback#onSessionConfigFailed()} is called if the
+ * <li>{@link DiscoverySessionCallback#onSessionConfigFailed()} is called if the
* subscribe operation failed.
* </ul>
* <p>
* Other results of the subscribe session operations will also be routed to callbacks
* on the {@code callback} object. The resulting subscribe session can be modified using
- * {@link WifiAwareSubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
+ * {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
* <p>
- * An application must use the {@link WifiAwareDiscoveryBaseSession#destroy()} to
+ * An application must use the {@link DiscoverySession#destroy()} to
* terminate the subscribe discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
* <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -164,13 +164,13 @@
*
* @param subscribeConfig The {@link SubscribeConfig} specifying the
* configuration of the requested subscribe session.
- * @param callback A {@link WifiAwareDiscoverySessionCallback} derived object to be used for
+ * @param callback A {@link DiscoverySessionCallback} derived object to be used for
* session event callbacks.
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* callback} object. If a null is provided then the application's main thread will be used.
*/
public void subscribe(@NonNull SubscribeConfig subscribeConfig,
- @NonNull WifiAwareDiscoverySessionCallback callback, @Nullable Handler handler) {
+ @NonNull DiscoverySessionCallback callback, @Nullable Handler handler) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.e(TAG, "publish: called post GC on WifiAwareManager");
@@ -193,7 +193,7 @@
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(WifiAwareManager.PeerHandle,
+ * {@link DiscoverySession#createNetworkSpecifier(PeerHandle,
* byte[])}.
*
* @param role The role of this device:
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 24c0127..a396d87 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -67,19 +67,19 @@
public Context mockContext;
@Mock
- public WifiAwareAttachCallback mockCallback;
+ public AttachCallback mockCallback;
@Mock
- public WifiAwareDiscoverySessionCallback mockSessionCallback;
+ public DiscoverySessionCallback mockSessionCallback;
@Mock
public IWifiAwareManager mockAwareService;
@Mock
- public WifiAwarePublishDiscoverySession mockPublishSession;
+ public PublishDiscoverySession mockPublishSession;
@Mock
- public WifiAwareSubscribeDiscoverySession mockSubscribeSession;
+ public SubscribeDiscoverySession mockSubscribeSession;
@Mock
public RttManager.RttListener mockRttListener;
@@ -276,7 +276,7 @@
final int sessionId = 123;
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
- final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+ final PeerHandle peerHandle = new PeerHandle(873);
final String string1 = "hey from here...";
final byte[] matchFilter = { 1, 12, 2, 31, 32 };
final int messageId = 2123;
@@ -290,10 +290,9 @@
.forClass(IWifiAwareEventCallback.class);
ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
.forClass(IWifiAwareDiscoverySessionCallback.class);
- ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
- .forClass(WifiAwarePublishDiscoverySession.class);
- ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
- WifiAwareManager.PeerHandle.class);
+ ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+ .forClass(PublishDiscoverySession.class);
+ ArgumentCaptor<PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(PeerHandle.class);
ArgumentCaptor<List<byte[]>> matchFilterCaptor = ArgumentCaptor.forClass(
(Class) List.class);
@@ -377,7 +376,6 @@
final int sessionId = 123;
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
- final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession);
@@ -387,8 +385,8 @@
.forClass(IWifiAwareEventCallback.class);
ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
.forClass(IWifiAwareDiscoverySessionCallback.class);
- ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
- .forClass(WifiAwarePublishDiscoverySession.class);
+ ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+ .forClass(PublishDiscoverySession.class);
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -404,10 +402,10 @@
inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig),
sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
- sessionProxyCallback.getValue().onSessionTerminated(reason);
+ sessionProxyCallback.getValue().onSessionTerminated(0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
- inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+ inOrder.verify(mockSessionCallback).onSessionTerminated();
// (3) failure when trying to update: NOP
publishSession.getValue().updatePublish(publishConfig);
@@ -428,7 +426,7 @@
final int sessionId = 123;
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
- final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
+ final PeerHandle peerHandle = new PeerHandle(873);
final String string1 = "hey from here...";
final byte[] matchFilter = { 1, 12, 3, 31, 32 }; // bad data!
final int messageId = 2123;
@@ -442,10 +440,9 @@
.forClass(IWifiAwareEventCallback.class);
ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
.forClass(IWifiAwareDiscoverySessionCallback.class);
- ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
- .forClass(WifiAwareSubscribeDiscoverySession.class);
- ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
- WifiAwareManager.PeerHandle.class);
+ ArgumentCaptor<SubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+ .forClass(SubscribeDiscoverySession.class);
+ ArgumentCaptor<PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(PeerHandle.class);
// (0) connect + success
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -516,7 +513,6 @@
final int sessionId = 123;
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
- final int reason = WifiAwareDiscoverySessionCallback.TERMINATE_REASON_DONE;
InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
mockSubscribeSession);
@@ -526,8 +522,8 @@
.forClass(IWifiAwareEventCallback.class);
ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
.forClass(IWifiAwareDiscoverySessionCallback.class);
- ArgumentCaptor<WifiAwareSubscribeDiscoverySession> subscribeSession = ArgumentCaptor
- .forClass(WifiAwareSubscribeDiscoverySession.class);
+ ArgumentCaptor<SubscribeDiscoverySession> subscribeSession = ArgumentCaptor
+ .forClass(SubscribeDiscoverySession.class);
// (1) connect successfully
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -543,10 +539,10 @@
inOrder.verify(mockAwareService).subscribe(eq(clientId), eq(subscribeConfig),
sessionProxyCallback.capture());
sessionProxyCallback.getValue().onSessionStarted(sessionId);
- sessionProxyCallback.getValue().onSessionTerminated(reason);
+ sessionProxyCallback.getValue().onSessionTerminated(0);
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
- inOrder.verify(mockSessionCallback).onSessionTerminated(reason);
+ inOrder.verify(mockSessionCallback).onSessionTerminated();
// (3) failure when trying to update: NOP
subscribeSession.getValue().updateSubscribe(subscribeConfig);
@@ -892,8 +888,8 @@
.forClass(IWifiAwareEventCallback.class);
ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
.forClass(IWifiAwareDiscoverySessionCallback.class);
- ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
- .forClass(WifiAwarePublishDiscoverySession.class);
+ ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+ .forClass(PublishDiscoverySession.class);
ArgumentCaptor<RttManager.ParcelableRttParams> rttParamCaptor = ArgumentCaptor
.forClass(RttManager.ParcelableRttParams.class);
ArgumentCaptor<RttManager.RttResult[]> rttResultsCaptor = ArgumentCaptor
@@ -953,7 +949,7 @@
public void testNetworkSpecifierWithClient() throws Exception {
final int clientId = 4565;
final int sessionId = 123;
- final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(123412);
+ final PeerHandle peerHandle = new PeerHandle(123412);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
final String token = "Some arbitrary token string - can really be anything";
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
@@ -967,8 +963,8 @@
.forClass(IWifiAwareEventCallback.class);
ArgumentCaptor<IWifiAwareDiscoverySessionCallback> sessionProxyCallback = ArgumentCaptor
.forClass(IWifiAwareDiscoverySessionCallback.class);
- ArgumentCaptor<WifiAwarePublishDiscoverySession> publishSession = ArgumentCaptor
- .forClass(WifiAwarePublishDiscoverySession.class);
+ ArgumentCaptor<PublishDiscoverySession> publishSession = ArgumentCaptor
+ .forClass(PublishDiscoverySession.class);
InOrder inOrder = inOrder(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);