summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/IUserManager.aidl2
-rw-r--r--core/java/android/os/UserManager.java18
-rw-r--r--core/java/android/os/storage/VolumeInfo.java2
-rw-r--r--core/java/android/util/LocalLog.java44
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/tests/coretests/src/android/util/LocalLogTest.java110
-rw-r--r--docs/html/google/play/billing/billing_admin.jd630
-rw-r--r--libs/hwui/Android.mk2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java1
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java18
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java25
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java102
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java74
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java20
-rw-r--r--services/net/java/android/net/apf/ApfFilter.java32
-rw-r--r--services/tests/servicestests/src/android/net/apf/ApfTest.java42
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java42
20 files changed, 782 insertions, 399 deletions
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3324f6fe4589..427add19f14f 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -83,4 +83,6 @@ interface IUserManager {
boolean someUserHasSeedAccount(in String accountName, in String accountType);
boolean isManagedProfile(int userId);
boolean isDemoUser(int userId);
+ UserInfo createProfileForUserEvenWhenDisallowed(in String name, int flags, int userHandle,
+ in String[] disallowedPackages);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c7e5e6308a8a..c656b066a51d 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1374,6 +1374,24 @@ public class UserManager {
}
/**
+ * Similar to {@link #createProfileForUser(String, int, int, String[])}
+ * except bypassing the checking of {@link UserManager#DISALLOW_ADD_USER}.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * @see #createProfileForUser(String, int, int, String[])
+ * @hide
+ */
+ public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags,
+ @UserIdInt int userHandle, String[] disallowedPackages) {
+ try {
+ return mService.createProfileForUserEvenWhenDisallowed(name, flags, userHandle,
+ disallowedPackages);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Creates a restricted profile with the specified name. This method also sets necessary
* restrictions and adds shared accounts.
*
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 7399b7bfef2e..e399be0095bc 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -437,7 +437,7 @@ public class VolumeInfo implements Parcelable {
final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.setData(uri);
+ intent.setDataAndType(uri, DocumentsContract.Root.MIME_TYPE_ITEM);
// note that docsui treats this as *force* show advanced. So sending
// false permits advanced to be shown based on user preferences.
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 39f66a5f18fc..665c583a56ab 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -20,44 +20,49 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.Deque;
+import java.util.ArrayDeque;
/**
* @hide
*/
public final class LocalLog {
- private LinkedList<String> mLog;
- private int mMaxLines;
- private long mNow;
+ private final Deque<String> mLog;
+ private final int mMaxLines;
public LocalLog(int maxLines) {
- mLog = new LinkedList<String>();
- mMaxLines = maxLines;
+ mMaxLines = Math.max(0, maxLines);
+ mLog = new ArrayDeque<>(mMaxLines);
}
- public synchronized void log(String msg) {
- if (mMaxLines > 0) {
- mNow = System.currentTimeMillis();
- StringBuilder sb = new StringBuilder();
- Calendar c = Calendar.getInstance();
- c.setTimeInMillis(mNow);
- sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
- mLog.add(sb.toString() + " - " + msg);
- while (mLog.size() > mMaxLines) mLog.remove();
+ public void log(String msg) {
+ if (mMaxLines <= 0) {
+ return;
}
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(System.currentTimeMillis());
+ append(String.format("%tm-%td %tH:%tM:%tS.%tL - %s", c, c, c, c, c, c, msg));
+ }
+
+ private synchronized void append(String logLine) {
+ while (mLog.size() >= mMaxLines) {
+ mLog.remove();
+ }
+ mLog.add(logLine);
}
public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- Iterator<String> itr = mLog.listIterator(0);
+ Iterator<String> itr = mLog.iterator();
while (itr.hasNext()) {
pw.println(itr.next());
}
}
public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
- for (int i = mLog.size() - 1; i >= 0; i--) {
- pw.println(mLog.get(i));
+ Iterator<String> itr = mLog.descendingIterator();
+ while (itr.hasNext()) {
+ pw.println(itr.next());
}
}
@@ -69,6 +74,9 @@ public final class LocalLog {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mLog.dump(fd, pw, args);
}
+ public void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mLog.reverseDump(fd, pw, args);
+ }
}
public ReadOnlyLocalLog readOnlyLocalLog() {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d4bef1729fa1..0942a24da117 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -149,6 +149,8 @@
<protected-broadcast
android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
<protected-broadcast
+ android:name="android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
new file mode 100644
index 000000000000..a63c8a084964
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import junit.framework.TestCase;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+
+public class LocalLogTest extends TestCase {
+
+ public void testA() {
+ String[] lines = {
+ "foo",
+ "bar",
+ "baz"
+ };
+ String[] want = lines;
+ testcase(new LocalLog(10), lines, want);
+ }
+
+ public void testB() {
+ String[] lines = {
+ "foo",
+ "bar",
+ "baz"
+ };
+ String[] want = {};
+ testcase(new LocalLog(0), lines, want);
+ }
+
+ public void testC() {
+ String[] lines = {
+ "dropped",
+ "dropped",
+ "dropped",
+ "dropped",
+ "dropped",
+ "dropped",
+ "foo",
+ "bar",
+ "baz",
+ };
+ String[] want = {
+ "foo",
+ "bar",
+ "baz",
+ };
+ testcase(new LocalLog(3), lines, want);
+ }
+
+ void testcase(LocalLog logger, String[] input, String[] want) {
+ for (String l : input) {
+ logger.log(l);
+ }
+ verifyAllLines(want, dump(logger).split("\n"));
+ verifyAllLines(reverse(want), reverseDump(logger).split("\n"));
+ }
+
+ void verifyAllLines(String[] wantLines, String[] gotLines) {
+ for (int i = 0; i < wantLines.length; i++) {
+ String want = wantLines[i];
+ String got = gotLines[i];
+ String msg = String.format("%s did not contain %s", quote(got), quote(want));
+ assertTrue(msg, got.contains(want));
+ }
+ }
+
+ static String dump(LocalLog logger) {
+ StringWriter buffer = new StringWriter();
+ PrintWriter writer = new PrintWriter(buffer);
+ logger.dump(null, writer, new String[0]);
+ return buffer.toString();
+ }
+
+ static String reverseDump(LocalLog logger) {
+ StringWriter buffer = new StringWriter();
+ PrintWriter writer = new PrintWriter(buffer);
+ logger.reverseDump(null, writer, new String[0]);
+ return buffer.toString();
+ }
+
+ static String quote(String s) {
+ return '"' + s + '"';
+ }
+
+ static String[] reverse(String[] ary) {
+ List<String> ls = Arrays.asList(ary);
+ Collections.reverse(ls);
+ return ls.toArray(new String[ary.length]);
+ }
+}
diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
index ad09f1f53b40..9936489d7d45 100644
--- a/docs/html/google/play/billing/billing_admin.jd
+++ b/docs/html/google/play/billing/billing_admin.jd
@@ -51,9 +51,9 @@ apps. You can sell an item using Google Play's in-app billing feature only if th
listed on an app's product list. Each app has its own product list; you cannot sell
items that appear on another app's product list.</p>
-<p>You can access an app's product list by opening the <strong>In-app Products</strong>
+<p>You can access an app's product list by opening the <em>In-app Products</em>
page for an app that is listed in your developer account. The link to the
-<strong>In-app Products</strong> page appears only if you have a Google payments merchant
+<em>In-app Products</em> page appears only if you have a Google payments merchant
account and the app's manifest includes the
<code>com.android.vending.BILLING</code> permission. For more information about this
permission, see <a href="{@docRoot}google/play/billing/billing_integrate.html#billing-permission">
@@ -73,7 +73,7 @@ uploading an unpublished draft version. This functionality is no longer
supported; instead, you must publish it to the alpha or beta distribution
channel. For more information, see <a
href="{@docRoot}google/play/billing/billing_testing.html#draft_apps">Draft Apps
-are No Longer Supported</a>.
+are No Longer Supported</a>.</p>
<p>In addition, an app package can have only one product list. If you create a product
list for an app, and you use the <a
@@ -82,8 +82,8 @@ more than one APK for that app, the product list applies to all APK versions tha
associated with the app listing. You cannot create individual product lists for each APK if
you are using the multiple APK feature.</p>
-<p>You can add items to a product list two ways: you can add items one at a time on the <strong>In-app
-Products</strong> page, or you can add a batch of items by importing the items from a
+<p>You can add items to a product list two ways: you can add items one at a time on the <em>In-app
+Products</em> page, or you can add a batch of items by importing the items from a
comma-separated values (CSV) file. Adding items one at a time is useful if your
app has only a few in-app items or you are adding only a few items to a
product list for testing purposes. The CSV file method is useful if your app has a large
@@ -100,14 +100,14 @@ number of in-app items.</p>
<ol>
<li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
- <li>In the <strong>All applications</strong> panel, click on the
- app name, then open the <strong>In-app Products</strong> page.</li>
+ <li>In the <em>All applications</em> panel, click on the
+ app name, then open the <em>In-app Products</em> page.</li>
<li><p>Click <strong>Add new product</strong>. After you provide the product type and ID for the item you are
selling, click <strong>Continue</strong>.</p>
<dl>
<dt>Product Type</dt>
<dd>
- <p>The product type can be <strong>Managed product</strong> or <strong>Subscription</strong>. You cannot
+ <p>The product type can be "Managed product" or "Subscription." You cannot
change an item's product type after you create the item. For more information, see
<a href="#billing-purchase-type">Choosing a Product Type</a>.</p>
<p class="note"><strong>Note: </strong>For subscription items, you cannot change the
@@ -169,7 +169,7 @@ number of in-app items.</p>
<p>You can also change prices for other currencies manually, but you can do
this only if a currency is used in one of the target countries for your
app. You can specify target countries for your app on the
- <strong>Pricing &amp; Distribution</strong> page in the Google Play
+ <em>Pricing &amp; Distribution</em> page in the Google Play
Developer Console.</p>
</dd>
</dl>
@@ -187,266 +187,412 @@ number of in-app items.</p>
<h3 id="billing-bulk-add">Adding a batch of items to a product list</h3>
-<p>To add a batch of items to a product list using a CSV file, you first need to create your CSV
-file. The data values that you specify in the CSV file represent the same data values you specify
-manually through the In-app Products UI (see <a href="#billing-form-add">Adding items one at a time
-to a product list</a>).
+<p>To add a batch of items to a product list using a CSV file, you first need to
+create your CSV file. The data values that you specify in the CSV file represent
+the options that you set when adding in-app products to a product list using the
+Google Play Developer Console UI. For more information about using this UI, see
+<a href="#billing-form-add">Adding items one at a time to a product list</a>.
-<p>If you are importing and exporting CSV files with in-app products, keep
-country-specific pricing in mind. If you use auto-fill, you can provide a
-tax-exclusive default price, and tax-inclusive prices will be auto-filled. If you
-do not use auto-fill, prices you provide must include tax.</p>
+<p class="note"><strong>Note:</strong> Batch upload of in-app product lists
+containing subscriptions is not supported. Also, when updating existing items in
+a batch upload, you cannot include changes to in-app products that are linked to
+a <a href="#pricing-template">pricing template</a>.</p>
-<p class="note"><strong>Note:</strong> Batch upload of product lists containing
-subscriptions is not supported. Also, when updating existing items in a batch
-upload, you cannot include changes to in-app products that are linked to a
-<a href="#pricing-template">pricing template</a>.</p>
-
-<p>To import the items that are specified in your CSV file, do the following:</p>
+<p>To import the in-app products that are specified in your CSV file, do the
+following:</p>
<ol>
- <li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
- <li>In the <strong>All applications</strong> panel, select the app
- name, then open the <strong>In-app Products</strong> page.</li>
- <li>On the In-app Products List page, click <strong>Import/Export</strong>
- &gt; <strong>Import in-app products from CSV file</strong>, then select your
- CSV file.
- <p>The CSV file must be on your local computer or on a local disk that is connected to your
- computer.</p>
- </li>
- <li>Select the <strong>Overwrite</strong> checkbox if you want to overwrite existing items in
- your product list.
- <p>This option overwrites values of existing items only if the value of the <em>product_id</em>
- in the CSV file matches the In-app Product ID for an existing item in the product list.
- Overwriting doesn't delete items that are on a product list but not present in the CSV
- file.</p>
+ <li>
+ <a href="http://play.google.com/apps/publish">Log in</a> to your
+ publisher account.
+ </li>
+ <li>In the <em>All applications</em> panel, select the app
+ name, then open the <em>In-app Products</em> page.</li>
+ <li>
+ <p>On the <em>In-app Products</em> page, click
+ <strong>Import/Export</strong> &gt; <strong>Import in-app products from CSV
+ file</strong> to open the <em>Import In-app Products</em> dialog.</p>
+ </li>
+ <li>
+ <p>
+ If you want to overwrite existing in-app products in your product list
+ during the import process, select the <strong>Overwrite existing
+ products</strong> checkbox.
+ </p>
+ <p>
+ This option overwrites values of existing items only if the value of the
+ <code>Product ID</code> in the CSV file matches the in-app product ID for
+ an existing in-app product in the product list. The overwriting process
+ doesn't delete in-app products that exist in a product list but aren't
+ included in the CSV file
+ </p>
+ <p class="note"><strong>Note: </strong>If you choose not to overwrite
+ existing items, the <code>Product ID</code> given to each item in the CSV
+ file must be different from any of the <code>Product ID</code> values
+ assigned to existing in-app products.
+ </p>
+ </li>
+ <li>
+ Select <strong>Browse files</strong>, then choose the CSV file that contains
+ the items you want to import. The CSV file must be stored locally.
</li>
</ol>
-<p>You can also export an existing product list to a CSV file by clicking <strong>Export to CSV
-</strong> on the In-app Product List page. This is useful if you have manually added items to
-a product list and you want to start managing the product list through a CSV file.</p>
+<p>
+ You can also export an existing product list to a CSV file by clicking
+ <strong>Import/Export</strong> &gt; <strong>Export in-app products to CSV file
+ </strong> on the <em>In-app Products page</em>. This is useful if you have
+ used the UI to add in-app products to your app but you want to start managing
+ the product list through a CSV file instead.
+</p>
<h4 id="billing-bulk-format">Formatting batches of items</h4>
-<p>The CSV file uses commas (,) and semicolons (;) to separate data values.
-Commas are used to separate primary data values, and semicolons are used to
-separate subvalues. For example, the syntax for the CSV file is as follows:</p>
+<p>
+ The CSV file uses commas (<code>,</code>) and semicolons (<code>;</code>) to
+ separate data values. Commas are used to separate primary data values, and
+ semicolons are used to separate subvalues. Each item must appear entirely on a
+ single line within the CSV file.
+</p>
+<p>
+ When creating a CSV file that represents a list of items, you must specify the
+ CSV syntax on the first row, followed by the items themselves on subsequent
+ rows, as shown in the following example:
+</p>
+
+<pre class="no-pretty-print">
+Product ID,Published State,Purchase Type,Auto Translate,Locale; Title; Description,Auto Fill Prices,Price,Pricing Template ID
+basic_sleeping_potion,published,managed_by_android,false,en_US; Basic Sleeping Potion; Puts small creatures to sleep.; es_ES; Poción básica de dormir; Causa las criaturas pequeñas ir a dormir.,false,,4637138456024710495
+standard_sleeping_potion,published,managed_by_android,false,en_US; Standard Sleeping Potion; Puts all creatures to sleep for 2 minutes.,true, 1990000,
+invisibility_potion,published,managed_by_android,false,en_US; Invisibility Potion; Invisible to all enemies for 5 minutes.,false, US; 1990000; BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
+</pre>
-<p>"<em>product_id</em>","<em>publish_state</em>","<em>purchase_type</em>","<em>autotranslate</em>
-","<em>locale</em>; <em>title</em>; <em>description</em>","<em>autofill</em>","<em>country</em>;
-<em>price</em>", "<em>pricing_template_id</em>"
+<p>
+ This example contains details for three items, each of which represents an
+ in-app product:
</p>
+<ul>
+ <li>
+ The first item defines a title and description for the <code>en_US</code>
+ and <code>es_ES</code> locales. A pricing template defines the item's
+ price.
+ </li>
+ <li>
+ The second item doesn't use a pricing template. Instead, it specifies a
+ price for the default country (US). The Google Play Developer Console
+ uses current exchange rates and locally relevant pricing patterns to
+ automatically set the prices in all other countries where the app is
+ distributed.
+ </li>
+ <li>
+ The third item also doesn't use a pricing template. The item's price is
+ specified manually for each country where the app is distributed.
+ </li>
+</ul>
-<p>Descriptions and usage details are provided below.</p>
+<p>
+ Each row in a CSV file can contain the following values, though at least one
+ of these values is undefined in each row:
+</p>
<dl>
- <dt>product_id</dt>
+ <dt><code>Product ID</code></dt>
<dd>
- This is equivalent to the In-app Product ID setting in the In-app Products UI. If you specify
- a <em>product_id</em> that already exists in a product list, and you choose to overwrite
- the product list while importing the CSV file, the data for the existing item is overwritten with
- the values specified in the CSV file. The overwrite feature does not delete items that are on a
- product list but not present in the CSV file.
+ <p>
+ Setting this value in the CSV file has the same effect as entering a
+ <em>Product ID</em> when creating a new in-app product.
+ </p>
+ <p>
+ If you specify a <code>Product ID</code> assigned to an in-app product that already
+ exists in a product list, and you've checked the <strong>Overwrite
+ existing products</strong> checkbox in the <em>Import In-app Products</em>
+ dialog, the data for the existing in-app product is overwritten with the
+ values that you specify in the CSV file.
+ </p>
</dd>
- <dt>publish_state</dt>
+ <dt><code>Publish State</code></dt>
<dd>
- This is equivalent to the Publishing State setting in the In-app Products UI. Can be <code>
- published</code> or <code>unpublished</code>.
+ <p>
+ This value must be set to <code>published</code>
+ or <code>unpublished</code>.
+ </p>
+ <p>
+ Setting this value to <code>published</code> has the same effect as
+ navigating to an item's <em>Managed Product Details</em> page and choosing
+ <strong>Active</strong> in the drop-down list next to the in-app product's
+ title and product ID. Setting the value to <code>unpublished</code>
+ has the same effect as choosing <strong>Inactive</strong> in the same
+ drop-down list.
+ </p>
</dd>
- <dt>purchase_type</dt>
+ <dt><code>Purchase Type</code></dt>
<dd>
- This is equivalent to the Product Type setting in the In-app Products UI. Can be <code>
- managed_by_android</code>, which is equivalent to <strong>Managed per user account
- </strong> in the In-app Products UI, or <code>managed_by_publisher</code>, which is equivalent
- to <strong>Unmanaged</strong> in the In-app Products UI.
+ <p>
+ This value must be set to <code>managed_by_android</code> because batch
+ upload of product lists containing subscriptions is not supported.
+ </p>
+ <p>
+ Setting this value to <code>managed_by_android</code> has the same effect
+ as selecting <strong>Managed product</strong> in the <em>Add New
+ Product</em> dialog when creating an in-app product.
+ </p>
</dd>
- <dt>autotranslate</dt>
+ <dt><code>Auto Translate</code></dt>
<dd>
- This is equivalent to selecting the <strong>Fill fields with auto translation</strong>
- checkbox in the In-app Products UI. Can be <code>true</code> or <code>false</code>.
+ <p>
+ This value must be set to <code>false</code> because auto-translation of
+ in-app product details isn't supported.
+ </p>
+ <p>
+ If you want to provide translations of an in-app product's title and
+ description, you need to specify these translations explicitly within the
+ <code>Locale</code> value.
+ </p>
</dd>
- <dt>locale</dt>
+ <dt><code>Locale</code>, <code>Title</code>, and <code>Description</code></dt>
<dd>
- <p>This is equivalent to the Language setting in the In-app Products UI. You must have an entry
- for the default locale. The default locale must be the first entry in the list of
- locales, and it must include a <em>title</em> and <em>description</em>. If you want to provide
- translated versions of the <em>title</em> and <em>description</em> in addition to the default,
- you must use the following syntax rules:</p>
- <ul>
+ <p>
+ If you include only one locale for an item, you must specify your app's
+ default locale and the item's default title and description:
+ </p>
+
+<pre class="no-pretty-print">
+<var>app_default_locale</var>; <var>item_default_title</var>; <var>item_default_description</var>;
+</pre>
+
+ <p>
+ Setting these values has the same effect as performing the following
+ sequence of actions:
+ </p>
+ <ol>
<li>
- <p>If <em>autotranslate</em> is <code>true</code>, you must specify the default locale,
- default title, default description, and other locales using the following format:</p>
- <p>"true,"<em>default_locale</em>; <em>default_locale_title</em>;
- <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_3</em>, ..."</p>
+ Choosing a default language when you add a new app to your
+ publisher account.
</li>
<li>
- <p>If <em>autotranslate</em> is <code>false</code>, you must specify the default locale,
- default title, and default description as well as the translated titles and descriptions using
- the following format:</p>
- <p>"false,"<em>default_locale</em>; <em>default_locale_title</em>;
- <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_2_title</em>;
- <em>local_2_description</em>; <em>locale_3</em>; <em>locale_3_title</em>;
- <em>locale_3_description</em>; ..."</p>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
</li>
- </ul>
- <p>See table 1 for a list of the language codes you can use with the <em>locale</em> field.</p>
- </dd>
- <dt>title</dt>
- <dd>
- This is equivalent to the Title setting in the In-app Products UI. If the <em>title</em>
- contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
- must be escaped with a backslash (for example, <code>\\</code>).
- </dd>
- <dt>description</dt>
- <dd>
- This is equivalent to the Description in the In-app Products UI. If the <em>description</em>
- contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
- must be escaped with a backslash (for example, <code>\\</code>).
+ <li>
+ Specifying the in-app product's default title and description.
+ </li>
+ </ol>
+ <p>
+ When setting the <code>Locale</code> value, you can use any of the
+ language codes that appear within the <em>Add Your Own Translations</em>
+ dialog. You can access this dialog by navigating to an in-app product's
+ <em>Managed Product Details</em> page and clicking <strong>Add
+ translations</strong> or <strong>Manage translations</strong>.
+ </p>
+ <p class="note">
+ <strong>Note: </strong>When specifying the <code>Title</code> and
+ <code>Description</code> values, use backslashes to escape the semicolon
+ (<code>\;</code>) and backslash (<code>\\</code>) characters.
+ </p>
+ <p>
+ If you want to include translated versions of the item's title and
+ description, you must list the default locale, title, and description,
+ followed by the locales, titles, and descriptions for each translation.
+ In the following example, the in-app product uses <code>en_US</code>
+ (United States English) as the default locale and <code>es_ES</code>
+ (Spain Spanish) as a translation:
+ </p>
+<pre class="no-pretty-print">
+en_US; Invisibility Cloak; Makes you invisible.; es_ES; Capote Invisible; Se vuelven invisible.
+</pre>
+ <p class="note">
+ <strong>Note: </strong>An app contains a single default language, but each
+ in-app product maintains its own list of translations. Therefore, although
+ the first locale in each item's <code>Locale</code> value must be the same
+ throughout the CSV file, the other locales can differ from one item to
+ another.
+ </p>
+ <p>
+ Providing values for multiple translations has the same effect as
+ performing the following sequence of actions:
+ </p>
+ <ol>
+ <li>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
+ </li>
+ <li>
+ Clicking <strong>Add translations</strong>.
+ </li>
+ <li>
+ Selecting the languages for the translations and clicking
+ <strong>Add</strong>.
+ </li>
+ <li>
+ Choosing one of the languages you added in the previous step.
+ </li>
+ <li>
+ Specifying a new title and description, which serve as translations into
+ the selected language.
+ </li>
+ <li>
+ Repeating steps 4 and 5 to add translations into all other non-default
+ languages.
+ </li>
+ </ol>
</dd>
- <dt>autofill</dt>
+ <dt><code>Auto Fill Prices</code>, <code>Country</code>, and
+ <code>Price</code></dt>
<dd>
- <p>This is equivalent to clicking <strong>Auto Fill</strong> in the In-app Products UI. Can be
- <code>true</code> or <code>false</code>. The syntax for specifying the <em>country</em>
- and <em>price</em> varies depending on which <em>autofill</em> setting you use:</p>
- <ul>
+ <p>
+ You can set <code>Auto Fill Prices</code> to <code>true</code> or
+ <code>false</code>.
+ If an in-app product uses a <a href="#pricing-template">pricing
+ template</a>, you should set <code>Auto Fill Prices</code> to
+ <code>false</code>, and you shouldn't set a value for the
+ <code>Price</code>.
+ </p>
+ <p class="note">
+ <strong>Note: </strong>When you specify an item's price in a CSV file, you
+ provide a price in <em>micro-units</em>, where 1,000,000 micro-units is
+ equivalent to 1 unit of real currency.
+ </p>
+ <p>
+ The following sections describe how the value of
+ <code>Auto Fill Prices</code> affects the syntax and meaning of the
+ <code>Country</code> and <code>Price</code> values.
+ </p>
+ <h5>Using auto-filled prices</h5>
+ <p>
+ If you set <code>Auto Fill Prices</code> to <code>true</code>, you specify
+ only the item's default price; you don't include a <code>Country</code>
+ value. Setting <code>Auto Fill Prices</code> to <code>true</code> has the
+ same effect as performing the following sequence of actions:
+ </p>
+ <ol>
+ <li>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
+ </li>
+ <li>
+ Selecting <strong>Edit</strong> in the <em>Price</em> section.
+ </li>
+ <li>
+ Entering a default, tax-exclusive price. Auto-filled prices include tax.
+ </li>
+ <li>
+ Clicking the checkbox next to <em>COUNTRY</em> in the <em>Edit Local
+ Prices</em> dialog that appears.
+ </li>
<li>
- <p>If <em>autofill</em> is set to <code>true</code>, you need to specify only the default
- price in your home currency, and you must use this syntax:</p>
- <p>"true","<em>default_price_in_home_currency</em>"
+ Selecting <strong>Refresh exchange rates</strong>.
</li>
<li>
- <p>If <em>autofill</em> is set to <code>false</code>, you need to either specify the <em>pricing_template_id</em>
- that is linked to the in-app product or specify a <em>country</em> and a <em>price</em> for each currency.
- If you choose to specify countries and prices, you must use the following syntax:</p>
- <p>"false", "<em>home_country</em>; <em>default_price_in_home_currency</em>; <em>country_2</em>;
- <em>country_2_price</em>; <em>country_3</em>; <em>country_3_price</em>; ..."</p>
+ Selecting <strong>Apply</strong>.
</li>
+ </ol>
+ <p>
+ For example, under the following conditions:
+ </p>
+ <ul>
+ <li>Your app's default locale is <code>en_US</code>.</li>
+ <li>An in-app product's default, tax-exclusive price is $1.99.</li>
+ <li>You want the prices for other countries auto-filled.</li>
</ul>
- <p class="note"><strong>Note: </strong>If you use an <em>autofill</em> value of <code>false</code>
- and set country prices manually, you must incorporate country-specific
- pricing patterns, including tax rates, into the prices you provide.</p>
- </dd>
- <dt>country</dt>
- <dd>
- The country for which you are specifying a price. You can only list countries that your
- app is targeting. The country codes are two-letter uppercase
- ISO country codes (such as "US"), as defined by
- <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-2</a>.
- </dd>
- <dt>price</dt>
- <dd>
<p>
- If you use this value, you shouldn't specify a value for the <em>pricing_template_id</em>.
+ ...you'd set the values of <code>Auto Fill Prices</code> and
+ <code>Price</code> at the end of a row in the CSV file as follows:
+ </p>
+
+<pre class="no-pretty-print">
+true,1990000,
+</pre>
+
+ <h5>Not using auto-filled prices</h5>
+ <p>
+ If you set <code>Auto Fill Prices</code> to <code>false</code> instead,
+ you specify a series of <code>Country</code> and <code>Price</code>
+ values for all countries where you distribute your app, including the country corresponding to your app's default locale.
+ Each <code>Country</code> value is the two-letter uppercase <a
+ class="external-link"
+ href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO country
+ code</a> that represents a country where your app is distributed.
+ </p>
+ <p class="note">
+ <strong>Note: </strong>You must provide a country code and price for each
+ country that your app is targeting. To view and edit the list of countries
+ that your app targets, open your app's <em>Pricing &amp; Distribution</em>
+ page.
</p>
<p>
- This is equivalent to the Price in the In-app Products UI. The price must be specified in
- micro-units. To convert a currency value to micro-units, you multiply the real value by
- 1,000,000.
- For example, if you want to sell an in-app item for $1.99, you specify <code>1990000</code> in the
- <em>price</em> field.
+ Each <code>Price</code> value represents the cost of the item in
+ micro-units of the currency used in that country. Setting <code>Auto Fill
+ Prices</code> to <code>false</code> has the same effect as performing
+ the following sequence of actions:
</p>
+ <ol>
+ <li>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
+ </li>
+ <li>
+ Selecting <strong>Edit</strong> in the <em>Price</em> section.
+ </li>
+ <li>
+ Explicitly setting tax-inclusive prices for different countries in the
+ <em>Edit Local Prices</em> dialog that appears.
+ </li>
+ <li>
+ Selecting <strong>Apply</strong>.
+ </li>
+ </ol>
+ <p>
+ For example, if you're offering your app for the following prices (all
+ taxes included) in other countries:
+ </p>
+ <ul>
+ <li>R$6.99 in Brazil.</li>
+ <li>129&nbsp;&#8381; in Russia.</li>
+ <li>&#8377;130 in India.</li>
+ <li>Rp&nbsp;27,000 in Indonesia.</li>
+ <li>$37 in Mexico.</li>
+ </ul>
+ <p>
+ ...you'd set the values of <code>Auto Fill Prices</code>,
+ <code>Country</code>, and <code>Price</code> at the end of a row in the
+ CSV file as follows:
+ </p>
+
+<pre class="no-pretty-print">
+false, BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
+</pre>
+
</dd>
- <dt>pricing_template_id</dt>
+ <dt><code>Pricing Template ID</code></dt>
<dd>
<p>
- If you use this value, you should set <em>autofill</em> to
- <code>false</code> and leave the <em>price</em> column empty.
+ If an item is linked to a pricing template, you should set <code>Auto Fill
+ Prices</code> to <code>false</code>, and you shouldn't set a value for the
+ <code>Price</code> column. If the item isn't linked to a pricing template,
+ you shouldn't set a value for the <code>Pricing Template ID</code>; instead,
+ you should set <code>Auto Fill Prices</code>, <code>Country</code>, and
+ <code>Price</code> based on how you want to set the in-app product's prices.
</p>
<p>
- This value represents the ID of the pricing template that you've linked to
- the in-app product. This ID appears under a pricing template's name
- on the <strong>Pricing template</strong> page. If an in-app product isn't
- linked to a pricing template, its <em>pricing_template_id</em> value is
- empty.
+ Setting this value has the same effect as navigating to an in-app product's
+ <em>Managed Product Details</em> page and linking the product's price to the
+ pricing template that has the same pricing template ID as the one specified
+ in the CSV file. This pricing template ID appears underneath a pricing
+ template's name on the <em>Pricing template</em> page.
</p>
<p>
- If you import a CSV file and choose to overwrite the product list, you can
- update the links between in-app products and pricing templates by changing
- the value of an in-app product's <em>pricing_template_id</em>. Leave the
- value empty to unlink an in-app product from all pricing templates.
+ If you import a CSV file, and you've checked the <strong>Overwrite existing
+ products</strong> checkbox in the <em>Import In-app Products</em> dialog,
+ you can update the links between in-app products and pricing templates. To
+ link the product to a specific pricing template, set the <code>Pricing
+ Template ID</code> value to that pricing template's ID. To unlink an in-app
+ product from all pricing templates, don't set a value for its <code>Pricing
+ Template ID</code>.
</p>
<p>
- <strong>Note: </strong>You can link up to 100 app prices or in-app product
- prices with a particular pricing template. Therefore, don't specify the same
- <em>pricing_template_id</em> value in more than 100 rows of your CSV file.
+ You can link up to 100 app prices or in-app product prices to a particular
+ pricing template. Therefore, don't specify the same <code>Pricing Template
+ ID</code> value in more than 100 rows of a CSV file.
</p>
</dd>
</dl>
-<p class="table-caption" id="language-table"><strong>Table 1.</strong> Language codes you can use
-with the <em>locale</em> field.</p>
-
-<table>
-
-<tr>
-<th>Language</th>
-<th>Code</th>
-<th>Language</th>
-<th>Code</th>
-</tr>
-<tr>
-<td>Chinese</td>
-<td>zh_TW</td>
-<td>Italian</td>
-<td>it_IT</td>
-</tr>
-<tr>
-<td>Czech</td>
-<td>cs_CZ</td>
-<td>Japanese</td>
-<td>ja_JP</td>
-</tr>
-<tr>
-<td>Danish</td>
-<td>da_DK</td>
-<td>Korean</td>
-<td>ko_KR</td>
-</tr>
-<tr>
-<td>Dutch</td>
-<td>nl_NL</td>
-<td>Norwegian</td>
-<td>no_NO</td>
-</tr>
-<tr>
-<td>English</td>
-<td>en_US</td>
-<td>Polish</td>
-<td>pl_PL</td>
-</tr>
-<tr>
-<td>French</td>
-<td>fr_FR</td>
-<td>Portuguese</td>
-<td>pt_PT</td>
-</tr>
-<tr>
-<td>Finnish</td>
-<td>fi_FI</td>
-<td>Russian</td>
-<td>ru_RU</td>
-</tr>
-<tr>
-<td>German</td>
-<td>de_DE</td>
-<td>Spanish</td>
-<td>es_ES</td>
-</tr>
-<tr>
-<td>Hebrew</td>
-<td>iw_IL</td>
-<td>Swedish</td>
-<td>sv_SE</td>
-</tr>
-<tr>
-<td>Hindi</td>
-<td>hi_IN</td>
-<td>--</td>
-<td>--</td>
-</tr>
-</table>
-
<h2 id="pricing-template">
Pricing Templates
</h2>
@@ -466,7 +612,8 @@ with the <em>locale</em> field.</p>
can apply to paid apps and in-app products. You can link the prices of up to
100 apps and in-app products to a single pricing template.
</p>
-</p>
+
+<p>
To add a pricing template, do the following:
</p>
@@ -476,14 +623,14 @@ with the <em>locale</em> field.</p>
account.
</li>
- <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
- template</strong> page.
+ <li>In the <em>Settings</em> panel, open the <em>Pricing
+ template</em> page.
</li>
<li>
<p>
- If you are adding your first pricing template, the <strong>Add a Pricing
- Template</strong> banner appears. Select <strong>Add template</strong> to
+ If you are adding your first pricing template, the <em>Add a Pricing
+ Template</em> banner appears. Select <strong>Add template</strong> to
create a new template. The new template's <em>Pricing</em> tab appears.
</p>
@@ -544,8 +691,8 @@ with the <em>locale</em> field.</p>
account.
</li>
- <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
- template</strong> page. This page shows the list of pricing templates you have
+ <li>In the <em>Settings</em> panel, open the <em>Pricing
+ template</em> page. This page shows the list of pricing templates you have
created for your account.
</li>
@@ -605,8 +752,8 @@ with the <em>locale</em> field.</p>
account.
</li>
- <li>In the <strong>All applications</strong> panel, select the app name, then
- open the <strong>In-app Products</strong> page.
+ <li>In the <em>All applications</em> panel, select the app name, then
+ open the <em>In-app Products</em> page.
</li>
<li>Choose the in-app product that you want to link to a pricing template.
@@ -625,7 +772,7 @@ with the <em>locale</em> field.</p>
<p>
To link the price of a paid app to a pricing template, you follow a similar
- process on the app's <strong>Pricing &amp; Distribution</strong> page.
+ process on the app's <em>Pricing &amp; Distribution</em> page.
</p>
<h3 id="delete-linked-item">
@@ -657,7 +804,7 @@ with the <em>locale</em> field.</p>
<li>Select the app that contains the in-app product you want to delete.
</li>
- <li>Open the app's <strong>In-app Products</strong> page.
+ <li>Open the app's <em>In-app Products</em> page.
</li>
<li>Choose the in-app product that you want to delete.
@@ -731,8 +878,8 @@ with the <em>locale</em> field.</p>
account.
</li>
- <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
- template</strong> page, which shows the list of pricing templates you have
+ <li>In the <em>Settings</em> panel, open the <em>Pricing
+ template</em> page, which shows the list of pricing templates you have
created for your account.
</li>
@@ -746,15 +893,15 @@ with the <em>locale</em> field.</p>
</li>
</ol>
-<h2 id="billing-purchase-type">Choosing a Product Type</h3>
+<h2 id="billing-purchase-type">Choosing a Product Type</h2>
<p>An item's product type controls how Google Play manages the purchase of the item. The supported
product types include "managed product" and "subscription." Since support for different product
types can vary among versions of the In-app Billing API, make sure that you choose a product
-type that's valid for the version of the In-app Billing API that your app uses. </p>
+type that's valid for the version of the In-app Billing API that your app uses.</p>
<p>For details, refer to the documentation for the <a
-href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.
+href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.</p>
<h2 id="billing-refunds">Handling Refunds</h2>
@@ -782,9 +929,10 @@ you at the conclusion of the purchase flow, as the value of the
intent.</p>
<p class="note">
- <strong>Note:</strong> Test purchases don't have an <code>orderId</code>
- field. To track test transactions, you use the <code>purchaseToken</code>
- field instead. For more information about working with test purchases, see <a
+ <strong>Note:</strong> When a user completes a test purchase, the
+ <code>orderId</code> field remains blank. To track test transactions, use
+ the <code>purchaseToken</code> field instead. For more information about
+ working with test purchases, see <a
href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
Billing</a>.
</p>
@@ -799,14 +947,14 @@ assigned and managed by Google.</p>
<p>For transactions dated 5 December 2012 or later, Google payments assigns a
Merchant Order Number (rather than a Google Order Number) and reports the Merchant
-Order Number as the value of <code>orderId</code>. Here's an
+Order Number as the value of <code>orderID</code>. Here's an
example:</p>
<pre>"orderId" : "GPA.1234-5678-9012-34567"</pre>
<p>For transactions dated previous to 5 December 2012, Google checkout assigned
a Google Order Number and reported that number as the value of
-<code>orderId</code>. Here's an example of an <code>orderId</code> holding a
+<code>orderID</code>. Here's an example of an <code>orderID</code> holding a
Google Order Number:</p>
<pre>"orderId" : "556515565155651"</pre>
@@ -853,8 +1001,8 @@ app.</p>
<p>To locate the key for an app, follow these steps:</p>
<ol>
- <li>Open the <strong>All applications</strong> panel.</li>
- <li>Click on the app name, then open the <strong>Services &amp; APIs</strong>
+ <li>Open the <em>All applications</em> panel.</li>
+ <li>Click on the app name, then open the <em>Services &amp; APIs</em>
page.</li>
<li>Scroll down to the section of the page labeled Your License Key for This
Application, as shown in figure 5.</li>
@@ -869,7 +1017,7 @@ for apps that depend on the (former) developer key. </p>
width="700" alt="">
<figcaption>
<b>Figure 5. </b>You can find the license key for each app on the
- <strong>Services &amp; APIs</strong> page.
+ <em>Services &amp; APIs</em> page.
</figcaption>
</figure>
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 81a183126cce..b44b1d8f061f 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-BUGREPORT_FONT_CACHE_USAGE := true
+BUGREPORT_FONT_CACHE_USAGE := false
# Enables fine-grained GLES error checking
# If set to true, every GLES call is wrapped & error checked
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 085e003f8869..53a54d6d29e4 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -298,6 +298,7 @@ public class PipManager {
mListeners.get(i).onMoveToFullscreen();
}
resizePinnedStack(mState);
+ updatePipVisibility(false);
}
/**
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9146bec2af49..c0de214c5833 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -97,6 +97,7 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.am.UserState;
import com.android.server.storage.DeviceStorageMonitorInternal;
+
import libcore.io.IoUtils;
import libcore.util.Objects;
@@ -2189,6 +2190,13 @@ public class UserManagerService extends IUserManager.Stub {
}
@Override
+ public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags, int userId,
+ String[] disallowedPackages) {
+ checkManageOrCreateUsersPermission(flags);
+ return createUserInternalUnchecked(name, flags, userId, disallowedPackages);
+ }
+
+ @Override
public UserInfo createUser(String name, int flags) {
checkManageOrCreateUsersPermission(flags);
return createUserInternal(name, flags, UserHandle.USER_NULL);
@@ -2204,17 +2212,17 @@ public class UserManagerService extends IUserManager.Stub {
Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
return null;
}
+ return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);
+ }
+
+ private UserInfo createUserInternalUnchecked(String name, int flags, int parentId,
+ String[] disallowedPackages) {
DeviceStorageMonitorInternal dsm = LocalServices
.getService(DeviceStorageMonitorInternal.class);
if (dsm.isMemoryLow()) {
Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
return null;
}
- return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);
- }
-
- private UserInfo createUserInternalUnchecked(String name, int flags, int parentId,
- String[] disallowedPackages) {
if (ActivityManager.isLowRamDeviceStatic()) {
return null;
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 5514551e0f1a..e9c8bef7db53 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -480,6 +480,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
WallpaperData mLastWallpaper;
IWallpaperManagerCallback mKeyguardListener;
boolean mWaitingForUnlock;
+ boolean mShuttingDown;
/**
* ID of the current wallpaper, changed every time anything sets a wallpaper.
@@ -607,6 +608,14 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
private Runnable mResetRunnable = () -> {
synchronized (mLock) {
+ if (mShuttingDown) {
+ // Don't expect wallpaper services to relaunch during shutdown
+ if (DEBUG) {
+ Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
+ }
+ return;
+ }
+
if (!mWallpaper.wallpaperUpdating
&& mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Wallpaper reconnect timed out, "
@@ -867,6 +876,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
public WallpaperManagerService(Context context) {
if (DEBUG) Slog.v(TAG, "WallpaperService startup");
mContext = context;
+ mShuttingDown = false;
mImageWallpaper = ComponentName.unflattenFromString(
context.getResources().getString(R.string.image_wallpaper_component));
mIWindowManager = IWindowManager.Stub.asInterface(
@@ -931,6 +941,21 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
}, userFilter);
+ final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
+ if (DEBUG) {
+ Slog.i(TAG, "Shutting down");
+ }
+ synchronized (mLock) {
+ mShuttingDown = true;
+ }
+ }
+ }
+ }, shutdownFilter);
+
try {
ActivityManagerNative.getDefault().registerUserSwitchObserver(
new UserSwitchObserver() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 42e9e2399f18..fb37c9f0c605 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -127,7 +127,7 @@ class DisplayContent extends WindowContainer<TaskStack> {
final WindowManagerService mService;
/** Remove this display when animation on it has completed. */
- boolean mDeferredRemoval;
+ private boolean mDeferredRemoval;
final DockedStackDividerController mDividerControllerLocked;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 1700bca2e51b..9bd311895f1b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -106,7 +106,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
private long mUserActivityTimeout = -1;
private boolean mUpdateRotation = false;
private boolean mObscured = false;
- boolean mSyswin = false;
+ private boolean mSyswin = false;
// Set to true when the display contains content to show the user.
// When false, the display manager may choose to mirror or blank the display.
private boolean mDisplayHasContent = false;
@@ -116,7 +116,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
// Last window that requires screen wakelock
WindowState mHoldScreenWindow = null;
// Last window that obscures all windows below
- WindowState mObsuringWindow = null;
+ WindowState mObscuringWindow = null;
// Only set while traversing the default display based on its content.
// Affects the behavior of mirroring on secondary displays.
private boolean mObscureApplicationContentOnSecondaryDisplays = false;
@@ -368,7 +368,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
* Callback used to trigger bounds update after configuration change and get ids of stacks whose
* bounds were updated.
*/
- int[] updateStackBoundsAfterConfigChange() {
+ private int[] updateStackBoundsAfterConfigChange() {
mChangedStackList.clear();
final int numDisplays = mChildren.size();
@@ -969,7 +969,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
// TODO: Super crazy long method that should be broken down...
private void applySurfaceChangesTransaction(boolean recoveringMemory, int defaultDw, int defaultDh) {
mHoldScreenWindow = null;
- mObsuringWindow = null;
+ mObscuringWindow = null;
if (mService.mWatermark != null) {
mService.mWatermark.positionSurface(defaultDw, defaultDh);
@@ -1195,7 +1195,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
// so we want to leave all of them as undimmed (for
// performance reasons).
if (!mObscured) {
- mObsuringWindow = w;
+ mObscuringWindow = w;
}
mObscured = true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9f8110503a25..12ad09c85f90 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -166,6 +166,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
@@ -203,6 +204,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.EventLogTags.WM_TASK_CREATED;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
@@ -2738,10 +2740,8 @@ public class WindowManagerService extends IWindowManager.Stub
== PackageManager.PERMISSION_GRANTED) {
return true;
}
- String msg = "Permission Denial: " + func + " from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " requires " + permission;
+ final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid() + " requires " + permission;
Slog.w(TAG_WM, msg);
return false;
}
@@ -2760,8 +2760,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void addWindowToken(IBinder token, int type) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "addWindowToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -2780,8 +2779,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void removeWindowToken(IBinder token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "removeWindowToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -2808,9 +2806,9 @@ public class WindowManagerService extends IWindowManager.Stub
+ " atoken=" + atoken + " bounds=" + bounds);
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
- throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
+ throw new IllegalArgumentException("createTaskLocked: invalid stackId=" + stackId);
}
- EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
+ EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
Task task = new Task(taskId, stack, userId, this, bounds, overrideConfig, isOnTopLauncher);
mTaskIdToTask.put(taskId, task);
stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
@@ -2824,8 +2822,7 @@ public class WindowManagerService extends IWindowManager.Stub
Rect taskBounds, Configuration overrideConfig, int taskResizeMode,
boolean alwaysFocusable, boolean homeTask, int targetSdkVersion,
int rotationAnimationHint, boolean isOnTopLauncher) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "addAppToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -2880,8 +2877,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void setAppTask(IBinder token, int taskId, int stackId, Rect taskBounds,
Configuration overrideConfig, int taskResizeMode, boolean homeTask,
boolean isOnTopLauncher) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppTask()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppTask()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -2978,8 +2974,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public Configuration updateOrientationFromAppTokens(
Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "updateOrientationFromAppTokens()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "updateOrientationFromAppTokens()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3092,8 +3087,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public int[] setNewConfiguration(Configuration config) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setNewConfiguration()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setNewConfiguration()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3118,8 +3112,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppOrientation()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppOrientation()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3158,8 +3151,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setFocusedApp(IBinder token, boolean moveFocusNow) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setFocusedApp()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setFocusedApp()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3200,8 +3192,7 @@ public class WindowManagerService extends IWindowManager.Stub
*/
@Override
public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "prepareAppTransition()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
@@ -3329,8 +3320,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void executeAppTransition() {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "executeAppTransition()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "executeAppTransition()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3354,8 +3344,7 @@ public class WindowManagerService extends IWindowManager.Stub
int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppStartingWindow()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppStartingWindow()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3426,7 +3415,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (wtoken != null && wtoken.transferStartingWindow(transferFrom)) {
+ if (wtoken.transferStartingWindow(transferFrom)) {
return true;
}
@@ -3473,10 +3462,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
- AppWindowToken wtoken = findAppWindowToken(token);
+ private void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
+ final AppWindowToken wtoken = findAppWindowToken(token);
if (wtoken != null) {
- WindowState win = wtoken.findMainWindow();
+ final WindowState win = wtoken.findMainWindow();
if (win != null) {
win.mWinAnimator.setOpaqueLocked(isOpaque);
}
@@ -3494,8 +3483,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "notifyAppResumed()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppResumed()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3512,8 +3500,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void notifyAppStopped(IBinder token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "notifyAppStopped()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppStopped()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3530,8 +3517,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setAppVisibility(IBinder token, boolean visible) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppVisibility()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppVisibility()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3648,8 +3634,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void startAppFreezingScreen(IBinder token, int configChanges) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppFreezingScreen()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3672,19 +3657,18 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void stopAppFreezingScreen(IBinder token, boolean force) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppFreezingScreen()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
- AppWindowToken wtoken = findAppWindowToken(token);
+ final AppWindowToken wtoken = findAppWindowToken(token);
if (wtoken == null || wtoken.appToken == null) {
return;
}
final long origId = Binder.clearCallingIdentity();
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token
- + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token + ": hidden="
+ + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
wtoken.stopFreezingScreen(true, force);
Binder.restoreCallingIdentity(origId);
}
@@ -3692,8 +3676,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void removeAppToken(IBinder token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "removeAppToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -6628,8 +6611,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void pauseKeyDispatching(IBinder _token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "pauseKeyDispatching()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "pauseKeyDispatching()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -6643,8 +6625,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void resumeKeyDispatching(IBinder _token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "resumeKeyDispatching()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "resumeKeyDispatching()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -6658,8 +6639,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void setEventDispatching(boolean enabled) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setEventDispatching()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setEventDispatching()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -8133,10 +8113,10 @@ public class WindowManagerService extends IWindowManager.Stub
} else {
if (DEBUG_KEEP_SCREEN_ON) {
Slog.d(TAG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by "
- + mRoot.mObsuringWindow);
+ + mRoot.mObscuringWindow);
}
mLastWakeLockHoldingWindow = null;
- mLastWakeLockObscuringWindow = mRoot.mObsuringWindow;
+ mLastWakeLockObscuringWindow = mRoot.mObscuringWindow;
mPolicy.keepScreenOnStoppedLw();
mHoldingScreenWakeLock.release();
}
@@ -8711,17 +8691,17 @@ public class WindowManagerService extends IWindowManager.Stub
return getDefaultDisplayContentLocked().getDockedDividerController().getContentInsets();
}
- void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
+ private void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
mPolicy.dump(" ", pw, args);
}
- void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
+ private void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)");
mAnimator.dumpLocked(pw, " ", dumpAll);
}
- void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
+ private void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
if (!mTokenMap.isEmpty()) {
pw.println(" All tokens:");
@@ -8764,7 +8744,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
+ private void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
for (int i=0; i<mSessions.size(); i++) {
Session s = mSessions.valueAt(i);
@@ -8773,13 +8753,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
+ private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
}
- void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
+ private void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
mRoot.dumpWindowsNoHeader(pw, dumpAll, windows);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 435b1d2c99d8..184b6cdea4ed 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -157,7 +157,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// to capture touch events in that area.
static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
- static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
+ private static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
final WindowManagerService mService;
final WindowManagerPolicy mPolicy;
@@ -182,7 +182,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final boolean mLayoutAttached;
final boolean mIsImWindow;
final boolean mIsWallpaper;
- final boolean mIsFloatingLayer;
+ private final boolean mIsFloatingLayer;
int mSeq;
boolean mEnforceSizeCompat;
int mViewVisibility;
@@ -199,16 +199,16 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* animation is done.
*/
boolean mPolicyVisibilityAfterAnim = true;
- boolean mAppOpVisibility = true;
+ private boolean mAppOpVisibility = true;
boolean mPermanentlyHidden; // the window should never be shown again
boolean mAppFreezing;
boolean mHidden; // Used to determine if to show child windows.
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
- boolean mDragResizing;
- boolean mDragResizingChangeReported;
- int mResizeMode;
+ private boolean mDragResizing;
+ private boolean mDragResizingChangeReported;
+ private int mResizeMode;
- RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
+ private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
/**
* The window size that was requested by the application. These are in
@@ -216,8 +216,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
int mRequestedWidth;
int mRequestedHeight;
- int mLastRequestedWidth;
- int mLastRequestedHeight;
+ private int mLastRequestedWidth;
+ private int mLastRequestedHeight;
int mLayer;
boolean mHaveFrame;
@@ -244,8 +244,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* coordinate space (without compatibility scale applied).
*/
final Rect mVisibleInsets = new Rect();
- final Rect mLastVisibleInsets = new Rect();
- boolean mVisibleInsetsChanged;
+ private final Rect mLastVisibleInsets = new Rect();
+ private boolean mVisibleInsetsChanged;
/**
* Insets that are covered by system windows (such as the status bar) and
@@ -254,31 +254,31 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
final Rect mContentInsets = new Rect();
final Rect mLastContentInsets = new Rect();
- boolean mContentInsetsChanged;
+ private boolean mContentInsetsChanged;
/**
* Insets that determine the area covered by the display overscan region. These are in the
* application's coordinate space (without compatibility scale applied).
*/
final Rect mOverscanInsets = new Rect();
- final Rect mLastOverscanInsets = new Rect();
- boolean mOverscanInsetsChanged;
+ private final Rect mLastOverscanInsets = new Rect();
+ private boolean mOverscanInsetsChanged;
/**
* Insets that determine the area covered by the stable system windows. These are in the
* application's coordinate space (without compatibility scale applied).
*/
final Rect mStableInsets = new Rect();
- final Rect mLastStableInsets = new Rect();
- boolean mStableInsetsChanged;
+ private final Rect mLastStableInsets = new Rect();
+ private boolean mStableInsetsChanged;
/**
* Outsets determine the area outside of the surface where we want to pretend that it's possible
* to draw anyway.
*/
final Rect mOutsets = new Rect();
- final Rect mLastOutsets = new Rect();
- boolean mOutsetsChanged = false;
+ private final Rect mLastOutsets = new Rect();
+ private boolean mOutsetsChanged = false;
/**
* Set to true if we are waiting for this window to receive its
@@ -321,14 +321,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// "Real" frame that the application sees, in display coordinate space.
final Rect mFrame = new Rect();
final Rect mLastFrame = new Rect();
- boolean mFrameSizeChanged = false;
+ private boolean mFrameSizeChanged = false;
// Frame that is scaled to the application's coordinate space when in
// screen size compatibility mode.
final Rect mCompatFrame = new Rect();
final Rect mContainingFrame = new Rect();
- final Rect mParentFrame = new Rect();
+ private final Rect mParentFrame = new Rect();
// The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
// screen area of the device.
@@ -338,11 +338,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// is mostly a special case for TV where some displays don’t have the entire display usable.
// {@link WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to allow
// window display contents to extend into the overscan region.
- final Rect mOverscanFrame = new Rect();
+ private final Rect mOverscanFrame = new Rect();
// The display frame minus the stable insets. This value is always constant regardless of if
// the status bar or navigation bar is visible.
- final Rect mStableFrame = new Rect();
+ private final Rect mStableFrame = new Rect();
// The area not occupied by the status and navigation bars. So, if both status and navigation
// bars are visible, the decor frame is equal to the stable frame.
@@ -350,7 +350,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame
// minus the area occupied by the IME if the IME is present.
- final Rect mContentFrame = new Rect();
+ private final Rect mContentFrame = new Rect();
// Legacy stuff. Generally equal to the content frame expect when the IME for older apps
// displays hint text.
@@ -358,13 +358,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Frame that includes dead area outside of the surface but where we want to pretend that it's
// possible to draw.
- final Rect mOutsetFrame = new Rect();
+ private final Rect mOutsetFrame = new Rect();
/**
* Usually empty. Set to the task's tempInsetFrame. See
*{@link android.app.IActivityManager#resizeDockedStack}.
*/
- final Rect mInsetFrame = new Rect();
+ private final Rect mInsetFrame = new Rect();
boolean mContentChanged;
@@ -446,7 +446,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* or some other higher level component said so (e.g. activity manager).
* TODO: We should either have different booleans for the removal reason or use a bit-field.
*/
- boolean mWindowRemovalAllowed;
+ private boolean mWindowRemovalAllowed;
/**
* Temp for keeping track of windows that have been removed when
@@ -457,18 +457,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Input channel and input window handle used by the input dispatcher.
final InputWindowHandle mInputWindowHandle;
InputChannel mInputChannel;
- InputChannel mClientChannel;
+ private InputChannel mClientChannel;
// Used to improve performance of toString()
- String mStringNameCache;
- CharSequence mLastTitle;
- boolean mWasExiting;
+ private String mStringNameCache;
+ private CharSequence mLastTitle;
+ private boolean mWasExiting;
final WindowStateAnimator mWinAnimator;
boolean mHasSurface = false;
- boolean mNotOnAppsDisplay = false;
+ private boolean mNotOnAppsDisplay = false;
DisplayContent mDisplayContent;
/** When true this window can be displayed on screens owther than mOwnerUid's */
@@ -486,26 +486,26 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Whether the window was visible when we set the app to invisible last time. WM uses
// this as a hint to restore the surface (if available) for early animation next time
// the app is brought visible.
- boolean mWasVisibleBeforeClientHidden;
+ private boolean mWasVisibleBeforeClientHidden;
// This window will be replaced due to relaunch. This allows window manager
// to differentiate between simple removal of a window and replacement. In the latter case it
// will preserve the old window until the new one is drawn.
boolean mWillReplaceWindow = false;
// If true, the replaced window was already requested to be removed.
- boolean mReplacingRemoveRequested = false;
+ private boolean mReplacingRemoveRequested = false;
// Whether the replacement of the window should trigger app transition animation.
- boolean mAnimateReplacingWindow = false;
+ private boolean mAnimateReplacingWindow = false;
// If not null, the window that will be used to replace the old one. This is being set when
// the window is added and unset when this window reports its first draw.
- WindowState mReplacementWindow = null;
+ private WindowState mReplacementWindow = null;
// For the new window in the replacement transition, if we have
// requested to replace without animation, then we should
// make sure we also don't apply an enter animation for
// the new window.
boolean mSkipEnterAnimationForSeamlessReplacement = false;
// Whether this window is being moved via the resize API
- boolean mMovedByResize;
+ private boolean mMovedByResize;
/**
* Wake lock for drawing.
@@ -514,7 +514,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* who is preventing the system from suspending.
* This lock is only acquired on first use.
*/
- PowerManager.WakeLock mDrawLock;
+ private PowerManager.WakeLock mDrawLock;
final private Rect mTmpRect = new Rect();
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index f4d5c8e898f9..cbdd181ca986 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -9,7 +9,6 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_CLOSE;
@@ -897,6 +896,6 @@ class WindowSurfacePlacer {
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
- pw.println(prefix + "mObsuringWindow=" + mService.mRoot.mObsuringWindow);
+ pw.println(prefix + "mObscuringWindow=" + mService.mRoot.mObscuringWindow);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e7772f339f7a..c30d30f1a8a0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8621,19 +8621,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
synchronized (this) {
if (mOwners.hasDeviceOwner()) {
- if (!mInjector.userManagerIsSplitSystemUser()) {
- // Only split-system-user systems support managed-profiles in combination with
- // device-owner.
- return false;
- }
- if (mOwners.getDeviceOwnerUserId() != UserHandle.USER_SYSTEM) {
- // Only system device-owner supports managed-profiles. Non-system device-owner
- // doesn't.
- return false;
- }
- if (callingUserId == UserHandle.USER_SYSTEM) {
- // Managed-profiles cannot be setup on the system user, only regular users.
- return false;
+ // STOPSHIP Only allow creating a managed profile if allowed by the device
+ // owner. http://b/31952368
+ if (mInjector.userManagerIsSplitSystemUser()) {
+ if (callingUserId == UserHandle.USER_SYSTEM) {
+ // Managed-profiles cannot be setup on the system user.
+ return false;
+ }
}
}
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 4c7545240c23..957a8d30e2f8 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -289,8 +289,15 @@ public class ApfFilter {
return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS;
}
+ public static class InvalidRaException extends Exception {
+ public InvalidRaException(String m) {
+ super(m);
+ }
+ }
+
// A class to hold information about an RA.
- private class Ra {
+ @VisibleForTesting
+ class Ra {
// From RFC4861:
private static final int ICMP6_RA_HEADER_LEN = 16;
private static final int ICMP6_RA_CHECKSUM_OFFSET =
@@ -362,7 +369,7 @@ public class ApfFilter {
} catch (UnsupportedOperationException e) {
// array() failed. Cannot happen, mPacket is array-backed and read-write.
return "???";
- } catch (ClassCastException | UnknownHostException e) {
+ } catch (ClassCastException|UnknownHostException e) {
// Cannot happen.
return "???";
}
@@ -403,7 +410,7 @@ public class ApfFilter {
rdnssOptionToString(sb, i);
}
return sb.toString();
- } catch (BufferUnderflowException | IndexOutOfBoundsException e) {
+ } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
return "<Malformed RA>";
}
}
@@ -436,7 +443,11 @@ public class ApfFilter {
// Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
// (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
// specifications.
- Ra(byte[] packet, int length) {
+ Ra(byte[] packet, int length) throws InvalidRaException {
+ if (length < ICMP6_RA_OPTION_OFFSET) {
+ throw new InvalidRaException("Not an ICMP6 router advertisement");
+ }
+
mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
mLastSeen = curTime();
@@ -445,7 +456,7 @@ public class ApfFilter {
if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
uint8(mPacket.get(IPV6_NEXT_HEADER_OFFSET)) != IPPROTO_ICMPV6 ||
uint8(mPacket.get(ICMP6_TYPE_OFFSET)) != ICMP6_ROUTER_ADVERTISEMENT) {
- throw new IllegalArgumentException("Not an ICMP6 router advertisement");
+ throw new InvalidRaException("Not an ICMP6 router advertisement");
}
@@ -511,7 +522,7 @@ public class ApfFilter {
break;
}
if (optionLength <= 0) {
- throw new IllegalArgumentException(String.format(
+ throw new InvalidRaException(String.format(
"Invalid option length opt=%d len=%d", optionType, optionLength));
}
mPacket.position(position + optionLength);
@@ -925,8 +936,8 @@ public class ApfFilter {
// Execution will reach the end of the program if no filters match, which will pass the
// packet to the AP.
program = gen.generate();
- } catch (IllegalInstructionException e) {
- Log.e(TAG, "Program failed to generate: ", e);
+ } catch (IllegalInstructionException|IllegalStateException e) {
+ Log.e(TAG, "Failed to generate APF program.", e);
return;
}
mLastTimeInstalledProgram = curTime();
@@ -972,7 +983,8 @@ public class ApfFilter {
* if the current APF program should be updated.
* @return a ProcessRaResult enum describing what action was performed.
*/
- private synchronized ProcessRaResult processRa(byte[] packet, int length) {
+ @VisibleForTesting
+ synchronized ProcessRaResult processRa(byte[] packet, int length) {
if (VDBG) hexDump("Read packet = ", packet, length);
// Have we seen this RA before?
@@ -1011,7 +1023,7 @@ public class ApfFilter {
try {
ra = new Ra(packet, length);
} catch (Exception e) {
- Log.e(TAG, "Error parsing RA: " + e);
+ Log.e(TAG, "Error parsing RA", e);
return ProcessRaResult.PARSE_ERROR;
}
// Ignore 0 lifetime RAs.
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index f7c61d15bb5f..37807b22264a 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -16,10 +16,6 @@
package android.net.apf;
-import static android.system.OsConstants.*;
-
-import com.android.frameworks.servicestests.R;
-
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
@@ -37,6 +33,10 @@ import android.system.ErrnoException;
import android.system.Os;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import static android.system.OsConstants.*;
+
+import com.android.frameworks.servicestests.R;
+import com.android.internal.util.HexDump;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -54,6 +54,7 @@ import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.List;
+import java.util.Random;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -1146,6 +1147,39 @@ public class ApfTest extends AndroidTestCase {
buffer.position(original);
}
+ public void testRaParsing() throws Exception {
+ final int maxRandomPacketSize = 512;
+ final Random r = new Random();
+ MockIpManagerCallback cb = new MockIpManagerCallback();
+ TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
+ for (int i = 0; i < 1000; i++) {
+ byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+ r.nextBytes(packet);
+ try {
+ apfFilter.new Ra(packet, packet.length);
+ } catch (ApfFilter.InvalidRaException e) {
+ } catch (Exception e) {
+ throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+ }
+ }
+ }
+
+ public void testRaProcessing() throws Exception {
+ final int maxRandomPacketSize = 512;
+ final Random r = new Random();
+ MockIpManagerCallback cb = new MockIpManagerCallback();
+ TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
+ for (int i = 0; i < 1000; i++) {
+ byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+ r.nextBytes(packet);
+ try {
+ apfFilter.processRa(packet, packet.length);
+ } catch (Exception e) {
+ throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+ }
+ }
+ }
+
/**
* Call the APF interpreter the run {@code program} on {@code packet} pretending the
* filter was installed {@code filter_age} seconds ago.
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 0fb2c9fb28dc..1f0422b4ed50 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -237,6 +237,38 @@ public class UserManagerTest extends AndroidTestCase {
}
}
+ // Make sure createProfile would fail if we have DISALLOW_ADD_USER.
+ @MediumTest
+ public void testCreateProfileForUser_disallowAddUser() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+ try {
+ UserInfo userInfo = createProfileForUser("Managed",
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+ assertNull(userInfo);
+ } finally {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
+ primaryUserHandle);
+ }
+ }
+
+ // Make sure createProfileEvenWhenDisallowedForUser bypass DISALLOW_ADD_USER.
+ @MediumTest
+ public void testCreateProfileForUserEvenWhenDisallowed() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+ try {
+ UserInfo userInfo = createProfileEvenWhenDisallowedForUser("Managed",
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+ assertNotNull(userInfo);
+ } finally {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
+ primaryUserHandle);
+ }
+ }
+
@MediumTest
public void testAddRestrictedProfile() throws Exception {
UserInfo userInfo = createRestrictedProfile("Profile");
@@ -474,6 +506,16 @@ public class UserManagerTest extends AndroidTestCase {
return profile;
}
+ private UserInfo createProfileEvenWhenDisallowedForUser(String name, int flags,
+ int userHandle) {
+ UserInfo profile = mUserManager.createProfileForUserEvenWhenDisallowed(
+ name, flags, userHandle, null);
+ if (profile != null) {
+ usersToRemove.add(profile.id);
+ }
+ return profile;
+ }
+
private UserInfo createRestrictedProfile(String name) {
UserInfo profile = mUserManager.createRestrictedProfile(name);
if (profile != null) {