Merge "AudioEffect JNI: use new max preprocessing constant" into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 979f2cf..a8c2ddc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16310,6 +16310,7 @@
method public void setPlaybackToRemote(android.media.VolumeProvider);
method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>);
method public void setQueueTitle(java.lang.CharSequence);
+ method public void setRatingType(int);
method public void setSessionActivity(android.app.PendingIntent);
field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
@@ -16368,6 +16369,7 @@
method public long getBufferedPosition();
method public java.util.List<android.media.session.PlaybackState.CustomAction> getCustomActions();
method public java.lang.CharSequence getErrorMessage();
+ method public android.os.Bundle getExtras();
method public long getLastPositionUpdateTime();
method public float getPlaybackSpeed();
method public long getPosition();
@@ -16412,6 +16414,7 @@
method public android.media.session.PlaybackState.Builder setActiveQueueItemId(long);
method public android.media.session.PlaybackState.Builder setBufferedPosition(long);
method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence);
+ method public android.media.session.PlaybackState.Builder setExtras(android.os.Bundle);
method public android.media.session.PlaybackState.Builder setState(int, long, float, long);
method public android.media.session.PlaybackState.Builder setState(int, long, float);
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index ba11a81..bc57030 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -417,7 +417,7 @@
} else if (opt.equals("--ei")) {
String key = nextArgRequired();
String value = nextArgRequired();
- intent.putExtra(key, Integer.valueOf(value));
+ intent.putExtra(key, Integer.decode(value));
} else if (opt.equals("--eu")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -434,7 +434,7 @@
String[] strings = value.split(",");
int[] list = new int[strings.length];
for (int i = 0; i < strings.length; i++) {
- list[i] = Integer.valueOf(strings[i]);
+ list[i] = Integer.decode(strings[i]);
}
intent.putExtra(key, list);
} else if (opt.equals("--el")) {
@@ -477,8 +477,23 @@
hasIntentInfo = true;
} else if (opt.equals("--ez")) {
String key = nextArgRequired();
- String value = nextArgRequired();
- intent.putExtra(key, Boolean.valueOf(value));
+ String value = nextArgRequired().toLowerCase();
+ // Boolean.valueOf() results in false for anything that is not "true", which is
+ // error-prone in shell commands
+ boolean arg;
+ if ("true".equals(value) || "t".equals(value)) {
+ arg = true;
+ } else if ("false".equals(value) || "f".equals(value)) {
+ arg = false;
+ } else {
+ try {
+ arg = Integer.decode(value) != 0;
+ } catch (NumberFormatException ex) {
+ throw new IllegalArgumentException("Invalid boolean value: " + value);
+ }
+ }
+
+ intent.putExtra(key, arg);
} else if (opt.equals("-n")) {
String str = nextArgRequired();
ComponentName cn = ComponentName.unflattenFromString(str);
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 71df60a..6159e1e 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -200,7 +200,7 @@
vendorInfo = info;
}
- public void setDomains(String domains) {
- domains = domains;
+ public void setDomains(String newDomains) {
+ domains = newDomains;
}
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 3f68a44..03a2085 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -41,10 +41,10 @@
* <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_SCORE_NETWORKS} 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.
+ * {@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.
* </ul>
*
* <p>The system keeps track of an active scorer application; at any time, only this application
@@ -194,8 +194,8 @@
*
* @return true if the operation succeeded, or false if the new package is not a valid scorer.
* @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission indicating
- * that it can manage scorer applications.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission
+ * indicating that it can manage scorer applications.
* @hide
*/
public boolean setActiveScorer(String packageName) throws SecurityException {
@@ -228,7 +228,7 @@
*
* @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_SCORE_NETWORKS} permission.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* @hide
*/
public boolean requestScores(NetworkKey[] networks) throws SecurityException {
@@ -252,7 +252,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_SCORE_NETWORKS} permission.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
* @hide
*/
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index c33f5ec..46f7194 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -79,7 +79,7 @@
* <ul>
* <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
* <li>Includes a receiver for {@link NetworkScoreManager#ACTION_SCORE_NETWORKS} guarded by the
- * {@link android.Manifest.permission#BROADCAST_SCORE_NETWORKS} permission.
+ * {@link android.Manifest.permission#BROADCAST_NETWORK_PRIVILEGED} permission.
* </ul>
*
* @return the list of scorers, or the empty list if there are no valid scorers.
@@ -98,8 +98,8 @@
// Should never happen with queryBroadcastReceivers, but invalid nonetheless.
continue;
}
- if (!permission.BROADCAST_SCORE_NETWORKS.equals(receiverInfo.permission)) {
- // Receiver doesn't require the BROADCAST_SCORE_NETWORKS permission, which means
+ if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) {
+ // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means
// anyone could trigger network scoring and flood the framework with score requests.
continue;
}
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 5a273cf..598a503 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -107,6 +107,7 @@
for (InetAddress dns : dnsServers) {
lp.addDnsServer(dns);
}
+ lp.setDomains(domains);
return lp;
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 9fb3535..36401eb 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -78,6 +78,7 @@
private static final String ALLOW_ATT_EVENTS = "events";
private static final String SLEEP_TAG = "sleep";
private static final String SLEEP_ATT_MODE = "mode";
+ private static final String SLEEP_ATT_NONE = "none";
private static final String SLEEP_ATT_START_HR = "startHour";
private static final String SLEEP_ATT_START_MIN = "startMin";
@@ -107,6 +108,7 @@
public int sleepStartMinute; // 0-59
public int sleepEndHour;
public int sleepEndMinute;
+ public boolean sleepNone; // false = priority, true = none
public ComponentName[] conditionComponents;
public Uri[] conditionIds;
public Condition exitCondition;
@@ -125,6 +127,7 @@
sleepStartMinute = source.readInt();
sleepEndHour = source.readInt();
sleepEndMinute = source.readInt();
+ sleepNone = source.readInt() == 1;
int len = source.readInt();
if (len > 0) {
conditionComponents = new ComponentName[len];
@@ -155,6 +158,7 @@
dest.writeInt(sleepStartMinute);
dest.writeInt(sleepEndHour);
dest.writeInt(sleepEndMinute);
+ dest.writeInt(sleepNone ? 1 : 0);
if (conditionComponents != null && conditionComponents.length > 0) {
dest.writeInt(conditionComponents.length);
dest.writeTypedArray(conditionComponents, 0);
@@ -182,6 +186,7 @@
.append(",sleepMode=").append(sleepMode)
.append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
.append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
+ .append(",sleepNone=").append(sleepNone)
.append(",conditionComponents=")
.append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
.append(",conditionIds=")
@@ -214,6 +219,7 @@
&& other.allowFrom == allowFrom
&& other.allowEvents == allowEvents
&& Objects.equals(other.sleepMode, sleepMode)
+ && other.sleepNone == sleepNone
&& other.sleepStartHour == sleepStartHour
&& other.sleepStartMinute == sleepStartMinute
&& other.sleepEndHour == sleepEndHour
@@ -226,7 +232,7 @@
@Override
public int hashCode() {
- return Objects.hash(allowCalls, allowMessages, allowFrom, allowEvents, sleepMode,
+ return Objects.hash(allowCalls, allowMessages, allowFrom, allowEvents, sleepMode, sleepNone,
sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute,
Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
exitCondition, exitConditionComponent);
@@ -302,6 +308,7 @@
} else if (SLEEP_TAG.equals(tag)) {
final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
rt.sleepMode = isValidSleepMode(mode)? mode : null;
+ rt.sleepNone = safeBoolean(parser, SLEEP_ATT_NONE, false);
final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
@@ -345,6 +352,7 @@
if (sleepMode != null) {
out.attribute(null, SLEEP_ATT_MODE, sleepMode);
}
+ out.attribute(null, SLEEP_ATT_NONE, Boolean.toString(sleepNone));
out.attribute(null, SLEEP_ATT_START_HR, Integer.toString(sleepStartHour));
out.attribute(null, SLEEP_ATT_START_MIN, Integer.toString(sleepStartMinute));
out.attribute(null, SLEEP_ATT_END_HR, Integer.toString(sleepEndHour));
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6f2a06b..ffe2b60 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2511,11 +2511,12 @@
android:description="@string/permdesc_broadcastWapPush"
android:protectionLevel="signature" />
- <!-- @SystemApi Allows an application to broadcast a SCORE_NETWORKS request.
+ <!-- @SystemApi Allows an application to broadcast privileged networking requests.
<p>Not for use by third-party applications. @hide -->
- <permission android:name="android.permission.BROADCAST_SCORE_NETWORKS"
- android:label="@string/permlab_broadcastScoreNetworks"
- android:description="@string/permdesc_broadcastScoreNetworks"
+ <permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:label="@string/permlab_broadcastNetworkPrivileged"
+ android:description="@string/permdesc_broadcastNetworkPrivileged"
android:protectionLevel="signature|system" />
<!-- @SystemApi Not for use by third-party applications. -->
diff --git a/core/res/res/drawable-hdpi/sym_def_app_icon.png b/core/res/res/drawable-hdpi/sym_def_app_icon.png
index 96a442e..cde69bc 100644
--- a/core/res/res/drawable-hdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sym_def_app_icon.png b/core/res/res/drawable-mdpi/sym_def_app_icon.png
index 359047d..c133a0c 100644
--- a/core/res/res/drawable-mdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/sym_def_app_icon.png b/core/res/res/drawable-xhdpi/sym_def_app_icon.png
index 71c6d76..bfa42f0 100644
--- a/core/res/res/drawable-xhdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-xhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/sym_def_app_icon.png b/core/res/res/drawable-xxhdpi/sym_def_app_icon.png
index 20a47a0..324e72c 100644
--- a/core/res/res/drawable-xxhdpi/sym_def_app_icon.png
+++ b/core/res/res/drawable-xxhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/sym_def_app_icon.png b/core/res/res/drawable-xxxhdpi/sym_def_app_icon.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-hdpi/sym_def_app_icon.png b/core/res/res/mipmap-hdpi/sym_def_app_icon.png
index c8a38ed..cde69bc 100644
--- a/core/res/res/mipmap-hdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-hdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-mdpi/sym_def_app_icon.png b/core/res/res/mipmap-mdpi/sym_def_app_icon.png
index b3e10f6..c133a0c 100644
--- a/core/res/res/mipmap-mdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-mdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-xhdpi/sym_def_app_icon.png b/core/res/res/mipmap-xhdpi/sym_def_app_icon.png
index f381f86..bfa42f0 100644
--- a/core/res/res/mipmap-xhdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-xhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png b/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png
index e3f3144..324e72c 100644
--- a/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png
+++ b/core/res/res/mipmap-xxhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/mipmap-xxxhdpi/sym_def_app_icon.png b/core/res/res/mipmap-xxxhdpi/sym_def_app_icon.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/core/res/res/mipmap-xxxhdpi/sym_def_app_icon.png
Binary files differ
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index bb9885c..f6a5787 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -441,4 +441,13 @@
<item>中文 (繁體)</item>
</string-array>
+ <array name="sim_colors">
+ <item>@color/Teal_700</item>
+ <item>@color/Blue_700</item>
+ <item>@color/Indigo_700</item>
+ <item>@color/Purple_700</item>
+ <item>@color/Pink_700</item>
+ <item>@color/Red_700</item>
+ </array>
+
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 91a8598..67ba27da 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6388,7 +6388,7 @@
<!-- The summary for the Preference in a PreferenceActivity screen. -->
<attr name="summary" />
<!-- The order for the Preference (lower values are to be ordered first). If this is not
- specified, the default orderin will be alphabetic. -->
+ specified, the default ordering will be alphabetic. -->
<attr name="order" format="integer" />
<!-- When used inside of a modern PreferenceActivity, this declares
a new PreferenceFragment to be shown when the user selects this item. -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 9f83db4..b9825c5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -160,5 +160,18 @@
<color name="user_icon_8">#ffff5722</color><!-- deep orange 500 -->
<color name="user_icon_default_gray">#ff9e9e9e</color><!-- gray 500 -->
<color name="user_icon_default_white">#ffffffff</color><!-- white -->
-</resources>
+ <!-- Multi-sim sim colors -->
+ <color name="Teal_700">#ff00796b</color>
+ <color name="Teal_800">#ff00695c</color>
+ <color name="Blue_700">#ff3367d6</color>
+ <color name="Blue_800">#ff2a56c6</color>
+ <color name="Indigo_700">#ff303f9f</color>
+ <color name="Indigo_800">#ff283593</color>
+ <color name="Purple_700">#ff7b1fa2</color>
+ <color name="Purple_800">#ff6a1b9a</color>
+ <color name="Pink_700">#ffc2185b</color>
+ <color name="Pink_800">#ffad1457</color>
+ <color name="Red_700">#ffc53929</color>
+ <color name="Red_800">#ffb93221</color>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 652e40c..52ef4f9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -473,6 +473,8 @@
<bool name="config_allowTheaterModeWakeFromDock">false</bool>
<!-- If this is true, allow wake from theater mode from window layout flag. -->
<bool name="config_allowTheaterModeWakeFromWindowLayout">false</bool>
+ <!-- If this is true, go to sleep when theater mode is enabled from button press -->
+ <bool name="config_goToSleepOnButtonPressTheaterMode">true</bool>
<!-- Auto-rotation behavior -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3051234..c5bd495 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -977,10 +977,10 @@
<!-- TODO: Mark these as translatable when API is finalized. -->
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_broadcastScoreNetworks" translatable="false">send score networks broadcast</string>
+ <string name="permlab_broadcastNetworkPrivileged" translatable="false">send privileged network broadcasts</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_broadcastScoreNetworks" translatable="false">Allows the app
- to broadcast a notification that networks need to be scored.
+ <string name="permdesc_broadcastNetworkPrivileged" translatable="false">Allows the app
+ to send privileged network broadcasts.
Never needed for normal apps.
</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a5f0ff1..6e881a7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1073,6 +1073,7 @@
<java-symbol type="array" name="networkAttributes" />
<java-symbol type="array" name="preloaded_color_state_lists" />
<java-symbol type="array" name="preloaded_drawables" />
+ <java-symbol type="array" name="sim_colors" />
<java-symbol type="array" name="special_locale_codes" />
<java-symbol type="array" name="special_locale_names" />
<java-symbol type="array" name="config_masterVolumeRamp" />
@@ -1584,6 +1585,7 @@
<java-symbol type="bool" name="config_allowTheaterModeWakeFromLidSwitch" />
<java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" />
<java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" />
+ <java-symbol type="bool" name="config_goToSleepOnButtonPressTheaterMode" />
<java-symbol type="bool" name="config_wifi_background_scan_support" />
<java-symbol type="bool" name="config_wifi_dual_band_support" />
<java-symbol type="bool" name="config_wimaxEnabled" />
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index f916711..9bb44d0 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -59,7 +59,7 @@
// Package 1 - Valid scorer.
Pair<ResolveInfo, ResolveInfo> package1 = buildResolveInfo("package1", true, true, false);
- // Package 2 - Receiver does not have BROADCAST_SCORE_NETWORKS permission.
+ // Package 2 - Receiver does not have BROADCAST_NETWORK_PRIVILEGED permission.
Pair<ResolveInfo, ResolveInfo> package2 = buildResolveInfo("package2", false, true, false);
// Package 3 - App does not have SCORE_NETWORKS permission.
@@ -134,7 +134,7 @@
resolveInfo.activityInfo.packageName = packageName;
resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
if (hasReceiverPermission) {
- resolveInfo.activityInfo.permission = permission.BROADCAST_SCORE_NETWORKS;
+ resolveInfo.activityInfo.permission = permission.BROADCAST_NETWORK_PRIVILEGED;
}
ResolveInfo configActivityInfo = null;
diff --git a/docs/html/images/tools/as-attach.png b/docs/html/images/tools/as-attach.png
new file mode 100644
index 0000000..c572b1e
--- /dev/null
+++ b/docs/html/images/tools/as-attach.png
Binary files differ
diff --git a/docs/html/sdk/installing/studio-debug.jd b/docs/html/sdk/installing/studio-debug.jd
index 2e3e137..b048400 100644
--- a/docs/html/sdk/installing/studio-debug.jd
+++ b/docs/html/sdk/installing/studio-debug.jd
@@ -6,7 +6,11 @@
<div id="qv">
<h2>In this document</h2>
<ol>
- <li><a href="#runDebug">Run your App in Debug Mode</a></li>
+ <li><a href="#runDebug">Run your App in Debug Mode</a>
+ <ol>
+ <li><a href="#attachDebug">Attach the debugger to a running process</a></li>
+ </ol>
+ </li>
<li><a href="#systemLog">Use the System Log</a>
<ol>
<li><a href="#systemLogWrite">Write log messages in your code</a></li>
@@ -94,6 +98,22 @@
<p class="img-caption"><strong>Figure 2.</strong> The Debug tool window in Android Studio showing
the current thread and the object tree for a variable.</p>
+<h3 id="attachDebug">Attach the debugger to a running process</h3>
+
+<p>You don't always have to restart your app to debug it. To debug an app that you're already
+running:</p>
+
+<ol>
+<li>Click <strong>Attach debugger to Android proccess</strong>
+<img src="{@docRoot}images/tools/as-attach.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/>.</li>
+<li>In the <em>Choose Process</em> window, select the device and app you want to attach the
+debugger to.</li>
+<li>To open the <em>Debug</em> tool window, click <strong>Debug</strong>
+<img src="{@docRoot}images/tools/as-debugwindowbutton.png"
+alt="" style="vertical-align:bottom;margin:0;height:20px"/>.</li>
+</ol>
+
<h2 id="systemLog">Use the System Log</h2>
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 6991dea..f02cdbc 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -340,7 +340,6 @@
</td>
</tr>
</table>
-<p class="note"><strong>Note:</strong> The full SDK/NDK requires 13 GB of disk space.</p>
</div><!-- end pax -->
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index f1e4858..3cf1021 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3645,8 +3645,12 @@
Entry entry;
status_t err = getEntry(grp, t, e, &desiredConfig, &entry);
if (err != NO_ERROR) {
+ // Only log the failure when we're not running on the host as
+ // part of a tool. The caller will do its own logging.
+#ifndef STATIC_ANDROIDFW_FOR_TOOLS
ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) (error %d)\n",
resID, t, e, err);
+#endif
return err;
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 86da80a..973527f 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -286,7 +286,9 @@
if (volumeProvider == null) {
throw new IllegalArgumentException("volumeProvider may not be null!");
}
- mVolumeProvider = volumeProvider;
+ synchronized (mLock) {
+ mVolumeProvider = volumeProvider;
+ }
volumeProvider.setCallback(new VolumeProvider.Callback() {
@Override
public void onVolumeChanged(VolumeProvider volumeProvider) {
@@ -449,6 +451,27 @@
}
/**
+ * Set the style of rating used by this session. Apps trying to set the
+ * rating should use this style. Must be one of the following:
+ * <ul>
+ * <li>{@link Rating#RATING_NONE}</li>
+ * <li>{@link Rating#RATING_3_STARS}</li>
+ * <li>{@link Rating#RATING_4_STARS}</li>
+ * <li>{@link Rating#RATING_5_STARS}</li>
+ * <li>{@link Rating#RATING_HEART}</li>
+ * <li>{@link Rating#RATING_PERCENTAGE}</li>
+ * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
+ * </ul>
+ */
+ public void setRatingType(int type) {
+ try {
+ mBinder.setRatingType(type);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in setRatingType.", e);
+ }
+ }
+
+ /**
* Set some extras that can be associated with the {@link MediaSession}. No assumptions should
* be made as to how a {@link MediaController} will handle these extras.
* Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
@@ -470,9 +493,11 @@
* @hide
*/
public void notifyRemoteVolumeChanged(VolumeProvider provider) {
- if (provider == null || provider != mVolumeProvider) {
- Log.w(TAG, "Received update from stale volume provider");
- return;
+ synchronized (mLock) {
+ if (provider == null || provider != mVolumeProvider) {
+ Log.w(TAG, "Received update from stale volume provider");
+ return;
+ }
}
try {
mBinder.setCurrentVolume(provider.getCurrentVolume());
@@ -537,6 +562,14 @@
postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent);
}
+ private void dispatchAdjustVolume(int direction) {
+ postToCallback(CallbackMessageHandler.MSG_ADJUST_VOLUME, direction);
+ }
+
+ private void dispatchSetVolumeTo(int volume) {
+ postToCallback(CallbackMessageHandler.MSG_SET_VOLUME, volume);
+ }
+
private void postToCallback(int what) {
postToCallback(what, null);
}
@@ -988,9 +1021,7 @@
public void onAdjustVolume(int direction) {
MediaSession session = mMediaSession.get();
if (session != null) {
- if (session.mVolumeProvider != null) {
- session.mVolumeProvider.onAdjustVolume(direction);
- }
+ session.dispatchAdjustVolume(direction);
}
}
@@ -998,9 +1029,7 @@
public void onSetVolumeTo(int value) {
MediaSession session = mMediaSession.get();
if (session != null) {
- if (session.mVolumeProvider != null) {
- session.mVolumeProvider.onSetVolumeTo(value);
- }
+ session.dispatchSetVolumeTo(value);
}
}
@@ -1117,6 +1146,8 @@
private static final int MSG_CUSTOM_ACTION = 13;
private static final int MSG_MEDIA_BUTTON = 14;
private static final int MSG_COMMAND = 15;
+ private static final int MSG_ADJUST_VOLUME = 16;
+ private static final int MSG_SET_VOLUME = 17;
private MediaSession.Callback mCallback;
@@ -1145,6 +1176,7 @@
@Override
public void handleMessage(Message msg) {
+ VolumeProvider vp;
switch (msg.what) {
case MSG_PLAY:
mCallback.onPlay();
@@ -1192,6 +1224,22 @@
Command cmd = (Command) msg.obj;
mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
break;
+ case MSG_ADJUST_VOLUME:
+ synchronized (mLock) {
+ vp = mVolumeProvider;
+ }
+ if (vp != null) {
+ vp.onAdjustVolume((int) msg.obj);
+ }
+ break;
+ case MSG_SET_VOLUME:
+ synchronized (mLock) {
+ vp = mVolumeProvider;
+ }
+ if (vp != null) {
+ vp.onSetVolumeTo((int) msg.obj);
+ }
+ break;
}
}
}
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index 267d1ff..54d0acd 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -16,6 +16,7 @@
package android.media.session;
import android.annotation.DrawableRes;
+import android.annotation.Nullable;
import android.media.RemoteControlClient;
import android.os.Bundle;
import android.os.Parcel;
@@ -232,11 +233,12 @@
private final CharSequence mErrorMessage;
private final long mUpdateTime;
private final long mActiveItemId;
+ private final Bundle mExtras;
private PlaybackState(int state, long position, long updateTime, float speed,
long bufferedPosition, long transportControls,
List<PlaybackState.CustomAction> customActions, long activeItemId,
- CharSequence error) {
+ CharSequence error, Bundle extras) {
mState = state;
mPosition = position;
mSpeed = speed;
@@ -246,6 +248,7 @@
mCustomActions = new ArrayList<>(customActions);
mActiveItemId = activeItemId;
mErrorMessage = error;
+ mExtras = extras;
}
private PlaybackState(Parcel in) {
@@ -258,7 +261,7 @@
mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
mActiveItemId = in.readLong();
mErrorMessage = in.readCharSequence();
-
+ mExtras = in.readBundle();
}
@Override
@@ -293,6 +296,7 @@
dest.writeTypedList(mCustomActions);
dest.writeLong(mActiveItemId);
dest.writeCharSequence(mErrorMessage);
+ dest.writeBundle(mExtras);
}
/**
@@ -306,6 +310,7 @@
* <li> {@link PlaybackState#STATE_REWINDING}</li>
* <li> {@link PlaybackState#STATE_BUFFERING}</li>
* <li> {@link PlaybackState#STATE_ERROR}</li>
+ * </ul>
*/
public int getState() {
return mState;
@@ -394,6 +399,15 @@
}
/**
+ * Get any custom extras that were set on this playback state.
+ *
+ * @return The extras for this state or null.
+ */
+ public @Nullable Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
* Get the {@link PlaybackState} state for the given
* {@link RemoteControlClient} state.
*
@@ -737,6 +751,7 @@
private CharSequence mErrorMessage;
private long mUpdateTime;
private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
+ private Bundle mExtras;
/**
* Creates an initially empty state builder.
@@ -765,6 +780,7 @@
mErrorMessage = from.mErrorMessage;
mUpdateTime = from.mUpdateTime;
mActiveItemId = from.mActiveItemId;
+ mExtras = from.mExtras;
}
/**
@@ -947,13 +963,25 @@
}
/**
- * Build and return the {@link PlaybackState} instance with these values.
+ * Set any custom extras to be included with the playback state.
+ *
+ * @param extras The extras to include.
+ * @return this
+ */
+ public Builder setExtras(Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Build and return the {@link PlaybackState} instance with these
+ * values.
*
* @return A new state instance.
*/
public PlaybackState build() {
return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition,
- mActions, mCustomActions, mActiveItemId, mErrorMessage);
+ mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras);
}
}
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index d50be42..0754fd4 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -101,7 +101,6 @@
* be thrown.
*
* @see MediaBrowserService#onLoadChildren
- * @see MediaBrowserService#onLoadIcon
*/
public class Result<T> {
private Object mDebug;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 792712f..3c44e87 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -48,6 +48,7 @@
import android.media.RingtoneManager;
import android.media.session.MediaSessionLegacyHelper;
import android.os.Bundle;
+import android.os.Debug;
import android.os.FactoryTest;
import android.os.Handler;
import android.os.IBinder;
@@ -116,6 +117,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
+import java.util.List;
import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -527,6 +529,9 @@
private boolean mAllowTheaterModeWakeFromLidSwitch;
private boolean mAllowTheaterModeWakeFromWakeGesture;
+ // Whether to go to sleep entering theater mode from power button
+ private boolean mGoToSleepOnButtonPressTheaterMode;
+
// Screenshot trigger states
// Time to volume and power must be pressed within this interval of each other.
private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
@@ -984,7 +989,8 @@
Slog.i(TAG, "Toggling theater mode on.");
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.THEATER_MODE_ON, 1);
- if (interactive) {
+
+ if (mGoToSleepOnButtonPressTheaterMode && interactive) {
mPowerManager.goToSleep(eventTime,
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
}
@@ -1236,6 +1242,9 @@
mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
+ mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode);
+
mShortPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_shortPressOnPowerBehavior);
mLongPressOnPowerBehavior = mContext.getResources().getInteger(
@@ -2099,11 +2108,8 @@
/** {@inheritDoc} */
@Override
public void removeStartingWindow(IBinder appToken, View window) {
- if (DEBUG_STARTING_WINDOW) {
- RuntimeException e = new RuntimeException("here");
- e.fillInStackTrace();
- Log.v(TAG, "Removing starting window for " + appToken + ": " + window, e);
- }
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing starting window for " + appToken + ": "
+ + window + " Callers=" + Debug.getCallers(4));
if (window != null) {
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
@@ -2299,24 +2305,19 @@
boolean goingToNotificationShade) {
if (goingToNotificationShade) {
return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in);
- } else if (onWallpaper) {
- Animation a = AnimationUtils.loadAnimation(mContext,
- R.anim.lock_screen_behind_enter_wallpaper);
- AnimationSet set = (AnimationSet) a;
-
- // TODO: Use XML interpolators when we have log interpolators available in XML.
- set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator);
- set.getAnimations().get(1).setInterpolator(mLogDecelerateInterpolator);
- return set;
- } else {
- Animation a = AnimationUtils.loadAnimation(mContext,
- R.anim.lock_screen_behind_enter);
- AnimationSet set = (AnimationSet) a;
-
- // TODO: Use XML interpolators when we have log interpolators available in XML.
- set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator);
- return set;
}
+
+ AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(mContext, onWallpaper ?
+ R.anim.lock_screen_behind_enter_wallpaper :
+ R.anim.lock_screen_behind_enter);
+
+ // TODO: Use XML interpolators when we have log interpolators available in XML.
+ final List<Animation> animations = set.getAnimations();
+ for (int i = animations.size() - 1; i >= 0; --i) {
+ animations.get(i).setInterpolator(mLogDecelerateInterpolator);
+ }
+
+ return set;
}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 395e365..bb91a14 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -115,10 +115,10 @@
@Override
public boolean clearScores() {
- // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETWORKS) should
- // be allowed to flush all scores.
+ // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
+ // should be allowed to flush all scores.
if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
- mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) ==
+ mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
PackageManager.PERMISSION_GRANTED) {
clearInternal();
return true;
@@ -130,16 +130,16 @@
@Override
public boolean setActiveScorer(String packageName) {
- mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
+ mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
return setScorerInternal(packageName);
}
@Override
public void disableScoring() {
- // Only the active scorer or the system (who can broadcast BROADCAST_SCORE_NETOWRKS) should
- // be allowed to disable scoring.
+ // Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
+ // should be allowed to disable scoring.
if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
- mContext.checkCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS) ==
+ mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
PackageManager.PERMISSION_GRANTED) {
// The return value is discarded here because at this point, the call should always
// succeed. The only reason for failure is if the new package is not a valid scorer, but
@@ -188,7 +188,7 @@
@Override
public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
- mContext.enforceCallingOrSelfPermission(permission.BROADCAST_SCORE_NETWORKS, TAG);
+ mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
synchronized (mScoreCaches) {
if (mScoreCaches.containsKey(networkType)) {
throw new IllegalArgumentException(
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index fc7b5a9..3ff9ff4 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -553,20 +553,22 @@
private class DowntimeCallback implements DowntimeConditionProvider.Callback {
@Override
- public void onDowntimeChanged(boolean inDowntime) {
+ public void onDowntimeChanged(int downtimeMode) {
final int mode = mZenModeHelper.getZenMode();
final ZenModeConfig config = mZenModeHelper.getConfig();
- // enter downtime
- if (inDowntime && mode == Global.ZEN_MODE_OFF && config != null) {
+ final boolean inDowntime = downtimeMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ || downtimeMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+ final boolean downtimeCurrent = mDowntime.isDowntimeCondition(mExitCondition);
+ // enter downtime, or update mode if reconfigured during an active downtime
+ if (inDowntime && (mode == Global.ZEN_MODE_OFF || downtimeCurrent) && config != null) {
final Condition condition = mDowntime.createCondition(config.toDowntimeInfo(),
Condition.STATE_TRUE);
- mZenModeHelper.setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, "downtimeEnter");
+ mZenModeHelper.setZenMode(downtimeMode, "downtimeEnter");
setZenModeCondition(condition, "downtime");
}
// exit downtime
- if (!inDowntime && mDowntime.isDowntimeCondition(mExitCondition)
- && (mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
- || mode == Global.ZEN_MODE_NO_INTERRUPTIONS)) {
+ if (!inDowntime && downtimeCurrent && (mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ || mode == Global.ZEN_MODE_NO_INTERRUPTIONS)) {
mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "downtimeExit");
}
}
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
index 2a4b718..881c9ad 100644
--- a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
+++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
+import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
import android.service.notification.IConditionProvider;
@@ -64,7 +65,7 @@
private final ArraySet<Integer> mDays = new ArraySet<Integer>();
private boolean mConnected;
- private boolean mInDowntime;
+ private int mDowntimeMode;
private ZenModeConfig mConfig;
private Callback mCallback;
@@ -75,7 +76,7 @@
public void dump(PrintWriter pw, DumpFilter filter) {
pw.println(" DowntimeConditionProvider:");
pw.print(" mConnected="); pw.println(mConnected);
- pw.print(" mInDowntime="); pw.println(mInDowntime);
+ pw.print(" mDowntimeMode="); pw.println(Global.zenModeToString(mDowntimeMode));
}
public void attachBase(Context base) {
@@ -113,7 +114,7 @@
public void onRequestConditions(int relevance) {
if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
if ((relevance & Condition.FLAG_RELEVANT_NOW) != 0) {
- if (mInDowntime && mConfig != null) {
+ if (isInDowntime() && mConfig != null) {
notifyCondition(createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE));
}
}
@@ -124,7 +125,7 @@
if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId);
final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
if (downtime != null && mConfig != null) {
- final int state = mConfig.toDowntimeInfo().equals(downtime) && mInDowntime
+ final int state = mConfig.toDowntimeInfo().equals(downtime) && isInDowntime()
? Condition.STATE_TRUE : Condition.STATE_FALSE;
if (DEBUG) Slog.d(TAG, "notify condition state: " + Condition.stateToString(state));
notifyCondition(createCondition(downtime, state));
@@ -146,7 +147,7 @@
}
public boolean isInDowntime() {
- return mInDowntime;
+ return mDowntimeMode != Global.ZEN_MODE_OFF;
}
public Condition createCondition(DowntimeInfo downtime, int state) {
@@ -182,15 +183,18 @@
}
}
- private boolean isInDowntime(long time) {
- if (mConfig == null || mDays.size() == 0) return false;
+ private int computeDowntimeMode(long time) {
+ if (mConfig == null || mDays.size() == 0) return Global.ZEN_MODE_OFF;
final long start = getTime(time, mConfig.sleepStartHour, mConfig.sleepStartMinute);
long end = getTime(time, mConfig.sleepEndHour, mConfig.sleepEndMinute);
- if (start == end) return false;
+ if (start == end) return Global.ZEN_MODE_OFF;
if (end < start) {
end = addDays(end, 1);
}
- return isInDowntime(-1, time, start, end) || isInDowntime(0, time, start, end);
+ final boolean inDowntime = isInDowntime(-1, time, start, end)
+ || isInDowntime(0, time, start, end);
+ return inDowntime ? (mConfig.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
+ : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) : Global.ZEN_MODE_OFF;
}
private boolean isInDowntime(int daysOffset, long time, long start, long end) {
@@ -202,18 +206,18 @@
}
private void reevaluateDowntime() {
- final boolean inDowntime = isInDowntime(System.currentTimeMillis());
- if (DEBUG) Slog.d(TAG, "inDowntime=" + inDowntime);
- if (inDowntime == mInDowntime) return;
- Slog.i(TAG, (inDowntime ? "Entering" : "Exiting" ) + " downtime");
- mInDowntime = inDowntime;
- ZenLog.traceDowntime(mInDowntime, getDayOfWeek(System.currentTimeMillis()), mDays);
+ final int downtimeMode = computeDowntimeMode(System.currentTimeMillis());
+ if (DEBUG) Slog.d(TAG, "downtimeMode=" + downtimeMode);
+ if (downtimeMode == mDowntimeMode) return;
+ mDowntimeMode = downtimeMode;
+ Slog.i(TAG, (isInDowntime() ? "Entering" : "Exiting" ) + " downtime");
+ ZenLog.traceDowntime(mDowntimeMode, getDayOfWeek(System.currentTimeMillis()), mDays);
fireDowntimeChanged();
}
private void fireDowntimeChanged() {
if (mCallback != null) {
- mCallback.onDowntimeChanged(mInDowntime);
+ mCallback.onDowntimeChanged(mDowntimeMode);
}
}
@@ -256,7 +260,10 @@
time = addDays(time, 1);
}
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
- new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
+ new Intent(action)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .putExtra(EXTRA_TIME, time),
+ PendingIntent.FLAG_UPDATE_CURRENT);
alarms.cancel(pendingIntent);
if (mConfig.sleepMode != null) {
if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
@@ -290,6 +297,6 @@
};
public interface Callback {
- void onDowntimeChanged(boolean inDowntime);
+ void onDowntimeChanged(int downtimeMode);
}
}
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index e0b83de..1a3da79 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -75,8 +75,8 @@
append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode));
}
- public static void traceDowntime(boolean inDowntime, int day, ArraySet<Integer> days) {
- append(TYPE_DOWNTIME, inDowntime + ",day=" + day + ",days=" + days);
+ public static void traceDowntime(int downtimeMode, int day, ArraySet<Integer> days) {
+ append(TYPE_DOWNTIME, zenModeToString(downtimeMode) + ",day=" + day + ",days=" + days);
}
public static void traceSetZenMode(int mode, String reason) {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index bfc7659..eeb007c 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -691,8 +691,10 @@
throw new RuntimeException("Invalid thumbnail transition state");
}
- return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
- THUMBNAIL_APP_TRANSITION_DURATION, mThumbnailFastOutSlowInInterpolator);
+ int duration = Math.max(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION,
+ THUMBNAIL_APP_TRANSITION_DURATION);
+ return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
+ mThumbnailFastOutSlowInInterpolator);
}
/**
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 69c9144..bf96ea5 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -58,7 +58,9 @@
// the state changes.
boolean allDrawn;
- // Special surface for thumbnail animation.
+ // Special surface for thumbnail animation. If deferThumbnailDestruction is enabled, then we
+ // will make sure that the thumbnail is destroyed after the other surface is completed. This
+ // requires that the duration of the two animations are the same.
SurfaceControl thumbnail;
int thumbnailTransactionSeq;
int thumbnailX;
@@ -68,13 +70,12 @@
Animation thumbnailAnimation;
final Transformation thumbnailTransformation = new Transformation();
// This flag indicates that the destruction of the thumbnail surface is synchronized with
- // another animation, so do not pre-emptively destroy the thumbnail surface when the animation
- // completes
+ // another animation, so defer the destruction of this thumbnail surface for a single frame
+ // after the secondary animation completes.
boolean deferThumbnailDestruction;
- // This is the thumbnail surface that has been bestowed upon this animator, and when the
- // surface for this animator's animation is complete, we will destroy the thumbnail surface
- // as well. Do not animate or do anything with this surface.
- SurfaceControl deferredThumbnail;
+ // This flag is set if the animator has deferThumbnailDestruction set and has reached the final
+ // frame of animation. It will extend the animation by one frame and then clean up afterwards.
+ boolean deferFinalFrameCleanup;
/** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
@@ -134,9 +135,7 @@
animation = null;
animating = true;
}
- if (!deferThumbnailDestruction) {
- clearThumbnail();
- }
+ clearThumbnail();
if (mAppToken.deferClearAllDrawn) {
mAppToken.allDrawn = false;
mAppToken.deferClearAllDrawn = false;
@@ -148,13 +147,7 @@
thumbnail.destroy();
thumbnail = null;
}
- }
-
- public void clearDeferredThumbnail() {
- if (deferredThumbnail != null) {
- deferredThumbnail.destroy();
- deferredThumbnail = null;
- }
+ deferThumbnailDestruction = false;
}
void updateLayers() {
@@ -223,19 +216,26 @@
return false;
}
transformation.clear();
- final boolean more = animation.getTransformation(currentTime, transformation);
- if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
- TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation);
- if (!more) {
- animation = null;
- if (!deferThumbnailDestruction) {
+ boolean hasMoreFrames = animation.getTransformation(currentTime, transformation);
+ if (!hasMoreFrames) {
+ if (deferThumbnailDestruction && !deferFinalFrameCleanup) {
+ // We are deferring the thumbnail destruction, so extend the animation for one more
+ // (dummy) frame before we clean up
+ deferFinalFrameCleanup = true;
+ hasMoreFrames = true;
+ } else {
+ if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
+ TAG, "Stepped animation in " + mAppToken + ": more=" + hasMoreFrames +
+ ", xform=" + transformation);
+ deferFinalFrameCleanup = false;
+ animation = null;
clearThumbnail();
+ if (WindowManagerService.DEBUG_ANIM) Slog.v(
+ TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
}
- if (WindowManagerService.DEBUG_ANIM) Slog.v(
- TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
}
- hasTransformation = more;
- return more;
+ hasTransformation = hasMoreFrames;
+ return hasMoreFrames;
}
// This must be called while inside a transaction.
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 61ea1e8..8d93141 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -91,6 +91,9 @@
boolean mKeyguardGoingAwayToNotificationShade;
boolean mKeyguardGoingAwayDisableWindowAnimations;
+ /** Use one animation for all entering activities after keyguard is dismissed. */
+ Animation mPostKeyguardExitAnimation;
+
// forceHiding states.
static final int KEYGUARD_NOT_SHOWN = 0;
static final int KEYGUARD_ANIMATING_IN = 1;
@@ -220,9 +223,6 @@
++mAnimTransactionSequence;
final WindowList windows = mService.getWindowListLocked(displayId);
- ArrayList<WindowStateAnimator> unForceHiding = null;
- boolean wallpaperInUnForceHiding = false;
- WindowState wallpaper = null;
if (mKeyguardGoingAway) {
for (int i = windows.size() - 1; i >= 0; i--) {
@@ -261,6 +261,9 @@
final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
null : winShowWhenLocked.mAppToken;
+ boolean wallpaperInUnForceHiding = false;
+ ArrayList<WindowStateAnimator> unForceHiding = null;
+ WindowState wallpaper = null;
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState win = windows.get(i);
WindowStateAnimator winAnimator = win.mWinAnimator;
@@ -327,40 +330,53 @@
} else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
final boolean hideWhenLocked = !((win.mIsImWindow && showImeOverKeyguard) ||
(appShowWhenLocked != null && appShowWhenLocked == win.mAppToken));
- final boolean changed;
if (((mForceHiding == KEYGUARD_ANIMATING_IN)
&& (!winAnimator.isAnimating() || hideWhenLocked))
|| ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked)) {
- changed = win.hideLw(false, false);
- if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
- && changed) Slog.v(TAG, "Now policy hidden: " + win);
+ if (!win.hideLw(false, false)) {
+ // Was already hidden
+ continue;
+ }
+ if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+ "Now policy hidden: " + win);
} else {
- changed = win.showLw(false, false);
- if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
- && changed) Slog.v(TAG, "Now policy shown: " + win);
- if (changed) {
- if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
- && win.isVisibleNow() /*w.isReadyForDisplay()*/) {
- if (unForceHiding == null) {
- unForceHiding = new ArrayList<WindowStateAnimator>();
- }
- unForceHiding.add(winAnimator);
- if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
- wallpaperInUnForceHiding = true;
- }
+ if (!win.showLw(false, false)) {
+ // Was already showing.
+ continue;
+ }
+ final boolean visibleNow = win.isVisibleNow();
+ if (!visibleNow) {
+ // Couldn't really show, must showLw() again when win becomes visible.
+ win.hideLw(false, false);
+ continue;
+ }
+ if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+ "Now policy shown: " + win);
+ if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
+ if (unForceHiding == null) {
+ unForceHiding = new ArrayList<>();
}
- final WindowState currentFocus = mService.mCurrentFocus;
- if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
- // We are showing on to of the current
- // focus, so re-evaluate focus to make
- // sure it is correct.
- if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
- "updateWindowsLocked: setting mFocusMayChange true");
- mService.mFocusMayChange = true;
+ unForceHiding.add(winAnimator);
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
+ wallpaperInUnForceHiding = true;
}
+ } else if (mPostKeyguardExitAnimation != null) {
+ // We're already in the middle of an animation. Use the existing
+ // animation to bring in this window.
+ winAnimator.setAnimation(mPostKeyguardExitAnimation);
+ winAnimator.keyguardGoingAwayAnimation = true;
+ }
+ final WindowState currentFocus = mService.mCurrentFocus;
+ if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
+ // We are showing on top of the current
+ // focus, so re-evaluate focus to make
+ // sure it is correct.
+ if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
+ "updateWindowsLocked: setting mFocusMayChange true");
+ mService.mFocusMayChange = true;
}
}
- if (changed && (flags & FLAG_SHOW_WALLPAPER) != 0) {
+ if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
@@ -403,42 +419,44 @@
// If we have windows that are being show due to them no longer
// being force-hidden, apply the appropriate animation to them.
if (unForceHiding != null) {
- boolean startKeyguardExit = true;
- for (int i=unForceHiding.size()-1; i>=0; i--) {
- Animation a = null;
- if (!mKeyguardGoingAwayDisableWindowAnimations) {
- a = mPolicy.createForceHideEnterAnimation(wallpaperInUnForceHiding,
- mKeyguardGoingAwayToNotificationShade);
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim=" + a
- + " for win=" + unForceHiding.get(i));
- } else {
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for win="
- + unForceHiding.get(i));
- }
- if (a != null) {
+ // This only happens the first time that we detect the keyguard is animating out.
+ if (mKeyguardGoingAwayDisableWindowAnimations) {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for windows");
+ } else {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim for windows");
+ mPostKeyguardExitAnimation = mPolicy.createForceHideEnterAnimation(
+ wallpaperInUnForceHiding, mKeyguardGoingAwayToNotificationShade);
+ }
+ if (mPostKeyguardExitAnimation != null) {
+ for (int i=unForceHiding.size()-1; i>=0; i--) {
final WindowStateAnimator winAnimator = unForceHiding.get(i);
- winAnimator.setAnimation(a);
+ winAnimator.setAnimation(mPostKeyguardExitAnimation);
winAnimator.keyguardGoingAwayAnimation = true;
- if (startKeyguardExit && mKeyguardGoingAway) {
- // Do one time only.
- mPolicy.startKeyguardExitAnimation(mCurrentTime + a.getStartOffset(),
- a.getDuration());
- mKeyguardGoingAway = false;
- startKeyguardExit = false;
- }
}
}
+ }
- // Wallpaper is going away in un-force-hide motion, animate it as well.
- if (!wallpaperInUnForceHiding && wallpaper != null
- && !mKeyguardGoingAwayDisableWindowAnimations) {
- if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
- Animation a = mPolicy.createForceHideWallpaperExitAnimation(
- mKeyguardGoingAwayToNotificationShade);
- if (a != null) {
- WindowStateAnimator animator = wallpaper.mWinAnimator;
- animator.setAnimation(a);
- }
+ if (mPostKeyguardExitAnimation != null) {
+ // We're in the midst of a keyguard exit animation.
+ if (mKeyguardGoingAway) {
+ mPolicy.startKeyguardExitAnimation(mCurrentTime +
+ mPostKeyguardExitAnimation.getStartOffset(),
+ mPostKeyguardExitAnimation.getDuration());
+ mKeyguardGoingAway = false;
+ } else if (mPostKeyguardExitAnimation.hasEnded()) {
+ // Done with the animation, reset.
+ mPostKeyguardExitAnimation = null;
+ }
+ }
+
+ // Wallpaper is going away in un-force-hide motion, animate it as well.
+ if (!wallpaperInUnForceHiding && wallpaper != null
+ && !mKeyguardGoingAwayDisableWindowAnimations) {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
+ Animation a = mPolicy.createForceHideWallpaperExitAnimation(
+ mKeyguardGoingAwayToNotificationShade);
+ if (a != null) {
+ wallpaper.mWinAnimator.setAnimation(a);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b4e2778..968b35c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -9244,12 +9244,6 @@
topClosingLayer);
openingAppAnimator.deferThumbnailDestruction =
!mAppTransition.isNextThumbnailTransitionScaleUp();
- if (openingAppAnimator.deferThumbnailDestruction) {
- if (closingAppAnimator != null &&
- closingAppAnimator.animation != null) {
- closingAppAnimator.deferredThumbnail = surfaceControl;
- }
- }
} else {
anim = mAppTransition.createThumbnailScaleAnimationLocked(
displayInfo.appWidth, displayInfo.appHeight, transit);
@@ -9783,7 +9777,7 @@
if (!w.isDrawnLw()) {
Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
+ " pv=" + w.mPolicyVisibility
- + " mDrawState=" + winAnimator.mDrawState
+ + " mDrawState=" + winAnimator.drawStateToString()
+ " ah=" + w.mAttachedHidden
+ " th=" + atoken.hiddenRequested
+ " a=" + winAnimator.mAnimating);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index fc3f2c2..1dadb17 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -167,14 +167,14 @@
private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- static String drawStateToString(int state) {
- switch (state) {
+ String drawStateToString() {
+ switch (mDrawState) {
case NO_SURFACE: return "NO_SURFACE";
case DRAW_PENDING: return "DRAW_PENDING";
case COMMIT_DRAW_PENDING: return "COMMIT_DRAW_PENDING";
case READY_TO_SHOW: return "READY_TO_SHOW";
case HAS_DRAWN: return "HAS_DRAWN";
- default: return Integer.toString(state);
+ default: return Integer.toString(mDrawState);
}
}
int mDrawState;
@@ -489,7 +489,7 @@
if (DEBUG_STARTING_WINDOW &&
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState="
- + drawStateToString(mDrawState));
+ + drawStateToString());
}
if (mDrawState == DRAW_PENDING) {
if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
@@ -510,18 +510,17 @@
if (DEBUG_STARTING_WINDOW &&
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
- + drawStateToString(mDrawState));
+ + drawStateToString());
}
- if (mDrawState != COMMIT_DRAW_PENDING) {
+ if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) {
Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurfaceControl);
}
mDrawState = READY_TO_SHOW;
- final boolean starting = mWin.mAttrs.type == TYPE_APPLICATION_STARTING;
final AppWindowToken atoken = mWin.mAppToken;
- if (atoken == null || atoken.allDrawn || starting) {
+ if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
performShowLocked();
}
return true;
@@ -976,11 +975,6 @@
mWin.mHasSurface = false;
mDrawState = NO_SURFACE;
}
-
- // Destroy any deferred thumbnail surfaces
- if (mAppAnimator != null) {
- mAppAnimator.clearDeferredThumbnail();
- }
}
void destroyDeferredSurfaceLocked() {
@@ -1868,7 +1862,7 @@
if (dumpAll) {
pw.print(prefix); pw.print("mSurface="); pw.println(mSurfaceControl);
pw.print(prefix); pw.print("mDrawState=");
- pw.print(drawStateToString(mDrawState));
+ pw.print(drawStateToString());
pw.print(" mLastHidden="); pw.println(mLastHidden);
}
pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown);
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index f447462..848d9a1 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -794,4 +794,23 @@
return a.diff(b) == axisMask;
}
+bool isDensityOnly(const ResTable_config& config) {
+ if (config.density == ResTable_config::DENSITY_NONE) {
+ return false;
+ }
+
+ if (config.density == ResTable_config::DENSITY_ANY) {
+ if (config.sdkVersion != SDK_L) {
+ // Someone modified the sdkVersion from the default, this is not safe to assume.
+ return false;
+ }
+ } else if (config.sdkVersion != SDK_DONUT) {
+ return false;
+ }
+
+ const uint32_t mask = ResTable_config::CONFIG_DENSITY | ResTable_config::CONFIG_VERSION;
+ const ConfigDescription nullConfig;
+ return (nullConfig.diff(config) & ~mask) == 0;
+}
+
} // namespace AaptConfig
diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h
index 2963539..f73a5081 100644
--- a/tools/aapt/AaptConfig.h
+++ b/tools/aapt/AaptConfig.h
@@ -80,6 +80,12 @@
*/
bool isSameExcept(const android::ResTable_config& a, const android::ResTable_config& b, int configMask);
+/**
+ * Returns true if the configuration only has the density specified. In the case
+ * of 'anydpi', the version is ignored.
+ */
+bool isDensityOnly(const android::ResTable_config& config);
+
} // namespace AaptConfig
#endif // __AAPT_CONFIG_H
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index b9bd03a..0d8db13 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -4,6 +4,7 @@
// Build resource files from raw assets.
//
#include "AaptAssets.h"
+#include "AaptUtil.h"
#include "AaptXml.h"
#include "CacheUpdater.h"
#include "CrunchCache.h"
@@ -13,9 +14,12 @@
#include "Main.h"
#include "ResourceTable.h"
#include "StringPool.h"
+#include "Symbol.h"
#include "WorkQueue.h"
#include "XMLNode.h"
+#include <algorithm>
+
#if HAVE_PRINTF_ZD
# define ZD "%zd"
# define ZD_TYPE ssize_t
@@ -1550,6 +1554,7 @@
// Re-flatten because we may have added new resource IDs
// --------------------------------------------------------------
+
ResTable finalResTable;
sp<AaptFile> resFile;
@@ -1560,6 +1565,13 @@
return err;
}
+ KeyedVector<Symbol, Vector<SymbolDefinition> > densityVaryingResources;
+ if (builder->getSplits().size() > 1) {
+ // Only look for density varying resources if we're generating
+ // splits.
+ table.getDensityVaryingResources(densityVaryingResources);
+ }
+
Vector<sp<ApkSplit> >& splits = builder->getSplits();
const size_t numSplits = splits.size();
for (size_t i = 0; i < numSplits; i++) {
@@ -1583,6 +1595,63 @@
return err;
}
} else {
+ ResTable resTable;
+ err = resTable.add(flattenedTable->getData(), flattenedTable->getSize());
+ if (err != NO_ERROR) {
+ fprintf(stderr, "Generated resource table for split '%s' is corrupt.\n",
+ split->getPrintableName().string());
+ return err;
+ }
+
+ bool hasError = false;
+ const std::set<ConfigDescription>& splitConfigs = split->getConfigs();
+ for (std::set<ConfigDescription>::const_iterator iter = splitConfigs.begin();
+ iter != splitConfigs.end();
+ ++iter) {
+ const ConfigDescription& config = *iter;
+ if (AaptConfig::isDensityOnly(config)) {
+ // Each density only split must contain all
+ // density only resources.
+ Res_value val;
+ resTable.setParameters(&config);
+ const size_t densityVaryingResourceCount = densityVaryingResources.size();
+ for (size_t k = 0; k < densityVaryingResourceCount; k++) {
+ const Symbol& symbol = densityVaryingResources.keyAt(k);
+ ssize_t block = resTable.getResource(symbol.id, &val, true);
+ if (block < 0) {
+ // Maybe it's in the base?
+ finalResTable.setParameters(&config);
+ block = finalResTable.getResource(symbol.id, &val, true);
+ }
+
+ if (block < 0) {
+ hasError = true;
+ SourcePos().error("%s has no definition for density split '%s'",
+ symbol.toString().string(), config.toString().string());
+
+ if (bundle->getVerbose()) {
+ const Vector<SymbolDefinition>& defs = densityVaryingResources[k];
+ const size_t defCount = std::min(size_t(5), defs.size());
+ for (size_t d = 0; d < defCount; d++) {
+ const SymbolDefinition& def = defs[d];
+ def.source.error("%s has definition for %s",
+ symbol.toString().string(), def.config.toString().string());
+ }
+
+ if (defCount < defs.size()) {
+ SourcePos().error("and %d more ...", (int) (defs.size() - defCount));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (hasError) {
+ return UNKNOWN_ERROR;
+ }
+
+ // Generate the AndroidManifest for this split.
sp<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"),
AaptGroupEntry(), String8());
err = generateAndroidManifestForSplit(bundle, assets, split,
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 0f94f85..beff604 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -6,6 +6,7 @@
#include "ResourceTable.h"
+#include "AaptUtil.h"
#include "XMLNode.h"
#include "ResourceFilter.h"
#include "ResourceIdCache.h"
@@ -4486,3 +4487,34 @@
return NO_ERROR;
}
+
+void ResourceTable::getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources) {
+ const ConfigDescription nullConfig;
+
+ const size_t packageCount = mOrderedPackages.size();
+ for (size_t p = 0; p < packageCount; p++) {
+ const Vector<sp<Type> >& types = mOrderedPackages[p]->getOrderedTypes();
+ const size_t typeCount = types.size();
+ for (size_t t = 0; t < typeCount; t++) {
+ const Vector<sp<ConfigList> >& configs = types[t]->getOrderedConfigs();
+ const size_t configCount = configs.size();
+ for (size_t c = 0; c < configCount; c++) {
+ const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries = configs[c]->getEntries();
+ const size_t configEntryCount = configEntries.size();
+ for (size_t ce = 0; ce < configEntryCount; ce++) {
+ const ConfigDescription& config = configEntries.keyAt(ce);
+ if (AaptConfig::isDensityOnly(config)) {
+ // This configuration only varies with regards to density.
+ const Symbol symbol(mOrderedPackages[p]->getName(),
+ types[t]->getName(),
+ configs[c]->getName(),
+ getResId(mOrderedPackages[p], types[t], configs[c]->getEntryIndex()));
+
+ const sp<Entry>& entry = configEntries.valueAt(ce);
+ AaptUtil::appendValue(resources, symbol, SymbolDefinition(symbol, config, entry->getPos()));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index eac5dd3..db392c89 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -7,15 +7,16 @@
#ifndef RESOURCE_TABLE_H
#define RESOURCE_TABLE_H
-#include "ConfigDescription.h"
-#include "StringPool.h"
-#include "SourcePos.h"
-#include "ResourceFilter.h"
-
#include <map>
#include <queue>
#include <set>
+#include "ConfigDescription.h"
+#include "ResourceFilter.h"
+#include "SourcePos.h"
+#include "StringPool.h"
+#include "Symbol.h"
+
using namespace std;
class XMLNode;
@@ -543,6 +544,8 @@
DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping;
};
+ void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);
+
private:
void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
sp<Package> getPackage(const String16& package);
diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp
index ae25047..3864320 100644
--- a/tools/aapt/SourcePos.cpp
+++ b/tools/aapt/SourcePos.cpp
@@ -141,6 +141,12 @@
}
bool
+SourcePos::operator<(const SourcePos& rhs) const
+{
+ return (file < rhs.file) || (line < rhs.line);
+}
+
+bool
SourcePos::hasErrors()
{
return g_errors.size() > 0;
diff --git a/tools/aapt/SourcePos.h b/tools/aapt/SourcePos.h
index 4ce817f..13cfb9d 100644
--- a/tools/aapt/SourcePos.h
+++ b/tools/aapt/SourcePos.h
@@ -21,6 +21,8 @@
void warning(const char* fmt, ...) const;
void printf(const char* fmt, ...) const;
+ bool operator<(const SourcePos& rhs) const;
+
static bool hasErrors();
static void printErrors(FILE* to);
};
diff --git a/tools/aapt/Symbol.h b/tools/aapt/Symbol.h
new file mode 100644
index 0000000..e157541
--- /dev/null
+++ b/tools/aapt/Symbol.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_SYMBOL_H
+#define AAPT_SYMBOL_H
+
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+#include "ConfigDescription.h"
+#include "SourcePos.h"
+
+/**
+ * A resource symbol, not attached to any configuration or context.
+ */
+struct Symbol {
+ inline Symbol();
+ inline Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i);
+ inline android::String8 toString() const;
+ inline bool operator<(const Symbol& rhs) const;
+
+ android::String16 package;
+ android::String16 type;
+ android::String16 name;
+ uint32_t id;
+
+};
+
+/**
+ * A specific defintion of a symbol, defined with a configuration and a definition site.
+ */
+struct SymbolDefinition {
+ inline SymbolDefinition();
+ inline SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src);
+ inline bool operator<(const SymbolDefinition& rhs) const;
+
+ Symbol symbol;
+ ConfigDescription config;
+ SourcePos source;
+};
+
+//
+// Implementations
+//
+
+Symbol::Symbol() {
+}
+
+Symbol::Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i)
+ : package(p)
+ , type(t)
+ , name(n)
+ , id(i) {
+}
+
+android::String8 Symbol::toString() const {
+ return android::String8::format("%s:%s/%s (0x%08x)",
+ android::String8(package).string(),
+ android::String8(type).string(),
+ android::String8(name).string(),
+ (int) id);
+}
+
+bool Symbol::operator<(const Symbol& rhs) const {
+ return (package < rhs.package) || (type < rhs.type) || (name < rhs.name) || (id < rhs.id);
+}
+
+SymbolDefinition::SymbolDefinition() {
+}
+
+SymbolDefinition::SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src)
+ : symbol(s)
+ , config(c)
+ , source(src) {
+}
+
+bool SymbolDefinition::operator<(const SymbolDefinition& rhs) const {
+ return (symbol < rhs.symbol) || (config < rhs.config) || (source < rhs.source);
+}
+
+#endif // AAPT_SYMBOL_H
+