Merge "Fix number picker vertical scroll computations" into klp-dev
diff --git a/api/current.txt b/api/current.txt
index d31a38dc..973a9fdc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -639,13 +639,13 @@
field public static final int keyPreviewHeight = 16843321; // 0x1010239
field public static final int keyPreviewLayout = 16843319; // 0x1010237
field public static final int keyPreviewOffset = 16843320; // 0x1010238
+ field public static final int keySet = 16843739; // 0x10103db
field public static final int keyTextColor = 16843318; // 0x1010236
field public static final int keyTextSize = 16843316; // 0x1010234
field public static final int keyWidth = 16843325; // 0x101023d
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
field public static final int keycode = 16842949; // 0x10100c5
- field public static final int keyset = 16843739; // 0x10103db
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
field public static final int labelFor = 16843718; // 0x10103c6
@@ -6522,6 +6522,7 @@
field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
field public static final int FLAG_PERSIST_GRANT_URI_PERMISSION = 64; // 0x40
field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
+ field public static final int FLAG_RECEIVER_NO_ABORT = 134217728; // 0x8000000
field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -19178,7 +19179,7 @@
field public static final android.print.PrintAttributes.MediaSize NA_LETTER;
field public static final android.print.PrintAttributes.MediaSize NA_MONARCH;
field public static final android.print.PrintAttributes.MediaSize NA_QUARTO;
- field public static final android.print.PrintAttributes.MediaSize NA_TBLOID;
+ field public static final android.print.PrintAttributes.MediaSize NA_TABLOID;
field public static final android.print.PrintAttributes.MediaSize OM_DAI_PA_KAI;
field public static final android.print.PrintAttributes.MediaSize OM_JUURO_KU_KAI;
field public static final android.print.PrintAttributes.MediaSize OM_PA_KAI;
@@ -30010,7 +30011,7 @@
method public deprecated void onConsoleMessage(java.lang.String, int, java.lang.String);
method public boolean onConsoleMessage(android.webkit.ConsoleMessage);
method public boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
- method public void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
+ method public deprecated void onExceededDatabaseQuota(java.lang.String, java.lang.String, long, long, long, android.webkit.WebStorage.QuotaUpdater);
method public void onGeolocationPermissionsHidePrompt();
method public void onGeolocationPermissionsShowPrompt(java.lang.String, android.webkit.GeolocationPermissions.Callback);
method public void onHideCustomView();
@@ -30020,7 +30021,7 @@
method public boolean onJsPrompt(android.webkit.WebView, java.lang.String, java.lang.String, java.lang.String, android.webkit.JsPromptResult);
method public deprecated boolean onJsTimeout();
method public void onProgressChanged(android.webkit.WebView, int);
- method public void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
+ method public deprecated void onReachedMaxAppCacheSize(long, long, android.webkit.WebStorage.QuotaUpdater);
method public void onReceivedIcon(android.webkit.WebView, android.graphics.Bitmap);
method public void onReceivedTitle(android.webkit.WebView, java.lang.String);
method public void onReceivedTouchIconUrl(android.webkit.WebView, java.lang.String, boolean);
@@ -30076,12 +30077,12 @@
method public int getCacheMode();
method public synchronized java.lang.String getCursiveFontFamily();
method public synchronized boolean getDatabaseEnabled();
- method public synchronized java.lang.String getDatabasePath();
+ method public deprecated synchronized java.lang.String getDatabasePath();
method public synchronized int getDefaultFixedFontSize();
method public synchronized int getDefaultFontSize();
method public synchronized java.lang.String getDefaultTextEncodingName();
method public static java.lang.String getDefaultUserAgent(android.content.Context);
- method public android.webkit.WebSettings.ZoomDensity getDefaultZoom();
+ method public deprecated android.webkit.WebSettings.ZoomDensity getDefaultZoom();
method public boolean getDisplayZoomControls();
method public synchronized boolean getDomStorageEnabled();
method public synchronized java.lang.String getFantasyFontFamily();
@@ -30118,11 +30119,11 @@
method public void setCacheMode(int);
method public synchronized void setCursiveFontFamily(java.lang.String);
method public synchronized void setDatabaseEnabled(boolean);
- method public synchronized void setDatabasePath(java.lang.String);
+ method public deprecated synchronized void setDatabasePath(java.lang.String);
method public synchronized void setDefaultFixedFontSize(int);
method public synchronized void setDefaultFontSize(int);
method public synchronized void setDefaultTextEncodingName(java.lang.String);
- method public void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
+ method public deprecated void setDefaultZoom(android.webkit.WebSettings.ZoomDensity);
method public void setDisplayZoomControls(boolean);
method public synchronized void setDomStorageEnabled(boolean);
method public deprecated void setEnableSmoothTransition(boolean);
@@ -30165,9 +30166,10 @@
public static final class WebSettings.LayoutAlgorithm extends java.lang.Enum {
method public static android.webkit.WebSettings.LayoutAlgorithm valueOf(java.lang.String);
method public static final android.webkit.WebSettings.LayoutAlgorithm[] values();
- enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
+ enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm NARROW_COLUMNS;
enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm NORMAL;
enum_constant public static final deprecated android.webkit.WebSettings.LayoutAlgorithm SINGLE_COLUMN;
+ enum_constant public static final android.webkit.WebSettings.LayoutAlgorithm TEXT_AUTOSIZING;
}
public static final class WebSettings.PluginState extends java.lang.Enum {
@@ -30220,7 +30222,7 @@
method public long getUsage();
}
- public static abstract interface WebStorage.QuotaUpdater {
+ public static abstract deprecated interface WebStorage.QuotaUpdater {
method public abstract void updateQuota(long);
}
@@ -30248,7 +30250,7 @@
method public boolean canGoForward();
method public deprecated boolean canZoomIn();
method public deprecated boolean canZoomOut();
- method public android.graphics.Picture capturePicture();
+ method public deprecated android.graphics.Picture capturePicture();
method public void clearCache(boolean);
method public void clearFormData();
method public void clearHistory();
@@ -30265,7 +30267,7 @@
method public void findAllAsync(java.lang.String);
method public void findNext(boolean);
method public void flingScroll(int, int);
- method public void freeMemory();
+ method public deprecated void freeMemory();
method public android.net.http.SslCertificate getCertificate();
method public int getContentHeight();
method public android.graphics.Bitmap getFavicon();
@@ -31610,6 +31612,8 @@
ctor public NumberPicker(android.content.Context);
ctor public NumberPicker(android.content.Context, android.util.AttributeSet);
ctor public NumberPicker(android.content.Context, android.util.AttributeSet, int);
+ method public int computeVerticalScrollOffset();
+ method public int computeVerticalScrollRange();
method public java.lang.String[] getDisplayedValues();
method public int getMaxValue();
method public int getMinValue();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7925123..dcc6328 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3588,6 +3588,12 @@
*/
public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
/**
+ * If this is an ordered broadcast, don't allow receivers to abort the broadcast.
+ * They can still propagate results through to later receivers, but they can not prevent
+ * later receivers from seeing the broadcast.
+ */
+ public static final int FLAG_RECEIVER_NO_ABORT = 0x08000000;
+ /**
* If set, when sending a broadcast <i>before boot has completed</i> only
* registered receivers will be called -- no BroadcastReceiver components
* will be launched. Sticky intent state will be recorded properly even
@@ -3600,14 +3606,14 @@
*
* @hide
*/
- public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
+ public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x04000000;
/**
* Set when this broadcast is for a boot upgrade, a special mode that
* allows the broadcast to be sent before the system is ready and launches
* the app process with no providers running in it.
* @hide
*/
- public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
+ public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;
/**
* @hide Flags that can't be changed with PendingIntent.
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index efe6b15..e61fe89 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -391,7 +391,7 @@
public static final MediaSize NA_LEDGER =
new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
/** North America Tabloid media size: 11" x 17" (279mm × 432mm) */
- public static final MediaSize NA_TBLOID =
+ public static final MediaSize NA_TABLOID =
new MediaSize("NA_TABLOID", "android",
R.string.mediaSize_na_tabloid, 11000, 17000);
/** North America Index Card 3x5 media size: 3" x 5" (76mm x 127mm) */
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 21b0578..aa57423 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -238,9 +238,10 @@
* @param totalQuota The total quota for all origins, in bytes
* @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
* must be used to inform the WebView of the new quota.
+ * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+ * Management API.
*/
- // Note that the callback must always be executed at some point to ensure
- // that the sleeping WebCore thread is woken up.
+ @Deprecated
public void onExceededDatabaseQuota(String url, String databaseIdentifier,
long quota, long estimatedDatabaseSize, long totalQuota,
WebStorage.QuotaUpdater quotaUpdater) {
@@ -263,9 +264,10 @@
* @param quota the current maximum Application Cache size, in bytes
* @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
* must be used to inform the WebView of the new quota.
+ * @deprecated This method is no longer called; WebView now uses the HTML5 / JavaScript Quota
+ * Management API.
*/
- // Note that the callback must always be executed at some point to ensure
- // that the sleeping WebCore thread is woken up.
+ @Deprecated
public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(quota);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 7a38a16..98ef66e 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -33,14 +33,17 @@
/**
* Enum for controlling the layout of html.
* <ul>
- * <li>NORMAL means no rendering changes.</li>
+ * <li>NORMAL means no rendering changes. This is the recommended choice for maximum
+ * compatibility across different platforms and Android versions.</li>
* <li>SINGLE_COLUMN moves all content into one column that is the width of the
* view.</li>
- * <li>NARROW_COLUMNS makes all columns no wider than the screen if possible.</li>
+ * <li>NARROW_COLUMNS makes all columns no wider than the screen if possible. Only use
+ * this for API levels prior to {@link android.os.Build.VERSION_CODES#KITKAT}.</li>
* <li>TEXT_AUTOSIZING boosts font size of paragraphs based on heuristics to make
* the text readable when viewing a wide-viewport layout in the overview mode.
* It is recommended to enable zoom support {@link #setSupportZoom} when
- * using this mode.</li>
+ * using this mode. Supported from API level
+ * {@link android.os.Build.VERSION_CODES#KITKAT}</li>
* </ul>
*/
// XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
@@ -51,10 +54,11 @@
*/
@Deprecated
SINGLE_COLUMN,
- NARROW_COLUMNS,
/**
- * @hide
+ * @deprecated This algorithm is now obsolete.
*/
+ @Deprecated
+ NARROW_COLUMNS,
TEXT_AUTOSIZING
}
@@ -510,7 +514,10 @@
* and {@link #setUseWideViewPort} can be used.
*
* @param zoom the zoom density
+ * @deprecated This method is no longer supported, see the function documentation for
+ * recommended alternatives.
*/
+ @Deprecated
public void setDefaultZoom(ZoomDensity zoom) {
throw new MustOverrideException();
}
@@ -523,6 +530,7 @@
*
* @return the zoom density
* @see #setDefaultZoom
+ * @deprecated Will only return the default value.
*/
public ZoomDensity getDefaultZoom() {
throw new MustOverrideException();
@@ -1059,10 +1067,13 @@
*
* @param databasePath a path to the directory where databases should be
* saved.
+ * @deprecated Database paths are managed by the implementation and calling this method
+ * will have no effect.
*/
// This will update WebCore when the Sync runs in the C++ side.
// Note that the WebCore Database Tracker only allows the path to be set
// once.
+ @Deprecated
public synchronized void setDatabasePath(String databasePath) {
throw new MustOverrideException();
}
@@ -1161,7 +1172,9 @@
*
* @return the String path to the database storage API databases
* @see #setDatabasePath
+ * @deprecated Database paths are managed by the implementation this method is obsolete.
*/
+ @Deprecated
public synchronized String getDatabasePath() {
throw new MustOverrideException();
}
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 7d9373c..3bfe9cf 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -41,12 +41,9 @@
* See
* {@link WebChromeClient#onExceededDatabaseQuota} and
* {@link WebChromeClient#onReachedMaxAppCacheSize}.
+ * @deprecated This class is obsolete and no longer used.
*/
- // We primarily want this to allow us to call back the sleeping WebCore
- // thread from outside the WebViewCore class (as the native call is
- // private). It is imperative that the setDatabaseQuota method is
- // executed after a decision to either allow or deny new quota is made,
- // otherwise the WebCore thread will remain asleep.
+ @Deprecated
public interface QuotaUpdater {
/**
* Provides a new quota, specified in bytes.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 15331dc..20fb1a7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1058,9 +1058,20 @@
* {@link android.os.Build.VERSION_CODES#HONEYCOMB} and
* {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} inclusive, the
* picture does not include fixed position elements or scrollable divs.
+ * <p>
+ * Note that from {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} the returned picture
+ * should only be drawn into bitmap-backed Canvas - using any other type of Canvas will involve
+ * additional conversion at a cost in memory and performance. Also the
+ * {@link android.graphics.Picture#createFromStream} and
+ * {@link android.graphics.Picture#writeToStream} methods are not supported on the
+ * returned object.
+ *
+ * @deprecated Use {@link #onDraw} to obtain a bitmap snapshot of the WebView, or
+ * {@link #saveWebArchive} to save the content to a file.
*
* @return a picture that captures the current contents of this WebView
*/
+ @Deprecated
public Picture capturePicture() {
checkThread();
if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
@@ -1342,7 +1353,10 @@
/**
* Informs this WebView that memory is low so that it can free any available
* memory.
+ * @deprecated Memory caches are automatically dropped when no longer needed, and in response
+ * to system memory pressure.
*/
+ @Deprecated
public void freeMemory() {
checkThread();
if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 8819237..497c0c6 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -280,6 +280,9 @@
}
void startSelected(int which, boolean always) {
+ if (isFinishing()) {
+ return;
+ }
ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
Intent intent = mAdapter.intentForPosition(which);
onIntentSelected(ri, intent, always);
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 80810d5..b20f5ba 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1821,7 +1821,9 @@
<attr name="value" />
</declare-styleable>
- <attr name="keyset" />
+ <!-- Groups signing keys into a {@code KeySet} for easier reference in
+ other APIs. However, currently no APIs use this. -->
+ <attr name="keySet" />
<declare-styleable name="PublicKey">
<attr name="value" />
</declare-styleable>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c5d4810..ef7f2b7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2058,7 +2058,7 @@
=============================================================== -->
<eat-comment />
- <public type="attr" name="keyset" />
+ <public type="attr" name="keySet" />
<public type="attr" name="targetId" />
<public type="attr" name="fromScene" />
<public type="attr" name="toScene" />
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 2846e61..0d9a386 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -138,7 +138,8 @@
DroidSansHebrew-Regular.ttf \
DroidSansHebrew-Bold.ttf \
DroidSansArmenian.ttf \
- DroidSansGeorgian.ttf
+ DroidSansGeorgian.ttf \
+ AndroidEmoji.ttf
endif # !MINIMAL_FONT
diff --git a/data/fonts/AndroidEmoji.ttf b/data/fonts/AndroidEmoji.ttf
new file mode 100644
index 0000000..98f72e7
--- /dev/null
+++ b/data/fonts/AndroidEmoji.ttf
Binary files differ
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 69db6aa..ede7ef4 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -186,6 +186,11 @@
</family>
<family>
<fileset>
+ <file>AndroidEmoji.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
<file>NotoColorEmoji.ttf</file>
</fileset>
</family>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index a677c4f..05cca13 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -43,6 +43,7 @@
DroidSansMono.ttf \
DroidSansArmenian.ttf \
DroidSansGeorgian.ttf \
+ AndroidEmoji.ttf \
Clockopia.ttf \
AndroidClock.ttf \
AndroidClock_Highlight.ttf \
diff --git a/packages/PrintSpooler/res/color/item_text_color.xml b/packages/PrintSpooler/res/color/item_text_color.xml
new file mode 100644
index 0000000..f580fbd
--- /dev/null
+++ b/packages/PrintSpooler/res/color/item_text_color.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="true" android:color="#333333" />
+ <item android:color="#888888"/>
+</selector>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
index 7817094..98b5cfe 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_container.xml
@@ -14,10 +14,10 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.printspooler.PrintDialogFrame xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@color/container_background">
-</FrameLayout>
+</com.android.printspooler.PrintDialogFrame>
diff --git a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
index abf3c03..83019b9 100644
--- a/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
+++ b/packages/PrintSpooler/res/layout/print_job_config_activity_content_editing.xml
@@ -15,17 +15,16 @@
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:scrollbars="vertical"
android:background="@color/editable_background">
- <GridLayout
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:columnCount="2">
+ android:orientation="vertical">
<!-- Destination -->
@@ -37,190 +36,179 @@
android:layout_marginTop="24dip"
android:layout_marginStart="24dip"
android:layout_marginEnd="24dip"
- android:layout_row="0"
- android:layout_column="0"
- android:layout_columnSpan="2"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
</Spinner>
- <!-- Copies -->
-
- <view
- class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
- android:id="@+id/copies_edittext"
+ <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="6dip"
- android:layout_row="2"
- android:layout_column="0"
- android:layout_gravity="bottom|fill_horizontal"
- style="@style/PrintOptionEditTextStyle"
- android:inputType="numberDecimal">
- </view>
+ android:orientation="horizontal"
+ android:baselineAligned="false">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="36dip"
- android:layout_marginEnd="6dip"
- android:layout_row="1"
- android:layout_column="0"
- style="@style/PrintOptionTextViewStyle"
- android:labelFor="@id/copies_edittext"
- android:text="@string/label_copies">
- </TextView>
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
- <!-- Paper size -->
+ <!-- Copies -->
- <Spinner
- android:id="@+id/paper_size_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="24dip"
- android:layout_row="2"
- android:layout_column="1"
- android:layout_gravity="fill_horizontal"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_marginStart="36dip"
+ android:layout_marginEnd="6dip"
+ android:textAppearance="@style/PrintOptionTitleTextAppearance"
+ android:labelFor="@+id/copies_edittext"
+ android:text="@string/label_copies">
+ </TextView>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="18dip"
- android:layout_marginEnd="24dip"
- android:layout_row="1"
- android:layout_column="1"
- style="@style/PrintOptionTextViewStyle"
- android:labelFor="@id/paper_size_spinner"
- android:text="@string/label_paper_size">
- </TextView>
+ <view
+ class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+ android:id="@+id/copies_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dip"
+ android:layout_marginEnd="6dip"
+ style="@style/PrintOptionEditTextStyle"
+ android:inputType="numberDecimal">
+ </view>
- <!-- Color -->
+ <!-- Color -->
- <Spinner
- android:id="@+id/color_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="6dip"
- android:layout_row="4"
- android:layout_column="0"
- android:layout_gravity="fill_horizontal"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_marginStart="36dip"
+ android:layout_marginEnd="6dip"
+ android:textAppearance="@style/PrintOptionTitleTextAppearance"
+ android:labelFor="@+id/color_spinner"
+ android:text="@string/label_color">
+ </TextView>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="36dip"
- android:layout_marginEnd="6dip"
- android:layout_row="3"
- android:layout_column="0"
- style="@style/PrintOptionTextViewStyle"
- android:labelFor="@id/color_spinner"
- android:text="@string/label_color">
- </TextView>
+ <Spinner
+ android:id="@+id/color_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dip"
+ android:layout_marginEnd="6dip"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
- <!-- Orientation -->
+ <!-- Range options -->
- <Spinner
- android:id="@+id/orientation_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="24dip"
- android:layout_row="4"
- android:layout_column="1"
- android:layout_gravity="fill_horizontal"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
+ <TextView
+ android:id="@+id/range_options_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_marginStart="36dip"
+ android:textAppearance="@style/PrintOptionTitleTextAppearance"
+ android:labelFor="@+id/range_options_spinner"
+ android:text="@string/label_pages">
+ </TextView>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="18dip"
- android:layout_marginEnd="24dip"
- android:layout_row="3"
- android:layout_column="1"
- style="@style/PrintOptionTextViewStyle"
- android:labelFor="@id/orientation_spinner"
- android:text="@string/label_orientation">
- </TextView>
+ <Spinner
+ android:id="@+id/range_options_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dip"
+ android:layout_marginEnd="6dip"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
- <!-- Range options -->
+ </LinearLayout>
- <Spinner
- android:id="@+id/range_options_spinner"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="24dip"
- android:layout_marginEnd="6dip"
- android:layout_row="6"
- android:layout_column="0"
- android:layout_gravity="fill_horizontal"
- style="@style/PrintOptionSpinnerStyle">
- </Spinner>
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/range_options_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="36dip"
- android:layout_row="5"
- android:layout_column="0"
- style="@style/PrintOptionTextViewStyle"
- android:labelFor="@id/range_options_spinner"
- android:text="@string/label_pages">
- </TextView>
+ <!-- Paper size -->
- <!-- Pages -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_marginStart="18dip"
+ android:layout_marginEnd="24dip"
+ android:textAppearance="@style/PrintOptionTitleTextAppearance"
+ android:labelFor="@+id/paper_size_spinner"
+ android:text="@string/label_paper_size">
+ </TextView>
- <view
- class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
- android:id="@+id/page_range_edittext"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="6dip"
- android:layout_marginEnd="24dip"
- android:layout_row="6"
- android:layout_column="1"
- android:layout_gravity="bottom|fill_horizontal"
- style="@style/PrintOptionEditTextStyle"
- android:visibility="gone"
- android:inputType="textNoSuggestions">
- </view>
+ <Spinner
+ android:id="@+id/paper_size_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="6dip"
+ android:layout_marginEnd="24dip"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
- <TextView
- android:id="@+id/page_range_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dip"
- android:layout_marginStart="12dip"
- android:layout_marginEnd="24dip"
- android:layout_row="5"
- android:layout_column="1"
- style="@style/PrintOptionTextViewStyle"
- android:labelFor="@id/page_range_edittext"
- android:text="@string/pages_range_example"
- android:textAllCaps="false">
- </TextView>
+ <!-- Orientation -->
- <!-- Print button -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_marginStart="18dip"
+ android:layout_marginEnd="24dip"
+ android:textAppearance="@style/PrintOptionTitleTextAppearance"
+ android:labelFor="@+id/orientation_spinner"
+ android:text="@string/label_orientation">
+ </TextView>
+
+ <Spinner
+ android:id="@+id/orientation_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="6dip"
+ android:layout_marginEnd="24dip"
+ style="@style/PrintOptionSpinnerStyle">
+ </Spinner>
+
+ <!-- Pages -->
+
+ <TextView
+ android:id="@+id/page_range_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dip"
+ android:layout_marginStart="12dip"
+ android:layout_marginEnd="24dip"
+ android:textAppearance="@style/PrintOptionTitleTextAppearance"
+ android:text="@string/pages_range_example"
+ android:labelFor="@+id/page_range_edittext"
+ android:textAllCaps="false">
+ </TextView>
+
+ <view
+ class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
+ android:id="@+id/page_range_edittext"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="6dip"
+ android:layout_marginEnd="24dip"
+ android:layout_gravity="bottom|fill_horizontal"
+ style="@style/PrintOptionEditTextStyle"
+ android:visibility="gone"
+ android:inputType="textNoSuggestions">
+ </view>
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <!-- Print button -->
<ImageView
- android:layout_width="wrap_content"
+ android:layout_width="fill_parent"
android:layout_height="1dip"
android:layout_marginTop="24dip"
- android:layout_row="7"
- android:layout_column="0"
- android:layout_columnSpan="2"
android:layout_gravity="fill_horizontal"
android:background="@color/separator"
android:contentDescription="@null">
@@ -229,18 +217,14 @@
<Button
android:id="@+id/print_button"
style="?android:attr/buttonBarButtonStyle"
- android:layout_width="wrap_content"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
- android:layout_row="8"
- android:layout_column="0"
- android:layout_columnSpan="2"
android:text="@string/print_button"
android:textSize="16sp"
- android:textColor="@color/important_text">
+ android:textColor="@color/item_text_color">
</Button>
- </GridLayout>
+ </LinearLayout>
</ScrollView>
-
diff --git a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
index 48189bd..f00da0d 100644
--- a/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/spinner_dropdown_item.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingStart="8dip"
@@ -32,7 +32,8 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:gravity="top|left"
- android:textColor="@color/important_text">
+ android:textColor="@color/item_text_color"
+ android:duplicateParentState="true">
</TextView>
<TextView
@@ -44,7 +45,8 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="@color/important_text">
+ android:textColor="@color/item_text_color"
+ android:duplicateParentState="true">
</TextView>
diff --git a/packages/PrintSpooler/res/values/constants.xml b/packages/PrintSpooler/res/values/constants.xml
index 96cdeb1..e5a9d5d 100644
--- a/packages/PrintSpooler/res/values/constants.xml
+++ b/packages/PrintSpooler/res/values/constants.xml
@@ -24,4 +24,6 @@
<item>@integer/page_option_value_page_range</item>
</integer-array>
+ <dimen name="print_dialog_frame_max_width_dip">400dip</dimen>
+
</resources>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/values/styles.xml b/packages/PrintSpooler/res/values/styles.xml
index fe11c93..f6db6be 100644
--- a/packages/PrintSpooler/res/values/styles.xml
+++ b/packages/PrintSpooler/res/values/styles.xml
@@ -26,22 +26,14 @@
<style name="PrintOptionSpinnerStyle">
<item name="android:paddingTop">0dip</item>
<item name="android:paddingBottom">0dip</item>
- <item name="android:minWidth">150dip</item>
- <item name="android:maxWidth">200dip</item>
<item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
</style>
<style name="PrintOptionEditTextStyle">
<item name="android:selectAllOnFocus">true</item>
<item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
- <item name="android:maxWidth">200dip</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
</style>
- <style name="PrintOptionTextViewStyle">
- <item name="android:textAppearance">@style/PrintOptionTitleTextAppearance</item>
- <item name="android:maxWidth">200dip</item>
- </style>
-
</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
index 0431b94..72f6f0a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/FusedPrintersProvider.java
@@ -20,7 +20,6 @@
import android.content.Context;
import android.content.Loader;
import android.os.AsyncTask;
-import android.os.Build;
import android.print.PrintManager;
import android.print.PrinterDiscoverySession;
import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
@@ -34,8 +33,6 @@
import com.android.internal.util.FastXmlSerializer;
-import libcore.io.IoUtils;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -50,6 +47,8 @@
import java.util.List;
import java.util.Map;
+import libcore.io.IoUtils;
+
/**
* This class is responsible for loading printers by doing discovery
* and merging the discovered printers with the previously used ones.
@@ -86,38 +85,44 @@
mPersistenceManager.addPrinterAndWritePrinterHistory(printer);
}
- private void computeAndDeliverResult() {
+ private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters) {
if (!isStarted()) {
return;
}
List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
- // We want the first few favorite printers on top of the list.
- final int favoriteCount = Math.min(mFavoritePrinters.size(),
- MAX_FAVORITE_PRINTER_COUNT);
- for (int i = 0; i < favoriteCount; i++) {
- printers.add(mFavoritePrinters.get(i));
+ // Add the updated favorite printers.
+ final int favoritePrinterCount = mFavoritePrinters.size();
+ for (int i = 0; i < favoritePrinterCount; i++) {
+ PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
+ PrinterInfo updatedPrinter = discoveredPrinters.remove(
+ favoritePrinter.getId());
+ if (updatedPrinter != null) {
+ printers.add(updatedPrinter);
+ } else {
+ printers.add(favoritePrinter);
+ }
}
- // Add discovered printers updating favorites if needed.
+ // Add other updated printers.
final int printerCount = mPrinters.size();
for (int i = 0; i < printerCount; i++) {
- PrinterInfo discoveredPrinter = mPrinters.get(i);
- boolean printerHandled = false;
- for (int j = 0; j< favoriteCount; j++) {
- PrinterInfo favoritePrinter = printers.get(j);
- if (favoritePrinter.getId().equals(discoveredPrinter.getId())) {
- printers.set(j, discoveredPrinter);
- printerHandled = true;
- break;
- }
- }
- if (!printerHandled) {
- printers.add(discoveredPrinter);
+ PrinterInfo printer = mPrinters.get(i);
+ PrinterInfo updatedPrinter = discoveredPrinters.remove(
+ printer.getId());
+ if (updatedPrinter != null) {
+ printers.add(updatedPrinter);
}
}
+ // Add the new printers, i.e. what is left.
+ printers.addAll(discoveredPrinters.values());
+
+ // Update the list of printers.
+ mPrinters.clear();
+ mPrinters.addAll(printers);
+
// Deliver the printers.
deliverResult(printers);
}
@@ -129,8 +134,8 @@
}
// The contract is that if we already have a valid,
// result the we have to deliver it immediately.
- if (!mPrinters.isEmpty() || !mFavoritePrinters.isEmpty()) {
- computeAndDeliverResult();
+ if (!mPrinters.isEmpty()) {
+ deliverResult(new ArrayList<PrinterInfo>(mPrinters));
}
// Always load the data to ensure discovery period is
// started and to make sure obsolete printers are updated.
@@ -161,17 +166,22 @@
mDiscoverySession.setOnPrintersChangeListener(new OnPrintersChangeListener() {
@Override
public void onPrintersChanged() {
- mPrinters.clear();
- mPrinters.addAll(mDiscoverySession.getPrinters());
- computeAndDeliverResult();
+ ArrayMap<PrinterId, PrinterInfo> printersMap =
+ new ArrayMap<PrinterId, PrinterInfo>();
+ List<PrinterInfo> printers = mDiscoverySession.getPrinters();
+ final int printerCount = printers.size();
+ for (int i = 0; i < printerCount; i++) {
+ PrinterInfo printer = printers.get(i);
+ printersMap.put(printer.getId(), printer);
+ }
+ computeAndDeliverResult(printersMap);
}
});
mPersistenceManager.readPrinterHistory();
}
if (mPersistenceManager.isReadHistoryCompleted()
&& !mDiscoverySession.isPrinterDiscoveryStarted()) {
- final int favoriteCount = Math.min(MAX_FAVORITE_PRINTER_COUNT,
- mFavoritePrinters.size());
+ final int favoriteCount = mFavoritePrinters.size();
List<PrinterId> printerIds = new ArrayList<PrinterId>(favoriteCount);
for (int i = 0; i < favoriteCount; i++) {
printerIds.add(mFavoritePrinters.get(i).getId());
@@ -322,7 +332,8 @@
Collections.sort(favoriteRecords);
// Write the favorites to the output.
- final int favoriteCount = favoriteRecords.size();
+ final int favoriteCount = Math.min(favoriteRecords.size(),
+ MAX_FAVORITE_PRINTER_COUNT);
List<PrinterInfo> favoritePrinters = new ArrayList<PrinterInfo>(favoriteCount);
for (int i = 0; i < favoriteCount; i++) {
PrinterInfo printer = favoriteRecords.get(i).printer;
@@ -362,13 +373,15 @@
mHistoricalPrinters = printers;
// Compute the favorite printers.
- mFavoritePrinters.addAll(computeFavoritePrinters(printers));
+ mFavoritePrinters.clear();
+ mFavoritePrinters.addAll(computeFavoritePrinters(mHistoricalPrinters));
mReadHistoryInProgress = false;
mReadHistoryCompleted = true;
// Deliver the favorites.
- computeAndDeliverResult();
+ Map<PrinterId, PrinterInfo> discoveredPrinters = Collections.emptyMap();
+ computeAndDeliverResult(discoveredPrinters);
// Start loading the available printers.
loadInternal();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
new file mode 100644
index 0000000..6dd8aa0a
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintDialogFrame.java
@@ -0,0 +1,44 @@
+/*
+ * 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.printspooler;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class PrintDialogFrame extends FrameLayout {
+
+ public final int mMaxWidth;
+
+ public PrintDialogFrame(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mMaxWidth = context.getResources().getDimensionPixelSize(
+ R.dimen.print_dialog_frame_max_width_dip);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ if (widthMode == MeasureSpec.AT_MOST) {
+ final int receivedWidth = MeasureSpec.getSize(widthMeasureSpec);
+ final int computedWidth = Math.min(mMaxWidth, receivedWidth);
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(computedWidth,
+ MeasureSpec.EXACTLY);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
diff --git a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
index 4bf1db8..596435a 100644
--- a/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
+++ b/packages/services/Proxy/src/com/android/proxyhandler/ProxyServer.java
@@ -25,6 +25,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
@@ -198,9 +199,15 @@
while (mIsRunning) {
try {
- ProxyConnection parser = new ProxyConnection(serverSocket.accept());
+ Socket socket = serverSocket.accept();
+ // Only receive local connections.
+ if (socket.getInetAddress().isLoopbackAddress()) {
+ ProxyConnection parser = new ProxyConnection(socket);
- threadExecutor.execute(parser);
+ threadExecutor.execute(parser);
+ } else {
+ socket.close();
+ }
} catch (IOException e) {
e.printStackTrace();
}
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 37fbb13..fea7623 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -143,6 +143,7 @@
* Information about services for a single user.
*/
class ServiceMap extends Handler {
+ final int mUserId;
final ArrayMap<ComponentName, ServiceRecord> mServicesByName
= new ArrayMap<ComponentName, ServiceRecord>();
final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
@@ -165,6 +166,10 @@
static final int MSG_BG_START_TIMEOUT = 1;
+ ServiceMap(int userId) {
+ mUserId = userId;
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -224,6 +229,9 @@
Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
sendMessageAtTime(msg, when);
}
+ if (mStartingBackground.size() < mMaxStartingBackground) {
+ mAm.backgroundServicesFinishedLocked(mUserId);
+ }
}
}
@@ -239,10 +247,15 @@
return getServiceMap(callingUser).mServicesByName.get(name);
}
+ boolean hasBackgroundServices(int callingUser) {
+ ServiceMap smap = mServiceMap.get(callingUser);
+ return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false;
+ }
+
private ServiceMap getServiceMap(int callingUser) {
ServiceMap smap = mServiceMap.get(callingUser);
if (smap == null) {
- smap = new ServiceMap();
+ smap = new ServiceMap(callingUser);
mServiceMap.put(callingUser, smap);
}
return smap;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 80f4b00..f08b5b9 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -21,12 +21,12 @@
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
import android.app.AppOpsManager;
import android.appwidget.AppWidgetManager;
import android.util.ArrayMap;
-
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
@@ -52,7 +52,6 @@
import com.android.server.wm.AppTransition;
import com.android.server.wm.StackBox;
import com.android.server.wm.WindowManagerService;
-
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -155,7 +154,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.text.format.Time;
-import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
@@ -519,7 +517,7 @@
* This is the process holding what we currently consider to be
* the "home" activity.
*/
- ArraySet<ProcessRecord> mHomeProcess = new ArraySet<ProcessRecord>();
+ ProcessRecord mHomeProcess;
/**
* This is the process holding the activity the user last visited that
@@ -1903,8 +1901,8 @@
private ActivityManagerService() {
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
- mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
- mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+ mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false);
+ mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
@@ -4910,6 +4908,7 @@
final int userId = mStartedUsers.keyAt(i);
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
@Override
@@ -4924,7 +4923,7 @@
},
0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
- AppOpsManager.OP_NONE, false, false, MY_PID, Process.SYSTEM_UID,
+ AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID,
userId);
}
}
@@ -9121,8 +9120,8 @@
// with a home activity running in the process to prevent a repeatedly crashing app
// from blocking the user to manually clear the list.
final ArrayList<ActivityRecord> activities = app.activities;
- if (mHomeProcess.contains(app) && activities.size() > 0
- && (app.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (app == mHomeProcess && activities.size() > 0
+ && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.isHomeActivity()) {
@@ -10399,20 +10398,13 @@
pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
}
}
- if (!mHomeProcess.isEmpty()) {
- final int size = mHomeProcess.size();
- ProcessRecord[] processes = new ProcessRecord[size];
- mHomeProcess.toArray(processes);
- for (int processNdx = 0; processNdx < size; ++processNdx) {
- final ProcessRecord app = processes[processNdx];
- if (dumpPackage == null || app.pkgList.containsKey(dumpPackage)) {
- if (needSep) {
- pw.println();
- needSep = false;
- }
- pw.println(" mHomeProcess[" + processNdx + "]: " + app);
- }
+ if (mHomeProcess != null && (dumpPackage == null
+ || mHomeProcess.pkgList.containsKey(dumpPackage))) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
}
+ pw.println(" mHomeProcess: " + mHomeProcess);
}
if (mPreviousProcess != null && (dumpPackage == null
|| mPreviousProcess.pkgList.containsKey(dumpPackage))) {
@@ -11942,8 +11934,6 @@
}
mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();
- mHomeProcess.remove(app);
-
// If the caller is restarting this app, then leave it in its
// current lists and let the caller take care of it.
if (restarting) {
@@ -11973,8 +11963,8 @@
"Clean-up removing on hold: " + app);
mProcessesOnHold.remove(app);
- if (mHomeProcess.contains(app)) {
- mHomeProcess.remove(app);
+ if (app == mHomeProcess) {
+ mHomeProcess = null;
}
if (app == mPreviousProcess) {
mPreviousProcess = null;
@@ -12578,14 +12568,13 @@
boolean doTrim = false;
synchronized(this) {
- ReceiverList rl
- = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
+ ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl != null) {
if (rl.curBroadcast != null) {
BroadcastRecord r = rl.curBroadcast;
final boolean doNext = finishReceiverLocked(
receiver.asBinder(), r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort);
if (doNext) {
doTrim = true;
r.queue.processNextBroadcast(false);
@@ -13212,16 +13201,20 @@
}
private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
- String resultData, Bundle resultExtras, boolean resultAbort,
- boolean explicit) {
+ String resultData, Bundle resultExtras, boolean resultAbort) {
final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
if (r == null) {
Slog.w(TAG, "finishReceiver called but not found on queue");
return false;
}
- return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
- explicit);
+ return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, false);
+ }
+
+ void backgroundServicesFinishedLocked(int userId) {
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.backgroundServicesFinishedLocked(userId);
+ }
}
public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -13236,7 +13229,7 @@
final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
- BroadcastRecord r = null;
+ BroadcastRecord r;
synchronized(this) {
r = broadcastRecordForReceiverLocked(who);
@@ -13900,7 +13893,7 @@
}
}
- if (mHomeProcess.contains(app)) {
+ if (app == mHomeProcess) {
if (adj > ProcessList.HOME_APP_ADJ) {
// This process is hosting what we currently consider to be the
// home app, so we don't want to let it go into the background.
@@ -13967,7 +13960,7 @@
if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
procState = ActivityManager.PROCESS_STATE_SERVICE;
}
- if (app.hasShownUi && !mHomeProcess.contains(app)) {
+ if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
@@ -14030,7 +14023,7 @@
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
// Not doing bind OOM management, so treat
// this guy more like a started service.
- if (app.hasShownUi && !mHomeProcess.contains(app)) {
+ if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
// go to the LRU list because it may be pretty heavy with
// UI stuff. We'll tag it with a label just to help
@@ -14085,7 +14078,7 @@
// about letting this process get into the LRU
// list to be killed and restarted if needed for
// memory.
- if (app.hasShownUi && !mHomeProcess.contains(app)
+ if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adjType = "cch-bound-ui-services";
} else {
@@ -14199,7 +14192,7 @@
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
}
if (adj > clientAdj) {
- if (app.hasShownUi && !mHomeProcess.contains(app)
+ if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
app.adjType = "cch-ui-provider";
} else {
@@ -15061,7 +15054,7 @@
// to be good enough at this point that destroying
// activities causes more harm than good.
if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
- && !mHomeProcess.contains(app) && app != mPreviousProcess) {
+ && app != mHomeProcess && app != mPreviousProcess) {
// Need to do this on its own message because the stack may not
// be in a consistent state at this point.
// For these apps we will also finish their activities
@@ -15704,10 +15697,11 @@
final int userId = uss.mHandle.getIdentifier();
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, userId);
+ true, false, MY_PID, Process.SYSTEM_UID, userId);
}
int num = mUserLru.size();
int i = 0;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 6e50808..4359895 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -143,9 +143,6 @@
private boolean inHistory; // are we in the history stack?
final ActivityStackSupervisor mStackSupervisor;
- /** Launch the home activity rather than the activity at the top of stack */
- boolean mLaunchHomeTaskNext;
-
void dump(PrintWriter pw, String prefix) {
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.print("packageName="); pw.print(packageName);
@@ -243,6 +240,8 @@
pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
+ pw.print(prefix); pw.print("mActivityType=");
+ pw.println(activityTypeToString(mActivityType));
pw.print(prefix); pw.print("thumbHolder: ");
pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
if (thumbHolder != null) {
@@ -1040,6 +1039,15 @@
return null;
}
+ private String activityTypeToString(int type) {
+ switch (type) {
+ case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
+ case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
+ case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
+ default: return Integer.toString(type);
+ }
+ }
+
@Override
public String toString() {
if (stringName != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 1f64101..1482440 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1000,7 +1000,8 @@
boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
!(forceHomeShown && isHomeStack());
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
- final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.finishing) {
@@ -1083,7 +1084,7 @@
// At this point, nothing else needs to be shown
if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
behindFullscreen = true;
- } else if (r.mLaunchHomeTaskNext) {
+ } else if (task.mOnTopOfHome) {
if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
showHomeBehindStack = true;
behindFullscreen = true;
@@ -1224,7 +1225,7 @@
final TaskRecord nextTask = next.task;
final TaskRecord prevTask = prev != null ? prev.task : null;
- if (prevTask != null && prev.mLaunchHomeTaskNext && prev.finishing && prev.frontOfTask) {
+ if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (prevTask == nextTask) {
ArrayList<ActivityRecord> activities = prevTask.mActivities;
@@ -1234,7 +1235,6 @@
// r is usually the same as next, but what if two activities were launched
// before prev finished?
if (!r.finishing) {
- r.mLaunchHomeTaskNext = true;
r.frontOfTask = true;
break;
}
@@ -1243,7 +1243,7 @@
// This task is going away but it was supposed to return to the home task.
// Now the task above it has to return to the home task instead.
final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
- mTaskHistory.get(taskNdx).mActivities.get(0).mLaunchHomeTaskNext = true;
+ mTaskHistory.get(taskNdx).mOnTopOfHome = true;
} else {
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next");
return mStackSupervisor.resumeHomeActivity(prev);
@@ -2254,7 +2254,7 @@
if (r.state == ActivityState.RESUMED
|| r.state == ActivityState.PAUSING
|| r.state == ActivityState.PAUSED) {
- if (!r.isHomeActivity() || !mService.mHomeProcess.contains(r.app)) {
+ if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
@@ -2933,7 +2933,7 @@
if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
// Caller wants the home activity moved with it. To accomplish this,
// we'll just indicate that this task returns to the home task.
- task.mActivities.get(0).mLaunchHomeTaskNext = true;
+ task.mOnTopOfHome = true;
}
moveTaskToFrontLocked(task, null, options);
return true;
@@ -2994,17 +2994,17 @@
* If a watcher is installed, the action is preflighted and the watcher has an opportunity
* to premeptively cancel the move.
*
- * @param task The taskId to collect and move to the bottom.
+ * @param taskId The taskId to collect and move to the bottom.
* @return Returns true if the move completed, false if not.
*/
- final boolean moveTaskToBackLocked(int task, ActivityRecord reason) {
- Slog.i(TAG, "moveTaskToBack: " + task);
+ final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
+ Slog.i(TAG, "moveTaskToBack: " + taskId);
// If we have a watcher, preflight the move before committing to it. First check
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
if (mStackSupervisor.isFrontStack(this) && mService.mController != null) {
- ActivityRecord next = topRunningActivityLocked(null, task);
+ ActivityRecord next = topRunningActivityLocked(null, taskId);
if (next == null) {
next = topRunningActivityLocked(null, 0);
}
@@ -3024,9 +3024,9 @@
}
if (DEBUG_TRANSITION) Slog.v(TAG,
- "Prepare to back transition: task=" + task);
+ "Prepare to back transition: task=" + taskId);
- final TaskRecord tr = taskForIdLocked(task);
+ final TaskRecord tr = taskForIdLocked(taskId);
if (tr == null) {
return false;
}
@@ -3038,28 +3038,15 @@
// We make sure here that some activity in the stack will launch home.
ActivityRecord lastActivity = null;
int numTasks = mTaskHistory.size();
- int taskNdx;
- for (taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
- final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
- int activityNdx;
- for (activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.mLaunchHomeTaskNext) {
- break;
- }
- if (taskNdx == 1 && activityNdx == 0) {
- // Final activity before tr task.
- lastActivity = r;
- }
- }
- if (activityNdx >= 0) {
- // Early exit, we found an activity that will launchHomeTaskNext.
+ for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) {
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ if (task.mOnTopOfHome) {
break;
}
- }
- if (lastActivity != null) {
- // No early exit, we did not find an activity that will launchHomeTaskNext, set one.
- lastActivity.mLaunchHomeTaskNext = true;
+ if (taskNdx == 1) {
+ // Set the last task before tr to go to home.
+ task.mOnTopOfHome = true;
+ }
}
if (reason != null &&
@@ -3072,15 +3059,15 @@
} else {
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_TASK_TO_BACK, false);
}
- mWindowManager.moveTaskToBottom(task);
+ mWindowManager.moveTaskToBottom(taskId);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
- if (numTasks <= 1 || (mResumedActivity != null && mResumedActivity.task == tr &&
- mResumedActivity.mLaunchHomeTaskNext)) {
- mResumedActivity.mLaunchHomeTaskNext = false;
+ final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
+ if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
+ task.mOnTopOfHome = false;
return mStackSupervisor.resumeHomeActivity(null);
}
@@ -3427,7 +3414,7 @@
}
final ActivityRecord top = topRunningActivityLocked(null);
final boolean launchHomeTaskNext =
- top != null && top.app == app && top.mLaunchHomeTaskNext;
+ top != null && top.app == app && top.task.mOnTopOfHome;
// Remove this application's activities from active lists.
boolean hasVisibleActivities = removeHistoryRecordsForAppLocked(app);
@@ -3534,6 +3521,11 @@
}
boolean removeTask(TaskRecord task) {
+ final int taskNdx = mTaskHistory.indexOf(task);
+ final int topTaskNdx = mTaskHistory.size() - 1;
+ if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
+ mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
+ }
mTaskHistory.remove(task);
return mTaskHistory.isEmpty();
}
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 7756ff9..219cb85 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -282,7 +282,7 @@
boolean resumeHomeActivity(ActivityRecord prev) {
moveHomeStack(true);
if (prev != null) {
- prev.mLaunchHomeTaskNext = false;
+ prev.task.mOnTopOfHome = false;
}
mHomeStack.moveHomeTaskToTop();
ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
@@ -304,7 +304,7 @@
r = stack.topRunningActivityLocked(null);
}
if (r != null && !r.isHomeActivity() && r.isRootActivity()) {
- r.mLaunchHomeTaskNext = true;
+ r.task.mOnTopOfHome = true;
}
}
}
@@ -906,7 +906,8 @@
r.task.taskId, r.shortComponentName);
}
if (r.isHomeActivity() && r.isNotResolverActivity()) {
- mService.mHomeProcess.add(app);
+ // Home process is the root process of the task.
+ mService.mHomeProcess = r.task.mActivities.get(0).app;
}
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
r.sleeping = false;
@@ -1429,7 +1430,7 @@
(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity.
- r.mLaunchHomeTaskNext = true;
+ intentActivity.task.mOnTopOfHome = true;
}
targetStack.moveTaskToFrontLocked(intentActivity.task, r, options);
options = null;
@@ -1543,7 +1544,7 @@
// sure we have correctly resumed the top activity.
if (doResume) {
// Reset flag so it gets correctly reevaluated.
- intentActivity.mLaunchHomeTaskNext = false;
+ intentActivity.task.mOnTopOfHome = false;
setLaunchHomeTaskNextFlag(sourceRecord, intentActivity, targetStack);
targetStack.resumeTopActivityLocked(null, options);
} else {
@@ -1640,7 +1641,7 @@
== (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity, so before starting
// their own activity we will bring home to the front.
- r.mLaunchHomeTaskNext = true;
+ r.task.mOnTopOfHome = true;
}
}
} else if (sourceRecord != null) {
@@ -1949,7 +1950,7 @@
// makes sense to.
if (r.app != null && fgApp != null && r.app != fgApp
&& r.lastVisibleTime > mService.mPreviousProcessVisibleTime
- && !mService.mHomeProcess.contains(r.app)) {
+ && r.app != mService.mHomeProcess) {
mService.mPreviousProcess = r.app;
mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
}
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 254a219..b35ca79 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -54,8 +54,9 @@
static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
- static final int MAX_BROADCAST_HISTORY = 25;
- static final int MAX_BROADCAST_SUMMARY_HISTORY = 100;
+ static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 25;
+ static final int MAX_BROADCAST_SUMMARY_HISTORY
+ = ActivityManager.isLowRamDeviceStatic() ? 25 : 100;
final ActivityManagerService mService;
@@ -70,14 +71,20 @@
final long mTimeoutPeriod;
/**
+ * If true, we can delay broadcasts while waiting services to finish in the previous
+ * receiver's process.
+ */
+ final boolean mDelayBehindServices;
+
+ /**
* Lists of all active broadcasts that are to be executed immediately
* (without waiting for another broadcast to finish). Currently this only
* contains broadcasts to registered receivers, to avoid spinning up
* a bunch of processes to execute IntentReceiver components. Background-
* and foreground-priority broadcasts are queued separately.
*/
- final ArrayList<BroadcastRecord> mParallelBroadcasts
- = new ArrayList<BroadcastRecord>();
+ final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();
+
/**
* List of all active broadcasts that are to be executed one at a time.
* The object at the top of the list is the currently activity broadcasts;
@@ -85,20 +92,17 @@
* broadcasts, separate background- and foreground-priority queues are
* maintained.
*/
- final ArrayList<BroadcastRecord> mOrderedBroadcasts
- = new ArrayList<BroadcastRecord>();
+ final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
/**
* Historical data of past broadcasts, for debugging.
*/
- final BroadcastRecord[] mBroadcastHistory
- = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+ final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
/**
* Summary of historical data of past broadcasts, for debugging.
*/
- final Intent[] mBroadcastSummaryHistory
- = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+ final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
/**
* Set when we current have a BROADCAST_INTENT_MSG in flight.
@@ -128,10 +132,6 @@
static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
final Handler mHandler = new Handler() {
- //public Handler() {
- // if (localLOGV) Slog.v(TAG, "Handler started!");
- //}
-
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
@@ -163,10 +163,12 @@
}
}
- BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+ BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod,
+ boolean allowDelayBehindServices) {
mService = service;
mQueueName = name;
mTimeoutPeriod = timeoutPeriod;
+ mDelayBehindServices = allowDelayBehindServices;
}
public boolean isPendingBroadcastProcessLocked(int pid) {
@@ -260,7 +262,7 @@
+ br.curComponent.flattenToShortString(), e);
logBroadcastReceiverDiscardLocked(br);
finishReceiverLocked(br, br.resultCode, br.resultData,
- br.resultExtras, br.resultAbort, true);
+ br.resultExtras, br.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
br.state = BroadcastRecord.IDLE;
@@ -289,7 +291,7 @@
// let the broadcast continue.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
reschedule = true;
}
@@ -299,7 +301,7 @@
"[" + mQueueName + "] skip & discard pending app " + r);
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
reschedule = true;
}
if (reschedule) {
@@ -330,14 +332,11 @@
}
public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
- String resultData, Bundle resultExtras, boolean resultAbort,
- boolean explicit) {
- int state = r.state;
+ String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
+ final int state = r.state;
r.state = BroadcastRecord.IDLE;
if (state == BroadcastRecord.IDLE) {
- if (explicit) {
- Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
- }
+ Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
}
r.receiver = null;
r.intent.setComponent(null);
@@ -348,15 +347,35 @@
r.curFilter.receiverList.curBroadcast = null;
}
r.curFilter = null;
- r.curApp = null;
- r.curComponent = null;
r.curReceiver = null;
+ r.curApp = null;
mPendingBroadcast = null;
r.resultCode = resultCode;
r.resultData = resultData;
r.resultExtras = resultExtras;
- r.resultAbort = resultAbort;
+ if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
+ r.resultAbort = resultAbort;
+ } else {
+ r.resultAbort = false;
+ }
+
+ if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
+ && r.queue.mOrderedBroadcasts.size() > 0
+ && r.queue.mOrderedBroadcasts.get(0) == r) {
+ // In this case, we are ready to process the next receiver for the current broadcast,
+ // but are on a queue that would like to wait for services to finish before moving
+ // on. If there are background services currently starting, then we will go into a
+ // special state where we hold off on continuing this broadcast until they are done.
+ if (mService.mServices.hasBackgroundServices(r.userId)) {
+ Slog.i(ActivityManagerService.TAG, "Delay finish: "
+ + r.curComponent.flattenToShortString());
+ r.state = BroadcastRecord.WAITING_SERVICES;
+ return false;
+ }
+ }
+
+ r.curComponent = null;
// We will process the next receiver right now if this is finishing
// an app receiver (which is always asynchronous) or after we have
@@ -365,6 +384,18 @@
|| state == BroadcastRecord.CALL_DONE_RECEIVE;
}
+ public void backgroundServicesFinishedLocked(int userId) {
+ if (mOrderedBroadcasts.size() > 0) {
+ BroadcastRecord br = mOrderedBroadcasts.get(0);
+ if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
+ Slog.i(ActivityManagerService.TAG, "Resuming delayed broadcast");
+ br.curComponent = null;
+ br.state = BroadcastRecord.IDLE;
+ processNextBroadcast(false);
+ }
+ }
+ }
+
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
@@ -821,7 +852,7 @@
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
@@ -850,7 +881,7 @@
+ r.intent + ": process is bad");
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
@@ -917,7 +948,21 @@
}
}
- Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+ BroadcastRecord br = mOrderedBroadcasts.get(0);
+ if (br.state == BroadcastRecord.WAITING_SERVICES) {
+ // In this case the broadcast had already finished, but we had decided to wait
+ // for started services to finish as well before going on. So if we have actually
+ // waited long enough time timeout the broadcast, let's give up on the whole thing
+ // and just move on to the next.
+ Slog.i(ActivityManagerService.TAG, "Waited long enough for: " + (br.curComponent != null
+ ? br.curComponent.flattenToShortString() : "(null)"));
+ br.curComponent = null;
+ br.state = BroadcastRecord.IDLE;
+ processNextBroadcast(false);
+ return;
+ }
+
+ Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r. receiver
+ ", started " + (now - r.receiverTime) + "ms ago");
r.receiverTime = now;
r.anrCount++;
@@ -957,7 +1002,7 @@
// Move on to the next receiver.
finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
+ r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
if (anrMessage != null) {
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index db61e88..b2cfd7a 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -70,6 +70,7 @@
static final int APP_RECEIVE = 1;
static final int CALL_IN_RECEIVE = 2;
static final int CALL_DONE_RECEIVE = 3;
+ static final int WAITING_SERVICES = 4;
// The following are set when we are calling a receiver (one that
// was found in our list of registered receivers).
@@ -153,6 +154,7 @@
case APP_RECEIVE: stateStr=" (APP_RECEIVE)"; break;
case CALL_IN_RECEIVE: stateStr=" (CALL_IN_RECEIVE)"; break;
case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+ case WAITING_SERVICES: stateStr=" (WAITING_SERVICES)"; break;
}
pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
}
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 479665c..f0bba4f 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -60,6 +60,9 @@
/** Takes on same set of values as ActivityRecord.mActivityType */
private int mTaskType;
+ /** Launch the home activity when leaving this task. */
+ boolean mOnTopOfHome = false;
+
TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
taskId = _taskId;
affinity = info.taskAffinity;
@@ -411,11 +414,12 @@
}
void dump(PrintWriter pw, String prefix) {
- if (numActivities != 0 || rootWasReset || userId != 0) {
+ if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
pw.print(" rootWasReset="); pw.print(rootWasReset);
pw.print(" userId="); pw.print(userId);
- pw.print(" numFullscreen="); pw.println(numFullscreen);
+ pw.print(" numFullscreen="); pw.print(numFullscreen);
+ pw.print(" mOnTopOfHome="); pw.println(mOnTopOfHome);
}
if (affinity != null) {
pw.print(prefix); pw.print("affinity="); pw.println(affinity);