Merge "Hide QS customizer correctly" am: 03e4eb32fe
am: fb56958223
Change-Id: I62095e8b8c5bea7627e59cf166abce1cfa4ce2f1
diff --git a/Android.mk b/Android.mk
index 491c8be..7a21023f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -857,6 +857,7 @@
-since $(SRC_API_DIR)/22.txt 22 \
-since $(SRC_API_DIR)/23.txt 23 \
-since $(SRC_API_DIR)/24.txt 24 \
+ -since $(SRC_API_DIR)/25.txt 25 \
-werror -hide 111 -hide 113 \
-overview $(LOCAL_PATH)/core/java/overview.html
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index d2e0327..5cc064e 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -839,19 +839,22 @@
tmpConfig = new Configuration();
}
tmpConfig.setTo(config);
+
+ // Get new DisplayMetrics based on the DisplayAdjustments given
+ // to the ResourcesImpl. Update a copy if the CompatibilityInfo
+ // changed, because the ResourcesImpl object will handle the
+ // update internally.
+ DisplayAdjustments daj = r.getDisplayAdjustments();
+ if (compat != null) {
+ daj = new DisplayAdjustments(daj);
+ daj.setCompatibilityInfo(compat);
+ }
+ dm = getDisplayMetrics(displayId, daj);
+
if (!isDefaultDisplay) {
- // Get new DisplayMetrics based on the DisplayAdjustments given
- // to the ResourcesImpl. Udate a copy if the CompatibilityInfo
- // changed, because the ResourcesImpl object will handle the
- // update internally.
- DisplayAdjustments daj = r.getDisplayAdjustments();
- if (compat != null) {
- daj = new DisplayAdjustments(daj);
- daj.setCompatibilityInfo(compat);
- }
- dm = getDisplayMetrics(displayId, daj);
applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
}
+
if (hasOverrideConfiguration) {
tmpConfig.updateFrom(key.mOverrideConfiguration);
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 246a752..b93a557 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1498,6 +1498,36 @@
}
/**
+ * Gets the currently supported profiles by the adapter.
+ *
+ *<p> This can be used to check whether a profile is supported before attempting
+ * to connect to its respective proxy.
+ *
+ * @return a list of integers indicating the ids of supported profiles as defined in
+ * {@link BluetoothProfile}.
+ * @hide
+ */
+ public List<Integer> getSupportedProfiles() {
+ final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>();
+
+ try {
+ synchronized (mManagerCallback) {
+ if (mService != null) {
+ final long supportedProfilesBitMask = mService.getSupportedProfiles();
+
+ for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) {
+ if ((supportedProfilesBitMask & (1 << i)) != 0) {
+ supportedProfiles.add(i);
+ }
+ }
+ }
+ }
+ } catch (RemoteException e) {Log.e(TAG, "getSupportedProfiles:", e);}
+
+ return supportedProfiles;
+ }
+
+ /**
* Get the current connection state of the local Bluetooth adapter.
* This can be used to check whether the local Bluetooth adapter is connected
* to any profile of any other remote Bluetooth Device.
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index eee66d1..20d95cc 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -137,6 +137,13 @@
public static final int PBAP_CLIENT = 17;
/**
+ * Max profile ID. This value should be updated whenever a new profile is added to match
+ * the largest value assigned to a profile.
+ * @hide
+ */
+ public static final int MAX_PROFILE_ID = 17;
+
+ /**
* Default priority for devices that we try to auto-connect to and
* and allow incoming connections for the profile
* @hide
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 8c98536..96a1ae8 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -63,6 +63,7 @@
boolean removeBond(in BluetoothDevice device);
int getBondState(in BluetoothDevice device);
boolean isBondingInitiatedLocally(in BluetoothDevice device);
+ long getSupportedProfiles();
int getConnectionState(in BluetoothDevice device);
String getRemoteName(in BluetoothDevice device);
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index f4db4d6..b7099b6 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -268,6 +268,10 @@
}
public void setTo(DisplayMetrics o) {
+ if (this == o) {
+ return;
+ }
+
widthPixels = o.widthPixels;
heightPixels = o.heightPixels;
density = o.density;
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
new file mode 100644
index 0000000..cf1bf62
--- /dev/null
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.hardware;
+
+import com.android.internal.R;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+public class AmbientDisplayConfiguration {
+
+ private final Context mContext;
+
+ public AmbientDisplayConfiguration(Context context) {
+ mContext = context;
+ }
+
+ public boolean enabled(int user) {
+ return pulseOnNotificationEnabled(user)
+ || pulseOnPickupEnabled(user)
+ || pulseOnDoubleTapEnabled(user);
+ }
+
+ public boolean available() {
+ return pulseOnNotificationAvailable() || pulseOnPickupAvailable()
+ || pulseOnDoubleTapAvailable();
+ }
+
+ public boolean pulseOnNotificationEnabled(int user) {
+ return boolSetting(Settings.Secure.DOZE_ENABLED, user) && pulseOnNotificationAvailable();
+ }
+
+ public boolean pulseOnNotificationAvailable() {
+ return ambientDisplayAvailable();
+ }
+
+ public boolean pulseOnPickupEnabled(int user) {
+ return boolSetting(Settings.Secure.DOZE_PULSE_ON_PICK_UP, user)
+ && pulseOnPickupAvailable();
+ }
+
+ public boolean pulseOnPickupAvailable() {
+ return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup)
+ && ambientDisplayAvailable();
+ }
+
+ public boolean pulseOnDoubleTapEnabled(int user) {
+ return boolSetting(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, user)
+ && pulseOnDoubleTapAvailable();
+ }
+
+ public boolean pulseOnDoubleTapAvailable() {
+ return !TextUtils.isEmpty(doubleTapSensorType()) && ambientDisplayAvailable();
+ }
+
+ public String doubleTapSensorType() {
+ return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
+ }
+
+ public String ambientDisplayComponent() {
+ return mContext.getResources().getString(R.string.config_dozeComponent);
+ }
+
+ private boolean ambientDisplayAvailable() {
+ return !TextUtils.isEmpty(ambientDisplayComponent());
+ }
+
+ private boolean boolSetting(String name, int user) {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, 1, user) != 0;
+ }
+
+}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 644c7e9..4f7b106 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -580,7 +580,13 @@
return;
}
if (grantUriPermission) {
- inputContentInfo.requestPermission();
+ try {
+ inputContentInfo.requestPermission();
+ } catch (Exception e) {
+ Log.e(TAG, "InputConnectionInfo.requestPermission() failed", e);
+ args.callback.setCommitContentResult(false, args.seq);
+ return;
+ }
}
final boolean result =
ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 428159a..ee48264f 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -187,18 +187,17 @@
argv[argc++] = AssetManager::IDMAP_DIR;
// Directories to scan for overlays: if OVERLAY_SKU_DIR_PROPERTY is defined,
- // use OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> if exists, otherwise
- // use OVERLAY_DIR if exists.
+ // use OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> in addition to OVERLAY_DIR.
char subdir[PROP_VALUE_MAX];
int len = __system_property_get(AssetManager::OVERLAY_SKU_DIR_PROPERTY, subdir);
- String8 overlayPath;
if (len > 0) {
- overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
- } else {
- overlayPath = String8(AssetManager::OVERLAY_DIR);
+ String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
+ if (stat(overlayPath.string(), &st) == 0) {
+ argv[argc++] = overlayPath.string();
+ }
}
- if (stat(overlayPath.string(), &st) == 0) {
- argv[argc++] = overlayPath.string();
+ if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
+ argv[argc++] = AssetManager::OVERLAY_DIR;
}
// Finally, invoke idmap (if any overlay directory exists)
diff --git a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
index 307c6db..0ab56f9 100644
--- a/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-notround-watch/alert_dialog_title_material.xml
@@ -22,6 +22,7 @@
android:gravity="top|center_horizontal"
android:minHeight="@dimen/alert_dialog_title_height">
<ImageView android:id="@+id/icon"
+ android:adjustViewBounds="true"
android:maxHeight="24dp"
android:maxWidth="24dp"
android:layout_marginTop="8dp"
diff --git a/core/res/res/layout-round-watch/alert_dialog_title_material.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
index 7e71e41..e543c9b 100644
--- a/core/res/res/layout-round-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
@@ -21,6 +21,7 @@
android:gravity="top|center_horizontal"
android:minHeight="@dimen/alert_dialog_title_height">
<ImageView android:id="@+id/icon"
+ android:adjustViewBounds="true"
android:maxHeight="24dp"
android:maxWidth="24dp"
android:layout_marginTop="12dp"
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index 8a080d9c..af4207e 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -95,7 +95,7 @@
</style>
<style name="DialogWindowTitle.Material">
- <item name="maxLines">3</item>
+ <item name="maxLines">@empty</item>
<item name="scrollHorizontally">false</item>
<item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item>
<item name="gravity">@integer/config_dialogTextGravity</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b75d638..aa39930 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1739,6 +1739,12 @@
turned off and the screen off animation has been performed. -->
<bool name="config_dozeAfterScreenOff">false</bool>
+ <!-- Doze: should the TYPE_PICK_UP_GESTURE sensor be used as a pulse signal. -->
+ <bool name="config_dozePulsePickup">false</bool>
+
+ <!-- Type of the double tap sensor. Empty if double tap is not supported. -->
+ <string name="config_dozeDoubleTapSensorType" translatable="false"></string>
+
<!-- Power Management: Specifies whether to decouple the auto-suspend state of the
device from the display on/off state.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c794351..bbe5ebe 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2679,6 +2679,9 @@
<java-symbol type="string" name="config_emergency_call_number" />
<java-symbol type="array" name="config_emergency_mcc_codes" />
+ <java-symbol type="string" name="config_dozeDoubleTapSensorType" />
+ <java-symbol type="bool" name="config_dozePulsePickup" />
+
<!-- Used for MimeIconUtils. -->
<java-symbol type="drawable" name="ic_doc_apk" />
<java-symbol type="drawable" name="ic_doc_audio" />
diff --git a/docs/html/about/versions/nougat/android-7.0-samples.jd b/docs/html/about/versions/nougat/android-7.0-samples.jd
index e283a7a..ff63bef 100644
--- a/docs/html/about/versions/nougat/android-7.0-samples.jd
+++ b/docs/html/about/versions/nougat/android-7.0-samples.jd
@@ -6,7 +6,7 @@
<p>
Use the code samples below to learn about Android 7.0 capabilities and APIs. To
- download the samples in Android Studio, select the <b>File > Import
+ download the samples in Android Studio, select the <b>File > New > Import
Samples</b> menu option.
</p>
diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd
index ce6ad55..046e99e 100644
--- a/docs/html/training/location/geofencing.jd
+++ b/docs/html/training/location/geofencing.jd
@@ -332,22 +332,39 @@
<p>This section outlines recommendations for using geofencing with the location
APIs for Android.</p>
-<h3>Reduce power consumption</h3>
+<h3>
+ Reduce power consumption
+</h3>
-<p>You can use the following techniques to optimize power consumption in your apps that use geofencing:</p>
+<p>
+ You can use the following techniques to optimize power consumption in your
+ apps that use geofencing:
+</p>
<ul>
-<li><p>Set the <a href="{@docRoot}android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
-notification responsiveness</a> to a higher value. Doing so improves power consumption by
-increasing the latency of geofence alerts. For example, if you set a responsiveness value of five
-minutes your app only checks for an entrance or exit alert once every five minutes.
-Setting lower values does not necessarily mean that users will be notified within that time period
-(for example, if you set a value of 5 seconds it may take a bit longer than that to receive the
-alert).</p></li>
-<li><p>Use a larger geofence radius for locations where a user spends a significant amount of time,
-such as home or work. While a larger radius doesn't directly reduce power consumption, it reduces
-the frequency at which the app checks for entrance or exit, effectively lowering overall power
-consumption.</p></li>
+ <li>
+ <p>
+ Set the <a href=
+ "https://developers.google.com/android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
+ notification responsiveness</a> to a higher value. Doing so improves
+ power consumption by increasing the latency of geofence alerts. For
+ example, if you set a responsiveness value of five minutes your app only
+ checks for an entrance or exit alert once every five minutes. Setting
+ lower values does not necessarily mean that users will be notified
+ within that time period (for example, if you set a value of 5 seconds it
+ may take a bit longer than that to receive the alert).
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Use a larger geofence radius for locations where a user spends a
+ significant amount of time, such as home or work. While a larger radius
+ doesn't directly reduce power consumption, it reduces the frequency at
+ which the app checks for entrance or exit, effectively lowering overall
+ power consumption.
+ </p>
+ </li>
</ul>
<h3>Choose the optimal radius for your geofence</h3>
diff --git a/include/androidfw/Asset.h b/include/androidfw/Asset.h
index ee77e97..52c8637 100644
--- a/include/androidfw/Asset.h
+++ b/include/androidfw/Asset.h
@@ -44,7 +44,7 @@
*/
class Asset {
public:
- virtual ~Asset(void);
+ virtual ~Asset(void) = default;
static int32_t getGlobalCount();
static String8 getAssetAllocations();
@@ -119,6 +119,19 @@
const char* getAssetSource(void) const { return mAssetSource.string(); }
protected:
+ /*
+ * Adds this Asset to the global Asset list for debugging and
+ * accounting.
+ * Concrete subclasses must call this in their constructor.
+ */
+ static void registerAsset(Asset* asset);
+
+ /*
+ * Removes this Asset from the global Asset list.
+ * Concrete subclasses must call this in their destructor.
+ */
+ static void unregisterAsset(Asset* asset);
+
Asset(void); // constructor; only invoked indirectly
/* handle common seek() housekeeping */
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 099d82e..31b692d 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -74,7 +74,7 @@
static const char* OVERLAY_DIR;
/*
* If OVERLAY_SKU_DIR_PROPERTY is set, search for runtime resource overlay
- * APKs in OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> rather than in
+ * APKs in OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> in addition to
* OVERLAY_DIR.
*/
static const char* OVERLAY_SKU_DIR_PROPERTY;
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index 2cfa666..8e8c6a2 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -52,6 +52,47 @@
static Asset* gHead = NULL;
static Asset* gTail = NULL;
+void Asset::registerAsset(Asset* asset)
+{
+ AutoMutex _l(gAssetLock);
+ gCount++;
+ asset->mNext = asset->mPrev = NULL;
+ if (gTail == NULL) {
+ gHead = gTail = asset;
+ } else {
+ asset->mPrev = gTail;
+ gTail->mNext = asset;
+ gTail = asset;
+ }
+
+ if (kIsDebug) {
+ ALOGI("Creating Asset %p #%d\n", asset, gCount);
+ }
+}
+
+void Asset::unregisterAsset(Asset* asset)
+{
+ AutoMutex _l(gAssetLock);
+ gCount--;
+ if (gHead == asset) {
+ gHead = asset->mNext;
+ }
+ if (gTail == asset) {
+ gTail = asset->mPrev;
+ }
+ if (asset->mNext != NULL) {
+ asset->mNext->mPrev = asset->mPrev;
+ }
+ if (asset->mPrev != NULL) {
+ asset->mPrev->mNext = asset->mNext;
+ }
+ asset->mNext = asset->mPrev = NULL;
+
+ if (kIsDebug) {
+ ALOGI("Destroying Asset in %p #%d\n", asset, gCount);
+ }
+}
+
int32_t Asset::getGlobalCount()
{
AutoMutex _l(gAssetLock);
@@ -79,43 +120,8 @@
}
Asset::Asset(void)
- : mAccessMode(ACCESS_UNKNOWN)
+ : mAccessMode(ACCESS_UNKNOWN), mNext(NULL), mPrev(NULL)
{
- AutoMutex _l(gAssetLock);
- gCount++;
- mNext = mPrev = NULL;
- if (gTail == NULL) {
- gHead = gTail = this;
- } else {
- mPrev = gTail;
- gTail->mNext = this;
- gTail = this;
- }
- if (kIsDebug) {
- ALOGI("Creating Asset %p #%d\n", this, gCount);
- }
-}
-
-Asset::~Asset(void)
-{
- AutoMutex _l(gAssetLock);
- gCount--;
- if (gHead == this) {
- gHead = mNext;
- }
- if (gTail == this) {
- gTail = mPrev;
- }
- if (mNext != NULL) {
- mNext->mPrev = mPrev;
- }
- if (mPrev != NULL) {
- mPrev->mNext = mNext;
- }
- mNext = mPrev = NULL;
- if (kIsDebug) {
- ALOGI("Destroying Asset in %p #%d\n", this, gCount);
- }
}
/*
@@ -361,6 +367,9 @@
_FileAsset::_FileAsset(void)
: mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mMap(NULL), mBuf(NULL)
{
+ // Register the Asset with the global list here after it is fully constructed and its
+ // vtable pointer points to this concrete type. b/31113965
+ registerAsset(this);
}
/*
@@ -369,6 +378,10 @@
_FileAsset::~_FileAsset(void)
{
close();
+
+ // Unregister the Asset from the global list here before it is destructed and while its vtable
+ // pointer still points to this concrete type. b/31113965
+ unregisterAsset(this);
}
/*
@@ -685,6 +698,9 @@
: mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL)
{
+ // Register the Asset with the global list here after it is fully constructed and its
+ // vtable pointer points to this concrete type. b/31113965
+ registerAsset(this);
}
/*
@@ -693,6 +709,10 @@
_CompressedAsset::~_CompressedAsset(void)
{
close();
+
+ // Unregister the Asset from the global list here before it is destructed and while its vtable
+ // pointer still points to this concrete type. b/31113965
+ unregisterAsset(this);
}
/*
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 2bc026b7..1fe1773 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -22,6 +22,7 @@
testFiles := \
AppAsLib_test.cpp \
+ Asset_test.cpp \
AttributeFinder_test.cpp \
ByteBucketArray_test.cpp \
Config_test.cpp \
diff --git a/libs/androidfw/tests/Asset_test.cpp b/libs/androidfw/tests/Asset_test.cpp
new file mode 100644
index 0000000..45c8cef
--- /dev/null
+++ b/libs/androidfw/tests/Asset_test.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#include <androidfw/Asset.h>
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+TEST(AssetTest, FileAssetRegistersItself) {
+ const int32_t count = Asset::getGlobalCount();
+ Asset* asset = new _FileAsset();
+ EXPECT_EQ(count + 1, Asset::getGlobalCount());
+ delete asset;
+ EXPECT_EQ(count, Asset::getGlobalCount());
+}
+
+TEST(AssetTest, CompressedAssetRegistersItself) {
+ const int32_t count = Asset::getGlobalCount();
+ Asset* asset = new _CompressedAsset();
+ EXPECT_EQ(count + 1, Asset::getGlobalCount());
+ delete asset;
+ EXPECT_EQ(count, Asset::getGlobalCount());
+}
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 37d9d0e7..7524ba0 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -591,7 +591,7 @@
}
static bool hasMergeableClip(const BakedOpState& state) {
- return state.computedState.clipState
+ return !state.computedState.clipState
|| state.computedState.clipState->mode == ClipMode::Rectangle;
}
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 53dbede..e2dc3a0 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -477,6 +477,35 @@
EXPECT_EQ(4, renderer.getIndex());
}
+RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
+ class RegionClipStopsMergeTestRenderer : public TestRendererBase {
+ public:
+ void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
+ };
+ auto node = TestUtils::createNode(0, 0, 400, 400,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ SkPath path;
+ path.addCircle(200, 200, 200, SkPath::kCW_Direction);
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipPath(&path, SkRegion::kIntersect_Op);
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
+ canvas.restore();
+ });
+
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
+
+ RegionClipStopsMergeTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex());
+}
+
RENDERTHREAD_TEST(FrameBuilder, textMerging) {
class TextMergingTestRenderer : public TestRendererBase {
public:
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 6658e88..00bdc69 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -470,9 +470,7 @@
synchronized (sActiveRingtones) {
sActiveRingtones.remove(Ringtone.this);
}
- if (mLocalPlayer != null) {
- mLocalPlayer.setOnCompletionListener(null);
- }
+ mp.setOnCompletionListener(null); // Help the Java GC: break the refcount cycle.
}
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
index db326ba..012041f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/ExifInterfaceTest.java
@@ -416,7 +416,7 @@
in = getContext().getAssets().open(imageFile.getName());
ExifInterface exifInterface = new ExifInterface(in);
exifInterface.saveAttributes();
- } catch (UnsupportedOperationException e) {
+ } catch (IOException e) {
// Expected. saveAttributes is not supported with an ExifInterface object which was
// created with InputStream.
return;
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 90dd440..8f254e9 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -282,8 +282,8 @@
}
final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
if (info != null) {
- operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
- eventsSupported = mtpDevice.getDeviceInfo().getEventsSupported();
+ operationsSupported = info.getOperationsSupported();
+ eventsSupported = info.getEventsSupported();
}
} else {
roots = new MtpRoot[0];
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 3a16a75..6bc1d12 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -373,7 +373,11 @@
}
public DetailedState getDetailedState() {
- return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
+ if (mNetworkInfo != null) {
+ return mNetworkInfo.getDetailedState();
+ }
+ Log.w(TAG, "NetworkInfo is null, cannot return detailed state");
+ return null;
}
public String getSavedNetworkSummary() {
@@ -813,7 +817,10 @@
return context.getString(R.string.wifi_connected_no_internet);
}
}
-
+ if (state == null) {
+ Log.w(TAG, "state is null, returning empty summary");
+ return "";
+ }
String[] formats = context.getResources().getStringArray((ssid == null)
? R.array.wifi_status : R.array.wifi_status_with_ssid);
int index = state.ordinal();
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index eb1a1eb..9eea375 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -209,9 +209,6 @@
<!-- Doze: should the significant motion sensor be used as a pulse signal? -->
<bool name="doze_pulse_on_significant_motion">false</bool>
- <!-- Doze: should the pickup sensor be used as a pulse signal? -->
- <bool name="doze_pulse_on_pick_up">false</bool>
-
<!-- Doze: check proximity sensor before pulsing? -->
<bool name="doze_proximity_check_before_pulse">true</bool>
@@ -240,9 +237,6 @@
-->
<string name="doze_pickup_subtype_performs_proximity_check"></string>
- <!-- Type of the double tap sensor. Empty if double tap is not supported. -->
- <string name="doze_double_tap_sensor_type" translatable="false"></string>
-
<!-- Doze: pulse parameter - how long does it take to fade in? -->
<integer name="doze_pulse_duration_in">900</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 56f6b8d..6c35243 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -43,6 +43,7 @@
import android.util.Log;
import android.view.Display;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.SystemUIApplication;
@@ -85,6 +86,8 @@
private boolean mCarMode;
private long mNotificationPulseTime;
+ private AmbientDisplayConfiguration mConfig;
+
public DozeService() {
if (DEBUG) Log.d(mTag, "new DozeService()");
setDebug(DEBUG);
@@ -125,6 +128,7 @@
setWindowless(true);
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+ mConfig = new AmbientDisplayConfiguration(mContext);
mSensors = new TriggerSensor[] {
new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
@@ -135,12 +139,12 @@
mPickupSensor = new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
Settings.Secure.DOZE_PULSE_ON_PICK_UP,
- mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
+ mConfig.pulseOnPickupAvailable(), mDozeParameters.getVibrateOnPickup(),
DozeLog.PULSE_REASON_SENSOR_PICKUP),
new TriggerSensor(
- findSensorWithType(mDozeParameters.getDoubleTapSensorType()),
- Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
- mDozeParameters.getPulseOnPickup(), mDozeParameters.getVibrateOnPickup(),
+ findSensorWithType(mConfig.doubleTapSensorType()),
+ Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, true,
+ mDozeParameters.getVibrateOnPickup(),
DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
};
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -359,7 +363,7 @@
private void requestNotificationPulse() {
if (DEBUG) Log.d(mTag, "requestNotificationPulse");
- if (!mDozeParameters.getPulseOnNotifications()) return;
+ if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) return;
mNotificationPulseTime = SystemClock.elapsedRealtime();
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index d5bf499..9e9bdd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -18,11 +18,13 @@
import android.content.Context;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.MathUtils;
import android.util.SparseBooleanArray;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.R;
import java.io.PrintWriter;
@@ -31,9 +33,6 @@
import java.util.regex.Pattern;
public class DozeParameters {
- private static final String TAG = "DozeParameters";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
private static final int MAX_DURATION = 60 * 1000;
private final Context mContext;
@@ -55,10 +54,8 @@
pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration());
pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
pw.print(" getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
- pw.print(" getPulseOnPickup(): "); pw.println(getPulseOnPickup());
pw.print(" getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
pw.print(" getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
- pw.print(" getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println(
dumpPickupSubtypePerformsProxCheck());
@@ -106,26 +103,14 @@
return SystemProperties.getBoolean("doze.vibrate.sigmotion", false);
}
- public boolean getPulseOnPickup() {
- return getBoolean("doze.pulse.pickup", R.bool.doze_pulse_on_pick_up);
- }
-
public boolean getVibrateOnPickup() {
return SystemProperties.getBoolean("doze.vibrate.pickup", false);
}
- public String getDoubleTapSensorType() {
- return mContext.getString(R.string.doze_double_tap_sensor_type);
- }
-
public boolean getProxCheckBeforePulse() {
return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
}
- public boolean getPulseOnNotifications() {
- return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
- }
-
public int getPickupVibrationThreshold() {
return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f6447f6..498fae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -4231,7 +4231,7 @@
}
updateKeyguardState(staying, false /* fromShadeLocked */);
- if (viewToClick != null) {
+ if (viewToClick != null && viewToClick.isAttachedToWindow()) {
viewToClick.callOnClick();
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 4e236d1..0727629 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -838,7 +838,7 @@
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
return syncManager.computeSyncable(
- account, userId, providerName);
+ account, userId, providerName, false);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -854,6 +854,8 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
+ syncable = normalizeSyncable(syncable);
+
int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
@@ -1156,6 +1158,15 @@
}
}
+ private static int normalizeSyncable(int syncable) {
+ if (syncable > 0) {
+ return SyncStorageEngine.AuthorityInfo.SYNCABLE;
+ } else if (syncable == 0) {
+ return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
+ }
+ return SyncStorageEngine.AuthorityInfo.UNDEFINED;
+ }
+
/**
* Hide this class since it is not part of api,
* but current unittest framework requires it to be public
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 131da0b..653d241 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1001,7 +1001,12 @@
}
}
- public int computeSyncable(Account account, int userId, String authority) {
+ private int computeSyncable(Account account, int userId, String authority) {
+ return computeSyncable(account, userId, authority, true);
+ }
+
+ public int computeSyncable(Account account, int userId, String authority,
+ boolean checkAccountAccess) {
final int status = getIsSyncable(account, userId, authority);
if (status == AuthorityInfo.NOT_SYNCABLE) {
return AuthorityInfo.NOT_SYNCABLE;
@@ -1025,7 +1030,7 @@
} catch (RemoteException e) {
/* ignore - local call */
}
- if (!canAccessAccount(account, owningPackage, owningUid)) {
+ if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
Log.w(TAG, "Access to " + account + " denied for package "
+ owningPackage + " in UID " + syncAdapterInfo.uid);
return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 935fa13..a1e3d62 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -321,7 +321,6 @@
mLightSensorEnabled = false;
mRecentLightSamples = 0;
mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
- Slog.d(TAG, "disabling light sensor");
mSensorManager.unregisterListener(mLightSensorListener);
}
}
@@ -349,7 +348,6 @@
}
mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
mAmbientLightRingBuffer.push(time, lux);
- Slog.d(TAG, "pushing lux: " + lux);
// Remember this sample value.
mLastObservedLux = lux;
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 20bccf1..1991c00 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.BIND_DREAM_SERVICE;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -88,6 +89,8 @@
private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ private AmbientDisplayConfiguration mDozeConfig;
+
public DreamManagerService(Context context) {
super(context);
mContext = context;
@@ -97,6 +100,7 @@
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
+ mDozeConfig = new AmbientDisplayConfiguration(mContext);
}
@Override
@@ -121,7 +125,7 @@
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.DOZE_ENABLED), false,
+ Settings.Secure.getUriFor(Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP), false,
mDozeEnabledObserver, UserHandle.USER_ALL);
writePulseGestureEnabled();
}
@@ -326,19 +330,12 @@
}
private ComponentName getDozeComponent(int userId) {
- // Read the component from a system property to facilitate debugging.
- // Note that for production devices, the dream should actually be declared in
- // a config.xml resource.
- String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
- if (TextUtils.isEmpty(name)) {
- // Read the component from a config.xml resource.
- // The value should be specified in a resource overlay for the product.
- name = mContext.getResources().getString(
- com.android.internal.R.string.config_dozeComponent);
+ if (mDozeConfig.enabled(userId)) {
+ return ComponentName.unflattenFromString(mDozeConfig.ambientDisplayComponent());
+ } else {
+ return null;
}
- boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.DOZE_ENABLED, 1, userId) != 0;
- return TextUtils.isEmpty(name) || !enabled ? null : ComponentName.unflattenFromString(name);
+
}
private ServiceInfo getServiceInfo(ComponentName name) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 5dc9d02..72ee218 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -2011,6 +2011,9 @@
@ServiceThreadOnly
void standby() {
assertRunOnServiceThread();
+ if (!canGoToStandby()) {
+ return;
+ }
mStandbyMessageReceived = true;
mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0);
// PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets
@@ -2038,10 +2041,13 @@
@ServiceThreadOnly
private void onStandby(final int standbyAction) {
assertRunOnServiceThread();
- if (!canGoToStandby()) return;
mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
invokeVendorCommandListenersOnControlStateChanged(false,
HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
+ if (!canGoToStandby()) {
+ mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
+ return;
+ }
final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
disableDevices(new PendingActionClearedCallback() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 56a0173..f1bdde0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -464,8 +464,8 @@
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
/**
- * If VENDOR_OVERLAY_SKU_PROPERTY is set, search for runtime resource overlay APKs in
- * VENDOR_OVERLAY_DIR/<value of VENDOR_OVERLAY_SKU_PROPERTY> rather than in
+ * If VENDOR_OVERLAY_SKU_PROPERTY is set, search for runtime resource overlay APKs also in
+ * VENDOR_OVERLAY_DIR/<value of VENDOR_OVERLAY_SKU_PROPERTY> in addition to
* VENDOR_OVERLAY_DIR.
*/
private static final String VENDOR_OVERLAY_SKU_PROPERTY = "ro.boot.vendor.overlay.sku";
@@ -2271,18 +2271,17 @@
}
}
- // Collect vendor overlay packages.
- // (Do this before scanning any apps.)
+ // Collect vendor overlay packages. (Do this before scanning any apps.)
// For security and version matching reason, only consider
// overlay packages if they reside in the right directory.
- File vendorOverlayDir;
String overlaySkuDir = SystemProperties.get(VENDOR_OVERLAY_SKU_PROPERTY);
if (!overlaySkuDir.isEmpty()) {
- vendorOverlayDir = new File(VENDOR_OVERLAY_DIR, overlaySkuDir);
- } else {
- vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
+ scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlaySkuDir), mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR
+ | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
}
- scanDirTracedLI(vendorOverlayDir, mDefParseFlags
+ scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index ae41541..0a9b334 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -21,6 +21,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -85,12 +86,115 @@
mSurfaceControl = ctrl;
mDrawNeeded = true;
mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mScreenOffset = screenOffset;
mMaskThickness = maskThickness;
}
+ static private double distanceFromCenterSquared(double x, double y) {
+ return x*x + y*y;
+ }
+
+ static private double distanceFromCenter(double x, double y) {
+ return Math.sqrt(distanceFromCenterSquared(x, y));
+ }
+
+ static private double verticalLineIntersectsCircle(double x, double radius) {
+ return Math.sqrt(radius*radius - x*x);
+ }
+
+ static private double horizontalLineIntersectsCircle(double y, double radius) {
+ return Math.sqrt(radius*radius - y*y);
+ }
+
+ static private double triangleArea(double width, double height) {
+ return width * height / 2.0;
+ }
+
+ static private double trapezoidArea(double width, double height1, double height2) {
+ return width * (height1 + height2) / 2.0;
+ }
+
+ static private double areaUnderChord(double radius, double chordLength) {
+ double isocelesHeight = Math.sqrt(radius*radius - chordLength * chordLength / 4.0);
+ double areaUnderIsoceles = isocelesHeight * chordLength / 2.0;
+ double halfAngle = Math.asin(chordLength / (2.0 * radius));
+ double areaUnderArc = halfAngle * radius * radius;
+
+ return areaUnderArc - triangleArea(chordLength, isocelesHeight);
+ }
+
+ // Returns the fraction of the pixel at (px, py) covered by
+ // the circle with center (cx, cy) and radius 'radius'
+ static private double calcPixelShading(double cx, double cy, double px,
+ double py, double radius) {
+ // Translate so the center is at the origin
+ px -= cx;
+ py -= cy;
+
+ // Reflect across the axis so the point is in the first quadrant
+ px = Math.abs(px);
+ py = Math.abs(py);
+
+ // One more transformation which simplifies the logic later
+ if (py > px) {
+ double temp;
+
+ temp = px;
+ px = py;
+ py = temp;
+ }
+
+ double left = px - 0.5;
+ double right = px + 0.5;
+ double bottom = py - 0.5;
+ double top = py + 0.5;
+
+ if (distanceFromCenterSquared(left, bottom) > radius*radius) {
+ return 0.0;
+ }
+
+ if (distanceFromCenterSquared(right, top) < radius*radius) {
+ return 1.0;
+ }
+
+ // Check if only the bottom-left corner of the pixel is inside the circle
+ if (distanceFromCenterSquared(left, top) > radius*radius) {
+ double triangleWidth = horizontalLineIntersectsCircle(bottom, radius) - left;
+ double triangleHeight = verticalLineIntersectsCircle(left, radius) - bottom;
+ double chordLength = distanceFromCenter(triangleWidth, triangleHeight);
+
+ return triangleArea(triangleWidth, triangleHeight)
+ + areaUnderChord(radius, chordLength);
+
+ }
+
+ // Check if only the top-right corner of the pixel is outside the circle
+ if (distanceFromCenterSquared(right, bottom) < radius*radius) {
+ double triangleWidth = right - horizontalLineIntersectsCircle(top, radius);
+ double triangleHeight = top - verticalLineIntersectsCircle(right, radius);
+ double chordLength = distanceFromCenter(triangleWidth, triangleHeight);
+
+ return 1 - triangleArea(triangleWidth, triangleHeight)
+ + areaUnderChord(radius, chordLength);
+ }
+
+ // It must be that the top-left and bottom-left corners are inside the circle
+ double trapezoidWidth1 = horizontalLineIntersectsCircle(top, radius) - left;
+ double trapezoidWidth2 = horizontalLineIntersectsCircle(bottom, radius) - left;
+ double chordLength = distanceFromCenter(1, trapezoidWidth2 - trapezoidWidth1);
+ double shading = trapezoidArea(1.0, trapezoidWidth1, trapezoidWidth2)
+ + areaUnderChord(radius, chordLength);
+
+ // When top >= 0 and bottom <= 0 it's possible for the circle to intersect the pixel 4 times.
+ // If so, remove the area of the section which crosses the right-hand edge.
+ if (top >= 0 && bottom <= 0 && radius > right) {
+ shading -= areaUnderChord(radius, 2 * verticalLineIntersectsCircle(right, radius));
+ }
+
+ return shading;
+ }
+
private void drawIfNeeded() {
if (!mDrawNeeded || !mVisible || mDimensionsUnequal) {
return;
@@ -123,11 +227,41 @@
break;
}
- int circleRadius = mScreenSize.x / 2;
c.drawColor(Color.BLACK);
- // The radius is reduced by mMaskThickness to provide an anti aliasing effect on the display edges.
- c.drawCircle(circleRadius, circleRadius, circleRadius - mMaskThickness, mPaint);
+ int maskWidth = mScreenSize.x - 2*mMaskThickness;
+ int maskHeight;
+
+ // Don't render the whole mask if it is partly offscreen.
+ if (maskWidth > mScreenSize.y) {
+ maskHeight = mScreenSize.y;
+ } else {
+ // To ensure the mask can be properly centered on the canvas the
+ // bitmap dimensions must have the same parity as those of the canvas.
+ maskHeight = mScreenSize.y - ((mScreenSize.y - maskWidth) & ~1);
+ }
+
+ double cx = (maskWidth - 1.0) / 2.0;
+ double cy = (maskHeight - 1.0) / 2.0;
+ double radius = maskWidth / 2.0;
+ int[] pixels = new int[maskWidth * maskHeight];
+
+ for (int py=0; py<maskHeight; py++) {
+ for (int px=0; px<maskWidth; px++) {
+ double shading = calcPixelShading(cx, cy, px, py, radius);
+ pixels[maskWidth*py + px] =
+ Color.argb(255 - (int)Math.round(255.0*shading), 0, 0, 0);
+ }
+ }
+
+ Bitmap transparency = Bitmap.createBitmap(pixels, maskWidth, maskHeight,
+ Bitmap.Config.ARGB_8888);
+
+ c.drawBitmap(transparency,
+ (float)mMaskThickness,
+ (float)((mScreenSize.y - maskHeight) / 2),
+ mPaint);
+
mSurface.unlockCanvasAndPost(c);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7b1a523..e8104c4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -28,15 +28,11 @@
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import android.app.ActivityManager.StackId;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Region.Op;
-import android.os.Build;
-import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.Display;
@@ -728,8 +724,7 @@
for (int i = 0; i < windowCount; i++) {
WindowState window = windows.get(i);
if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
- && !window.mPermanentlyHidden && !window.mAnimatingExit
- && !window.mRemoveOnExit) {
+ && !window.isRemovedOrHidden()) {
return false;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 55bf394..fbef2c6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2961,4 +2961,10 @@
public boolean isRtl() {
return mMergedConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
+
+ public boolean isRemovedOrHidden() {
+ return mPermanentlyHidden || mAnimatingExit
+ || mRemoveOnExit || mWindowRemovalAllowed
+ || mViewVisibility == View.GONE;
+ }
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index 0dcd1521..dd7b5a8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -27,6 +27,9 @@
import android.text.TextUtils;
import android.util.Slog;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
import java.util.UUID;
@@ -40,7 +43,7 @@
static final boolean DBG = false;
private static final String NAME = "sound_model.db";
- private static final int VERSION = 5;
+ private static final int VERSION = 6;
public static interface SoundModelContract {
public static final String TABLE = "sound_model";
@@ -58,15 +61,19 @@
// Table Create Statement
private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
+ SoundModelContract.TABLE + "("
- + SoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
- + SoundModelContract.KEY_VENDOR_UUID + " TEXT, "
+ + SoundModelContract.KEY_MODEL_UUID + " TEXT,"
+ + SoundModelContract.KEY_VENDOR_UUID + " TEXT,"
+ SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER,"
+ SoundModelContract.KEY_TYPE + " INTEGER,"
+ SoundModelContract.KEY_DATA + " BLOB,"
+ SoundModelContract.KEY_RECOGNITION_MODES + " INTEGER,"
+ SoundModelContract.KEY_LOCALE + " TEXT,"
+ SoundModelContract.KEY_HINT_TEXT + " TEXT,"
- + SoundModelContract.KEY_USERS + " TEXT" + ")";
+ + SoundModelContract.KEY_USERS + " TEXT,"
+ + "PRIMARY KEY (" + SoundModelContract.KEY_KEYPHRASE_ID + ","
+ + SoundModelContract.KEY_LOCALE + ","
+ + SoundModelContract.KEY_USERS + ")"
+ + ")";
public DatabaseHelper(Context context) {
super(context, NAME, null, VERSION);
@@ -93,6 +100,44 @@
oldVersion++;
}
}
+ if (oldVersion == 5) {
+ // We need to enforce the new primary key constraint that the
+ // keyphrase id, locale, and users are unique. We have to first pull
+ // everything out of the database, remove duplicates, create the new
+ // table, then push everything back in.
+ String selectQuery = "SELECT * FROM " + SoundModelContract.TABLE;
+ Cursor c = db.rawQuery(selectQuery, null);
+ List<SoundModelRecord> old_records = new ArrayList<SoundModelRecord>();
+ try {
+ if (c.moveToFirst()) {
+ do {
+ try {
+ old_records.add(new SoundModelRecord(5, c));
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to extract V5 record", e);
+ }
+ } while (c.moveToNext());
+ }
+ } finally {
+ c.close();
+ }
+ db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
+ onCreate(db);
+ for (SoundModelRecord record : old_records) {
+ if (record.ifViolatesV6PrimaryKeyIsFirstOfAnyDuplicates(old_records)) {
+ try {
+ long return_value = record.writeToDatabase(6, db);
+ if (return_value == -1) {
+ Slog.e(TAG, "Database write failed " + record.modelUuid + ": "
+ + return_value);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to update V6 record " + record.modelUuid, e);
+ }
+ }
+ }
+ oldVersion++;
+ }
}
/**
@@ -279,4 +324,93 @@
}
return users;
}
+
+ private static class SoundModelRecord {
+ public final String modelUuid;
+ public final String vendorUuid;
+ public final int keyphraseId;
+ public final int type;
+ public final byte[] data;
+ public final int recognitionModes;
+ public final String locale;
+ public final String hintText;
+ public final String users;
+
+ public SoundModelRecord(int version, Cursor c) {
+ modelUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_MODEL_UUID));
+ if (version >= 5) {
+ vendorUuid = c.getString(c.getColumnIndex(SoundModelContract.KEY_VENDOR_UUID));
+ } else {
+ vendorUuid = null;
+ }
+ keyphraseId = c.getInt(c.getColumnIndex(SoundModelContract.KEY_KEYPHRASE_ID));
+ type = c.getInt(c.getColumnIndex(SoundModelContract.KEY_TYPE));
+ data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
+ recognitionModes = c.getInt(c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
+ locale = c.getString(c.getColumnIndex(SoundModelContract.KEY_LOCALE));
+ hintText = c.getString(c.getColumnIndex(SoundModelContract.KEY_HINT_TEXT));
+ users = c.getString(c.getColumnIndex(SoundModelContract.KEY_USERS));
+ }
+
+ private boolean V6PrimaryKeyMatches(SoundModelRecord record) {
+ return keyphraseId == record.keyphraseId && stringComparisonHelper(locale, record.locale)
+ && stringComparisonHelper(users, record.users);
+ }
+
+ // Returns true if this record is a) the only record with the same V6 primary key, or b) the
+ // first record in the list of all records that have the same primary key and equal data.
+ // It will return false if a) there are any records that have the same primary key and
+ // different data, or b) there is a previous record in the list that has the same primary
+ // key and data.
+ // Note that 'this' object must be inside the list.
+ public boolean ifViolatesV6PrimaryKeyIsFirstOfAnyDuplicates(
+ List<SoundModelRecord> records) {
+ // First pass - check to see if all the records that have the same primary key have
+ // duplicated data.
+ for (SoundModelRecord record : records) {
+ if (this == record) {
+ continue;
+ }
+ // If we have different/missing data with the same primary key, then we should drop
+ // everything.
+ if (this.V6PrimaryKeyMatches(record) && !Arrays.equals(data, record.data)) {
+ return false;
+ }
+ }
+
+ // We only want to return true for the first duplicated model.
+ for (SoundModelRecord record : records) {
+ if (this.V6PrimaryKeyMatches(record)) {
+ return this == record;
+ }
+ }
+ return true;
+ }
+
+ public long writeToDatabase(int version, SQLiteDatabase db) {
+ ContentValues values = new ContentValues();
+ values.put(SoundModelContract.KEY_MODEL_UUID, modelUuid);
+ if (version >= 5) {
+ values.put(SoundModelContract.KEY_VENDOR_UUID, vendorUuid);
+ }
+ values.put(SoundModelContract.KEY_KEYPHRASE_ID, keyphraseId);
+ values.put(SoundModelContract.KEY_TYPE, type);
+ values.put(SoundModelContract.KEY_DATA, data);
+ values.put(SoundModelContract.KEY_RECOGNITION_MODES, recognitionModes);
+ values.put(SoundModelContract.KEY_LOCALE, locale);
+ values.put(SoundModelContract.KEY_HINT_TEXT, hintText);
+ values.put(SoundModelContract.KEY_USERS, users);
+
+ return db.insertWithOnConflict(
+ SoundModelContract.TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE);
+ }
+
+ // Helper for checking string equality - including the case when they are null.
+ static private boolean stringComparisonHelper(String a, String b) {
+ if (a != null) {
+ return a.equals(b);
+ }
+ return a == b;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7432de9..4dcc7d5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -726,6 +726,16 @@
public static final String KEY_CARRIER_ADDITIONAL_CBS_CHANNELS_STRINGS =
"carrier_additional_cbs_channels_strings";
+ /**
+ * Indicates whether STK LAUNCH_BROWSER command is disabled.
+ * If {@code true}, then the browser will not be launched
+ * on UI for the LAUNCH_BROWSER STK command.
+ * @hide
+ */
+ public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
+ "stk_disable_launch_browser_bool";
+
+
// These variables are used by the MMS service and exposed through another API, {@link
// SmsManager}. The variable names and string values are copied from there.
public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -1194,6 +1204,7 @@
sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
+ sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
}
/**