Merge "Expose APIs to analyze UIDs in UserHandle/Process." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 0d031bc..8edab67 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22874,6 +22874,7 @@
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
diff --git a/api/system-current.txt b/api/system-current.txt
index 1af8150..54ddf49 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24492,6 +24492,7 @@
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
diff --git a/api/test-current.txt b/api/test-current.txt
index b6b8697..6626501 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -22883,6 +22883,7 @@
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 83f9357..5f3adda 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5730,4 +5730,32 @@
return false;
}
}
+
+ /**
+ * @hide
+ * Returns whether the uninstall for {@code packageName} for the current user is in queue
+ * to be started
+ * @param packageName the package to check for
+ * @return whether the uninstall intent for {@code packageName} is pending
+ */
+ public boolean isUninstallInQueue(String packageName) {
+ try {
+ return mService.isUninstallInQueue(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ return false;
+ }
+ }
+
+ /**
+ * @hide
+ * @param packageName the package containing active DAs to be uninstalled
+ */
+ public void uninstallPackageWithActiveAdmins(String packageName) {
+ try {
+ mService.uninstallPackageWithActiveAdmins(packageName);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c6a5344..2758f41 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -293,4 +293,7 @@
boolean getDeviceLoggingEnabled(in ComponentName admin);
ParceledListSlice retrieveDeviceLogs(in ComponentName admin);
ParceledListSlice retrievePreviousDeviceLogs(in ComponentName admin);
+
+ boolean isUninstallInQueue(String packageName);
+ void uninstallPackageWithActiveAdmins(String packageName);
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index c79dae5..9082482 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1038,10 +1038,10 @@
}
deviceEncryptedDataDir = Environment
- .getDataUserDeviceEncryptedPackageDirectory(volumeUuid, userId, packageName)
+ .getDataUserDePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
credentialEncryptedDataDir = Environment
- .getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName)
+ .getDataUserCePackageDirectory(volumeUuid, userId, packageName)
.getAbsolutePath();
if ((privateFlags & PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED) != 0
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 766868d..8724a96 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -847,6 +847,9 @@
* to make forward progress from the partial results and avoid waiting for the completed
* result.</p>
*
+ * <p>For a particular request, {@link #onCaptureProgressed} may happen before or after
+ * {@link #onCaptureStarted}.</p>
+ *
* <p>Each request will generate at least {@code 1} partial results, and at most
* {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT} partial results.</p>
*
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e841dfe..59bf293 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -176,35 +176,37 @@
return DIR_VENDOR_ROOT;
}
- /** {@hide} */
- @Deprecated
- public static File getSystemSecureDirectory() {
- return getDataSystemDirectory();
- }
-
- /** {@hide} */
- @Deprecated
- public static File getSecureDataDirectory() {
- return getDataDirectory();
- }
-
/**
- * Return the system directory for a user. This is for use by system services to store
- * files relating to the user. This directory will be automatically deleted when the user
- * is removed.
+ * Return the system directory for a user. This is for use by system
+ * services to store files relating to the user. This directory will be
+ * automatically deleted when the user is removed.
*
+ * @deprecated This directory is valid and still exists, but callers should
+ * <em>strongly</em> consider switching to
+ * {@link #getDataSystemCeDirectory(int)} which is protected
+ * with user credentials or
+ * {@link #getDataSystemDeDirectory(int)} which supports fast
+ * user wipe.
* @hide
*/
+ @Deprecated
public static File getUserSystemDirectory(int userId) {
return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
}
/**
- * Returns the config directory for a user. This is for use by system services to store files
- * relating to the user which should be readable by any app running as that user.
+ * Returns the config directory for a user. This is for use by system
+ * services to store files relating to the user which should be readable by
+ * any app running as that user.
*
+ * @deprecated This directory is valid and still exists, but callers should
+ * <em>strongly</em> consider switching to
+ * {@link #getDataMiscCeDirectory(int)} which is protected with
+ * user credentials or {@link #getDataMiscDeDirectory(int)}
+ * which supports fast user wipe.
* @hide
*/
+ @Deprecated
public static File getUserConfigDirectory(int userId) {
return new File(new File(new File(
getDataDirectory(), "misc"), "user"), Integer.toString(userId));
@@ -232,13 +234,28 @@
}
/** {@hide} */
- public static File getDataSystemCredentialEncryptedDirectory() {
- return new File(getDataDirectory(), "system_ce");
+ public static File getDataSystemCeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
}
/** {@hide} */
- public static File getDataSystemCredentialEncryptedDirectory(int userId) {
- return new File(getDataSystemCredentialEncryptedDirectory(), String.valueOf(userId));
+ public static File getDataSystemDeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
+ }
+
+ /** {@hide} */
+ public static File getDataMiscDirectory() {
+ return new File(getDataDirectory(), "misc");
+ }
+
+ /** {@hide} */
+ public static File getDataMiscCeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
+ }
+
+ /** {@hide} */
+ public static File getDataMiscDeDirectory(int userId) {
+ return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
}
/** {@hide} */
@@ -252,57 +269,37 @@
}
/** {@hide} */
- @Deprecated
- public static File getDataUserDirectory(String volumeUuid) {
- return getDataUserCredentialEncryptedDirectory(volumeUuid);
- }
-
- /** {@hide} */
- @Deprecated
- public static File getDataUserDirectory(String volumeUuid, int userId) {
- return getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
- }
-
- /** {@hide} */
- @Deprecated
- public static File getDataUserPackageDirectory(String volumeUuid, int userId,
- String packageName) {
- return getDataUserCredentialEncryptedPackageDirectory(volumeUuid, userId, packageName);
- }
-
- /** {@hide} */
- public static File getDataUserCredentialEncryptedDirectory(String volumeUuid) {
+ public static File getDataUserCeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user");
}
/** {@hide} */
- public static File getDataUserCredentialEncryptedDirectory(String volumeUuid, int userId) {
- return new File(getDataUserCredentialEncryptedDirectory(volumeUuid),
- String.valueOf(userId));
+ public static File getDataUserCeDirectory(String volumeUuid, int userId) {
+ return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
}
/** {@hide} */
- public static File getDataUserCredentialEncryptedPackageDirectory(String volumeUuid, int userId,
+ public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
String packageName) {
// TODO: keep consistent with installd
- return new File(getDataUserCredentialEncryptedDirectory(volumeUuid, userId), packageName);
+ return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedDirectory(String volumeUuid) {
+ public static File getDataUserDeDirectory(String volumeUuid) {
return new File(getDataDirectory(volumeUuid), "user_de");
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedDirectory(String volumeUuid, int userId) {
- return new File(getDataUserDeviceEncryptedDirectory(volumeUuid), String.valueOf(userId));
+ public static File getDataUserDeDirectory(String volumeUuid, int userId) {
+ return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
}
/** {@hide} */
- public static File getDataUserDeviceEncryptedPackageDirectory(String volumeUuid, int userId,
+ public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
String packageName) {
// TODO: keep consistent with installd
- return new File(getDataUserDeviceEncryptedDirectory(volumeUuid, userId), packageName);
+ return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
}
/**
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index ea54f92..4d3bea4 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -223,4 +223,98 @@
return res != null && res.getBoolean(RES_CAN_BLOCK_NUMBERS, false);
}
+ /**
+ * <p>
+ * The contract between the blockednumber provider and the system.
+ * </p>
+ * <p>This is a wrapper over {@link BlockedNumberContract} that also manages the blocking
+ * behavior when the user contacts emergency services. See
+ * {@link #notifyEmergencyContact(Context)} for details. All methods are protected by
+ * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} and
+ * {@link android.Manifest.permission#WRITE_BLOCKED_NUMBERS} appropriately which ensure that
+ * only system can access the methods defined here.
+ * </p>
+ * @hide
+ */
+ public static class SystemContract {
+ /**
+ * A protected broadcast intent action for letting components with
+ * {@link android.Manifest.permission#READ_BLOCKED_NUMBERS} know that the block suppressal
+ * status as returned by {@link #getBlockSuppressalStatus(Context)} has been updated.
+ */
+ public static final String ACTION_BLOCK_SUPPRESSAL_STATE_CHANGED =
+ "android.provider.action.BLOCK_SUPPRESSAL_STATE_CHANGED";
+
+ public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
+
+ public static final String METHOD_END_BLOCK_SUPPRESSAL = "end_block_suppressal";
+
+ public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
+
+ public static final String METHOD_GET_BLOCK_SUPPRESSAL_STATUS =
+ "get_block_suppresal_status";
+
+ public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
+
+ public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
+ "blocking_suppressed_until_timestamp";
+
+ /**
+ * Notifies the provider that emergency services were contacted by the user.
+ * <p> This results in {@link #shouldSystemBlockNumber} returning {@code false} independent
+ * of the contents of the provider for a duration defined by
+ * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}
+ * the provider unless {@link #endBlockSuppressal(Context)} is called.
+ */
+ public static void notifyEmergencyContact(Context context) {
+ context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_NOTIFY_EMERGENCY_CONTACT, null, null);
+ }
+
+ /**
+ * Notifies the provider to disable suppressing blocking. If emergency services were not
+ * contacted recently at all, calling this method is a no-op.
+ */
+ public static void endBlockSuppressal(Context context) {
+ context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_END_BLOCK_SUPPRESSAL, null, null);
+ }
+
+ /**
+ * Returns {@code true} if {@code phoneNumber} is blocked taking
+ * {@link #notifyEmergencyContact(Context)} into consideration. If emergency services have
+ * not been contacted recently, this method is equivalent to
+ * {@link #isBlocked(Context, String)}.
+ */
+ public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
+ return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
+ }
+
+ public static BlockSuppressalStatus getBlockSuppressalStatus(Context context) {
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSAL_STATUS, null, null);
+ return new BlockSuppressalStatus(res.getBoolean(RES_IS_BLOCKING_SUPPRESSED, false),
+ res.getLong(RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP, 0));
+ }
+
+ /**
+ * Represents the current status of {@link #shouldSystemBlockNumber(Context, String)}. If
+ * emergency services have been contacted recently, {@link #isSuppressed} is {@code true},
+ * and blocking is disabled until the timestamp {@link #untilTimestampMillis}.
+ */
+ public static class BlockSuppressalStatus {
+ public final boolean isSuppressed;
+ /**
+ * Timestamp in milliseconds from epoch.
+ */
+ public final long untilTimestampMillis;
+
+ BlockSuppressalStatus(boolean isSuppressed, long untilTimestampMillis) {
+ this.isSuppressed = isSuppressed;
+ this.untilTimestampMillis = untilTimestampMillis;
+ }
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b0fb93b..3402989 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -45,6 +45,7 @@
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.provider.DocumentsContract;
import android.service.chooser.ChooserTarget;
import android.service.chooser.ChooserTargetService;
@@ -232,7 +233,7 @@
// the case where we don't have access to credential encrypted storage we just won't
// have our pinned target info.
final File prefsFile = new File(new File(
- Environment.getDataUserCredentialEncryptedPackageDirectory(null,
+ Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
context.getUserId(), context.getPackageName()),
"shared_prefs"),
PINNED_SHARED_PREFS_NAME + ".xml");
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 210adce..465c4d8 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -104,6 +104,9 @@
}
private boolean isSuggestionOfType(int suggestionMask) {
+ if (!mIsTranslated) { // Never suggest an untranslated locale
+ return false;
+ }
return (mSuggestionFlags & suggestionMask) == suggestionMask;
}
@@ -207,6 +210,27 @@
}
}
+ /*
+ * Show all the languages supported for a country in the suggested list.
+ * This is also handy for devices without SIM (tablets).
+ */
+ private static void addSuggestedLocalesForRegion(Locale locale) {
+ if (locale == null) {
+ return;
+ }
+ final String country = locale.getCountry();
+ if (country.isEmpty()) {
+ return;
+ }
+
+ for (LocaleInfo li : sLocaleCache.values()) {
+ if (country.equals(li.getLocale().getCountry())) {
+ // We don't need to differentiate between manual and SIM suggestions
+ li.mSuggestionFlags |= LocaleInfo.SUGGESTION_TYPE_SIM;
+ }
+ }
+ }
+
public static void fillCache(Context context) {
if (sFullyInitialized) {
return;
@@ -256,6 +280,8 @@
li.setTranslated(localizedLocales.contains(li.getLangScriptKey()));
}
+ addSuggestedLocalesForRegion(Locale.getDefault());
+
sFullyInitialized = true;
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index dd0e456..ac77007 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -322,7 +322,11 @@
void NotifyHandler::handleMessage(const Message& message) {
JNIEnv* env = getenv(mVm);
- jobject target = env->NewLocalRef(mObserver->getObserverReference());
+ ObserverProxy* observer = mObserver.get();
+ LOG_ALWAYS_FATAL_IF(observer == nullptr, "received message with no observer configured");
+ LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "received message with no data to report");
+
+ jobject target = env->NewLocalRef(observer->getObserverReference());
if (target != nullptr) {
jlongArray javaBuffer = get_metrics_buffer(env, target);
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 63df5be..61753b1 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -25,6 +25,7 @@
<style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" />
<style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Micro.Dialog" />
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.Micro" />
<style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Micro" />
</resources>
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 3db28c9..5a5845a 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -100,7 +100,7 @@
static BakedOpState* tryConstruct(LinearAllocator& allocator,
Snapshot& snapshot, const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- BakedOpState* bakedState = new (allocator) BakedOpState(
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
allocator, snapshot, recordedOp, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
@@ -124,7 +124,7 @@
? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
: true;
- BakedOpState* bakedState = new (allocator) BakedOpState(
+ BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
allocator, snapshot, recordedOp, expandForStroke);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
@@ -140,16 +140,12 @@
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
// clip isn't empty, so construct the op
- return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
+ return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
}
static BakedOpState* directConstruct(LinearAllocator& allocator,
const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
- return new (allocator) BakedOpState(clip, dstRect, recordedOp);
- }
-
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
}
// computed state:
@@ -162,6 +158,8 @@
const RecordedOp* op;
private:
+ friend class LinearAllocator;
+
BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
const RecordedOp& recordedOp, bool expandForStroke)
: computedState(allocator, snapshot, recordedOp, expandForStroke)
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index c2e14a2..6d5833b 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -45,7 +45,7 @@
};
DamageAccumulator::DamageAccumulator() {
- mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ mHead = mAllocator.create_trivial<DirtyStack>();
memset(mHead, 0, sizeof(DirtyStack));
// Create a root that we will not pop off
mHead->prev = mHead;
@@ -78,7 +78,7 @@
void DamageAccumulator::pushCommon() {
if (!mHead->next) {
- DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ DirtyStack* nextFrame = mAllocator.create_trivial<DirtyStack>();
nextFrame->next = nullptr;
nextFrame->prev = mHead;
mHead->next = nextFrame;
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 2d5979f..98ccf11 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -49,11 +49,6 @@
class DeferredDisplayState {
public:
- static void* operator new(size_t size) = delete;
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
// global op bounds, mapped by mMatrix to be in screen space coordinates, clipped
Rect mBounds;
@@ -124,7 +119,7 @@
DeferredDisplayList(const DeferredDisplayList& other); // disallow copy
DeferredDisplayState* createState() {
- return new (mAllocator) DeferredDisplayState();
+ return mAllocator.create_trivial<DeferredDisplayState>();
}
void tryRecycleState(DeferredDisplayState* state) {
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index e5711e3..a703e22 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -251,7 +251,7 @@
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+ T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -320,8 +320,7 @@
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
- SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
- alloc().autoDestroy(localBitmap);
+ SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
mDisplayList->bitmapResources.push_back(localBitmap);
return localBitmap;
}
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 20501ba..98315d0 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -64,7 +64,9 @@
static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); }
static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ // FIXME: Quick hack to keep old pipeline working, delete this when
+ // we no longer need to support HWUI_NEWOPS := false
+ return allocator.alloc<char>(size);
}
enum OpLogFlag {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 185acce..4f51036 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -209,7 +209,7 @@
// not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
if (node.getLayer()) {
// HW layer
- LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
+ LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(node);
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
if (bakedOpState) {
// Node's layer already deferred, schedule it to render into parent layer
@@ -220,13 +220,13 @@
// (temp layers are clipped to viewport, since they don't persist offscreen content)
SkPaint saveLayerPaint;
saveLayerPaint.setAlpha(properties.getAlpha());
- deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
+ deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>(
saveLayerBounds,
Matrix4::identity(),
nullptr, // no record-time clip - need only respect defer-time one
&saveLayerPaint));
deferNodeOps(node);
- deferEndLayerOp(*new (mAllocator) EndLayerOp());
+ deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>());
} else {
deferNodeOps(node);
}
@@ -549,7 +549,7 @@
void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
const SkBitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
SkPaint* paint = op.vectorDrawable->getPaint();
- const BitmapRectOp* resolvedOp = new (mAllocator) BitmapRectOp(op.unmappedBounds,
+ const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
op.localMatrix,
op.localClip,
paint,
@@ -565,7 +565,7 @@
float y = *(op.y);
float radius = *(op.radius);
Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
- const OvalOp* resolvedOp = new (mAllocator) OvalOp(
+ const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(
unmappedBounds,
op.localMatrix,
op.localClip,
@@ -626,7 +626,7 @@
void FrameBuilder::deferRoundRectPropsOp(const RoundRectPropsOp& op) {
// allocate a temporary round rect op (with mAllocator, so it persists until render), so the
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
- const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
+ const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>(
Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
op.localMatrix,
op.localClip,
@@ -754,7 +754,7 @@
// record the draw operation into the previous layer's list of draw commands
// uses state from the associated beginLayerOp, since it has all the state needed for drawing
- LayerOp* drawLayerOp = new (mAllocator) LayerOp(
+ LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(
beginLayerOp.unmappedBounds,
beginLayerOp.localMatrix,
beginLayerOp.localClip,
@@ -788,7 +788,7 @@
/**
* First, defer an operation to copy out the content from the rendertarget into a layer.
*/
- auto copyToOp = new (mAllocator) CopyToLayerOp(op, layerHandle);
+ auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
&(currentLayer().viewportClip), dstRect, *copyToOp);
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
@@ -803,7 +803,7 @@
* And stash an operation to copy that layer back under the rendertarget until
* a balanced EndUnclippedLayerOp is seen
*/
- auto copyFromOp = new (mAllocator) CopyFromLayerOp(op, layerHandle);
+ auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
bakedState = BakedOpState::directConstruct(mAllocator,
&(currentLayer().viewportClip), dstRect, *copyFromOp);
currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index 7170d4f..1ba3bf2 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -64,10 +64,6 @@
class OpBatch : public BatchBase {
public:
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
OpBatch(batchid_t batchId, BakedOpState* op)
: BatchBase(batchId, op, false) {
}
@@ -80,10 +76,6 @@
class MergingOpBatch : public BatchBase {
public:
- static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
- }
-
MergingOpBatch(batchid_t batchId, BakedOpState* op)
: BatchBase(batchId, op, true)
, mClipSideFlags(op->computedState.clipSideFlags) {
@@ -247,7 +239,7 @@
// put the verts in the frame allocator, since
// 1) SimpleRectsOps needs verts, not rects
// 2) even if mClearRects stored verts, std::vectors will move their contents
- Vertex* const verts = (Vertex*) allocator.alloc(vertCount * sizeof(Vertex));
+ Vertex* const verts = (Vertex*) allocator.alloc<Vertex>(vertCount * sizeof(Vertex));
Vertex* currentVert = verts;
Rect bounds = mClearRects[0];
@@ -264,7 +256,7 @@
// Flush all of these clears with a single draw
SkPaint* paint = allocator.create<SkPaint>();
paint->setXfermodeMode(SkXfermode::kClear_Mode);
- SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds,
+ SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds,
Matrix4::identity(), nullptr, paint,
verts, vertCount);
BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
@@ -292,7 +284,7 @@
targetBatch->batchOp(op);
} else {
// new non-merging batch
- targetBatch = new (allocator) OpBatch(batchId, op);
+ targetBatch = allocator.create<OpBatch>(batchId, op);
mBatchLookup[batchId] = targetBatch;
mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
}
@@ -323,7 +315,7 @@
targetBatch->mergeOp(op);
} else {
// new merging batch
- targetBatch = new (allocator) MergingOpBatch(batchId, op);
+ targetBatch = allocator.create<MergingOpBatch>(batchId, op);
mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch);
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 16929b8..269e590 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -83,9 +83,9 @@
void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
if (removed.flags & Snapshot::kFlagIsFboLayer) {
- addOp(new (alloc()) EndLayerOp());
+ addOp(alloc().create_trivial<EndLayerOp>());
} else if (removed.flags & Snapshot::kFlagIsLayer) {
- addOp(new (alloc()) EndUnclippedLayerOp());
+ addOp(alloc().create_trivial<EndUnclippedLayerOp>());
}
}
@@ -167,7 +167,7 @@
snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot.roundRectClipState = nullptr;
- addOp(new (alloc()) BeginLayerOp(
+ addOp(alloc().create_trivial<BeginLayerOp>(
unmappedBounds,
*previous.transform, // transform to *draw* with
previousClip, // clip to *draw* with
@@ -175,7 +175,7 @@
} else {
snapshot.flags |= Snapshot::kFlagIsLayer;
- addOp(new (alloc()) BeginUnclippedLayerOp(
+ addOp(alloc().create_trivial<BeginUnclippedLayerOp>(
unmappedBounds,
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -241,7 +241,7 @@
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
- addOp(new (alloc()) RectOp(
+ addOp(alloc().create_trivial<RectOp>(
mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
Matrix4::identity(),
getRecordedClip(),
@@ -261,7 +261,7 @@
if (floatCount < 2) return;
floatCount &= ~0x1; // round down to nearest two
- addOp(new (alloc()) PointsOp(
+ addOp(alloc().create_trivial<PointsOp>(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -272,7 +272,7 @@
if (floatCount < 4) return;
floatCount &= ~0x3; // round down to nearest four
- addOp(new (alloc()) LinesOp(
+ addOp(alloc().create_trivial<LinesOp>(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
getRecordedClip(),
@@ -280,7 +280,7 @@
}
void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
- addOp(new (alloc()) RectOp(
+ addOp(alloc().create_trivial<RectOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -290,7 +290,7 @@
void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
if (rects == nullptr) return;
- Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc(vertexCount * sizeof(Vertex));
+ Vertex* rectData = (Vertex*) mDisplayList->allocator.alloc<Vertex>(vertexCount * sizeof(Vertex));
Vertex* vertex = rectData;
float left = FLT_MAX;
@@ -313,7 +313,7 @@
right = std::max(right, r);
bottom = std::max(bottom, b);
}
- addOp(new (alloc()) SimpleRectsOp(
+ addOp(alloc().create_trivial<SimpleRectsOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -347,7 +347,7 @@
}
void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint& paint) {
- addOp(new (alloc()) RoundRectOp(
+ addOp(alloc().create_trivial<RoundRectOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -367,7 +367,7 @@
mDisplayList->ref(ry);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(new (alloc()) RoundRectPropsOp(
+ addOp(alloc().create_trivial<RoundRectPropsOp>(
*(mState.currentSnapshot()->transform),
getRecordedClip(),
&paint->value,
@@ -389,7 +389,7 @@
mDisplayList->ref(radius);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(new (alloc()) CirclePropsOp(
+ addOp(alloc().create_trivial<CirclePropsOp>(
*(mState.currentSnapshot()->transform),
getRecordedClip(),
&paint->value,
@@ -397,7 +397,7 @@
}
void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
- addOp(new (alloc()) OvalOp(
+ addOp(alloc().create_trivial<OvalOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -406,7 +406,7 @@
void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
- addOp(new (alloc()) ArcOp(
+ addOp(alloc().create_trivial<ArcOp>(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -415,7 +415,7 @@
}
void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
- addOp(new (alloc()) PathOp(
+ addOp(alloc().create_trivial<PathOp>(
Rect(path.getBounds()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -424,7 +424,7 @@
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- addOp(new (alloc()) VectorDrawableOp(
+ addOp(alloc().create_trivial<VectorDrawableOp>(
tree,
Rect(tree->getBounds()),
*(mState.currentSnapshot()->transform),
@@ -475,7 +475,7 @@
drawBitmap(&bitmap, paint);
restore();
} else {
- addOp(new (alloc()) BitmapRectOp(
+ addOp(alloc().create_trivial<BitmapRectOp>(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -487,7 +487,7 @@
void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
int vertexCount = (meshWidth + 1) * (meshHeight + 1);
- addOp(new (alloc()) BitmapMeshOp(
+ addOp(alloc().create_trivial<BitmapMeshOp>(
calcBoundsOfPoints(vertices, vertexCount * 2),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -499,7 +499,7 @@
void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& patch,
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) {
- addOp(new (alloc()) PatchOp(
+ addOp(alloc().create_trivial<PatchOp>(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -515,7 +515,7 @@
positions = refBuffer<float>(positions, glyphCount * 2);
// TODO: either must account for text shadow in bounds, or record separate ops for text shadows
- addOp(new (alloc()) TextOp(
+ addOp(alloc().create_trivial<TextOp>(
Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -527,7 +527,7 @@
float hOffset, float vOffset, const SkPaint& paint) {
if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
- addOp(new (alloc()) TextOnPathOp(
+ addOp(alloc().create_trivial<TextOnPathOp>(
mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -535,7 +535,7 @@
}
void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
- addOp(new (alloc()) BitmapOp(
+ addOp(alloc().create_trivial<BitmapOp>(
Rect(bitmap->width(), bitmap->height()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -544,7 +544,7 @@
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
auto&& stagingProps = renderNode->stagingProperties();
- RenderNodeOp* op = new (alloc()) RenderNodeOp(
+ RenderNodeOp* op = alloc().create_trivial<RenderNodeOp>(
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
*(mState.currentSnapshot()->transform),
getRecordedClip(),
@@ -570,7 +570,7 @@
Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
totalTransform.multiply(layer->getTransform());
- addOp(new (alloc()) TextureLayerOp(
+ addOp(alloc().create_trivial<TextureLayerOp>(
Rect(layer->getWidth(), layer->getHeight()),
totalTransform,
getRecordedClip(),
@@ -579,7 +579,7 @@
void RecordingCanvas::callDrawGLFunction(Functor* functor) {
mDisplayList->functors.push_back(functor);
- addOp(new (alloc()) FunctorOp(
+ addOp(alloc().create_trivial<FunctorOp>(
mState.getLocalClipBounds(), // TODO: explicitly define bounds
*(mState.currentSnapshot()->transform),
getRecordedClip(),
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index cc14e61..719872d 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -219,7 +219,7 @@
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc(count * sizeof(T));
+ T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -290,8 +290,7 @@
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
- SkBitmap* localBitmap = new (alloc()) SkBitmap(bitmap);
- alloc().autoDestroy(localBitmap);
+ SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap);
mDisplayList->bitmapResources.push_back(localBitmap);
return localBitmap;
}
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index dbaa905..0ac2f14 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -46,7 +46,7 @@
public:
/** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.alloc<RoundRectClipState>(size);
}
bool areaRequiresRoundRectClip(const Rect& rect) const {
@@ -67,7 +67,7 @@
public:
/** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
static void* operator new(size_t size, LinearAllocator& allocator) {
- return allocator.alloc(size);
+ return allocator.alloc<ProjectionPathMask>(size);
}
const SkPath* projectionMask;
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 5c44290..402a09c 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -30,7 +30,7 @@
TEST(LinearAllocator, create) {
LinearAllocator la;
EXPECT_EQ(0u, la.usedSize());
- la.alloc(64);
+ la.alloc<char>(64);
// There's some internal tracking as well as padding
// so the usedSize isn't strictly defined
EXPECT_LE(64u, la.usedSize());
@@ -50,13 +50,12 @@
la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
la.create<SimplePair>();
}
- la.alloc(100);
+ la.alloc<char>(100);
for (int i = 0; i < 5; i++) {
- auto sd = new (la) TestUtils::SignalingDtor(destroyed + 5 + i);
- la.autoDestroy(sd);
- new (la) SimplePair();
+ la.create<TestUtils::SignalingDtor>(destroyed + 5 + i);
+ la.create_trivial<SimplePair>();
}
- la.alloc(100);
+ la.alloc<char>(100);
for (int i = 0; i < 10; i++) {
EXPECT_EQ(0, destroyed[i]);
}
@@ -70,7 +69,7 @@
int destroyed = 0;
{
LinearAllocator la;
- auto addr = la.alloc(100);
+ auto addr = la.alloc<char>(100);
EXPECT_LE(100u, la.usedSize());
la.rewindIfLastAlloc(addr, 100);
EXPECT_GT(16u, la.usedSize());
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index e6a4c03..5bba420 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -81,10 +81,6 @@
#define min(x,y) (((x) < (y)) ? (x) : (y))
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la) {
- return la.alloc(size);
-}
-
namespace android {
namespace uirenderer {
@@ -171,7 +167,7 @@
mNext = start(mCurrentPage);
}
-void* LinearAllocator::alloc(size_t size) {
+void* LinearAllocator::allocImpl(size_t size) {
size = ALIGN(size);
if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
@@ -196,7 +192,7 @@
"DestructorNode must have standard layout");
static_assert(std::is_trivially_destructible<DestructorNode>::value,
"DestructorNode must be trivially destructable");
- auto node = new (*this) DestructorNode();
+ auto node = new (allocImpl(sizeof(DestructorNode))) DestructorNode();
node->dtor = dtor;
node->addr = addr;
node->next = mDtorList;
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index dcbc0dd..0a0e185 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -52,30 +52,36 @@
* The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
* delete() on an object stored in a buffer is needed, it should be overridden to use
* rewindIfLastAlloc()
+ *
+ * Note that unlike create, for alloc the type is purely for compile-time error
+ * checking and does not affect size.
*/
- void* alloc(size_t size);
+ template<class T>
+ void* alloc(size_t size) {
+ static_assert(std::is_trivially_destructible<T>::value,
+ "Error, type is non-trivial! did you mean to use create()?");
+ return allocImpl(size);
+ }
/**
* Allocates an instance of the template type with the given construction parameters
* and adds it to the automatic destruction list.
*/
template<class T, typename... Params>
- T* create(Params... params) {
- T* ret = new (*this) T(params...);
- autoDestroy(ret);
+ T* create(Params&&... params) {
+ T* ret = new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
+ if (!std::is_trivially_destructible<T>::value) {
+ auto dtor = [](void* ret) { ((T*)ret)->~T(); };
+ addToDestructionList(dtor, ret);
+ }
return ret;
}
- /**
- * Adds the pointer to the tracking list to have its destructor called
- * when the LinearAllocator is destroyed.
- */
- template<class T>
- void autoDestroy(T* addr) {
- if (!std::is_trivially_destructible<T>::value) {
- auto dtor = [](void* addr) { ((T*)addr)->~T(); };
- addToDestructionList(dtor, addr);
- }
+ template<class T, typename... Params>
+ T* create_trivial(Params&&... params) {
+ static_assert(std::is_trivially_destructible<T>::value,
+ "Error, called create_trivial on a non-trivial type");
+ return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
}
/**
@@ -114,6 +120,8 @@
DestructorNode* next = nullptr;
};
+ void* allocImpl(size_t size);
+
void addToDestructionList(Destructor, void* addr);
void runDestructorFor(void* addr);
Page* newPage(size_t pageSize);
@@ -159,7 +167,7 @@
: linearAllocator(other.linearAllocator) {}
T* allocate(size_t num, const void* = 0) {
- return (T*)(linearAllocator.alloc(num * sizeof(T)));
+ return (T*)(linearAllocator.alloc<void*>(num * sizeof(T)));
}
void deallocate(pointer p, size_t num) {
@@ -187,6 +195,4 @@
}; // namespace uirenderer
}; // namespace android
-void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la);
-
#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 82c5a8e..9203ef2 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1426,6 +1426,17 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
/**
+ * The ID of the TV input service that is associated with this recorded program.
+ *
+ * <p>Use {@link #buildInputId} to build the ID.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_INPUT_ID = "input_id";
+
+ /**
* The ID of the TV channel that provided this recorded TV program.
*
* <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 127bddd..c23c745 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -20,11 +20,31 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <com.android.systemui.qs.PageIndicator
- android:id="@+id/page_indicator"
- android:layout_width="match_parent"
+ <FrameLayout
+ android:id="@+id/page_decor"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal|bottom"
- android:gravity="center" />
+ android:layout_gravity="bottom">
+
+ <com.android.systemui.qs.PageIndicator
+ android:id="@+id/page_indicator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center" />
+
+ <TextView
+ android:id="@android:id/edit"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end"
+ android:minWidth="88dp"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton"
+ android:textColor="#4DFFFFFF"
+ android:focusable="true"
+ android:text="@string/qs_edit" />
+
+ </FrameLayout>
</com.android.systemui.qs.PagedTileLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index bb37b83..45236a0 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -18,13 +18,16 @@
android:id="@+id/quick_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/qs_background_primary"
- android:paddingBottom="8dp"
- android:elevation="2dp">
+ android:background="@drawable/qs_background_primary">
<com.android.systemui.qs.QSPanel
android:id="@+id/quick_settings_panel"
android:background="#0000"
+ android:layout_marginTop="@dimen/status_bar_header_height"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp" />
+
+ <include layout="@layout/quick_status_bar_expanded_header" />
+
</com.android.systemui.qs.QSContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 89abe2d..289b1d9 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,32 +39,11 @@
android:clipToPadding="false"
android:clipChildren="false">
- <com.android.systemui.statusbar.phone.ObservableScrollView
- android:id="@+id/scroll_view"
+ <include
+ layout="@layout/qs_panel"
android:layout_width="@dimen/notification_panel_width"
- android:layout_height="match_parent"
- android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:scrollbars="none"
- android:overScrollMode="never"
- android:fillViewport="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <include
- layout="@layout/qs_panel"
- android:layout_marginTop="@dimen/status_bar_header_height_expanded"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- <!-- A view to reserve space for the collapsed stack -->
- <!-- Layout height: notification_min_height + bottom_stack_peek_amount -->
- <View
- android:id="@+id/reserve_notification_space"
- android:layout_height="@dimen/min_stack_height"
- android:layout_width="match_parent" />
- </LinearLayout>
- </com.android.systemui.statusbar.phone.ObservableScrollView>
+ android:layout_height="wrap_content"
+ android:layout_gravity="@integer/notification_panel_layout_gravity" />
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
@@ -90,12 +69,6 @@
layout="@layout/keyguard_bottom_area"
android:visibility="gone" />
- <ViewStub
- android:id="@+id/status_bar_header"
- android:layout_width="@dimen/notification_panel_width"
- android:layout_height="@dimen/status_bar_header_height"
- android:layout_gravity="@integer/notification_panel_layout_gravity" />
-
<com.android.systemui.statusbar.AlphaOptimizedView
android:id="@+id/qs_navbar_scrim"
android:layout_height="96dp"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 6ff9be1..5d4789a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1405,4 +1405,7 @@
<!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
<string name="drag_to_add_tiles">Drag to add tiles</string>
+ <!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
+ <string name="qs_edit">Edit</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index d723367..8e9857d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,7 +6,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
import com.android.systemui.R;
@@ -27,6 +26,7 @@
private PageIndicator mPageIndicator;
private int mNumPages;
+ private View mDecorGroup;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -55,7 +55,8 @@
protected void onFinishInflate() {
super.onFinishInflate();
mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
- ((LayoutParams) mPageIndicator.getLayoutParams()).isDecor = true;
+ mDecorGroup = findViewById(R.id.page_decor);
+ ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
mPages.add((TilePage) LayoutInflater.from(mContext)
.inflate(R.layout.qs_paged_page, this, false));
@@ -137,7 +138,7 @@
maxHeight = height;
}
}
- setMeasuredDimension(getMeasuredWidth(), maxHeight + mPageIndicator.getMeasuredHeight());
+ setMeasuredDimension(getMeasuredWidth(), maxHeight + mDecorGroup.getMeasuredHeight());
}
private final Runnable mDistribute = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
index cfe8d07..32eeb07 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
@@ -16,19 +16,38 @@
package com.android.systemui.qs;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
-
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.BaseStatusBarHeader;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
- * Wrapper view with background which contains {@link QSPanel}
+ * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
+ *
+ * Also manages animations for the QS Header and Panel.
*/
public class QSContainer extends FrameLayout {
+ private static final String TAG = "QSContainer";
+ private static final boolean DEBUG = false;
private int mHeightOverride = -1;
private QSPanel mQSPanel;
+ protected BaseStatusBarHeader mHeader;
+ private float mQsExpansion;
+ private boolean mQsExpanded;
+ private boolean mHeaderAnimating;
+ private boolean mKeyguardShowing;
+ private boolean mStackScrollerOverscrolling;
+
+ private long mDelay;
public QSContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -38,6 +57,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
+ mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
}
@Override
@@ -63,14 +83,132 @@
*/
public int getDesiredHeight() {
if (mQSPanel.isClosingDetail()) {
- return mQSPanel.getGridHeight() + getPaddingTop() + getPaddingBottom();
+ return mQSPanel.getGridHeight() + mHeader.getCollapsedHeight() + getPaddingBottom();
} else {
return getMeasuredHeight();
}
}
private void updateBottom() {
- int height = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
+ int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
+ int height = (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
+ + mHeader.getCollapsedHeight();
setBottom(getTop() + height);
}
+
+ private void updateQsState() {
+ boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
+ mQSPanel.setExpanded(mQsExpanded);
+ mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
+ ? View.VISIBLE
+ : View.INVISIBLE);
+ mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
+ || (mQsExpanded && !mStackScrollerOverscrolling));
+ mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
+ }
+
+ public BaseStatusBarHeader getHeader() {
+ return mHeader;
+ }
+
+ public QSPanel getQsPanel() {
+ return mQSPanel;
+ }
+
+ public void setHeaderClickable(boolean clickable) {
+ if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
+ mHeader.setClickable(clickable);
+ }
+
+ public void setExpanded(boolean expanded) {
+ if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
+ mQsExpanded = expanded;
+ updateQsState();
+ }
+
+ public void setKeyguardShowing(boolean keyguardShowing) {
+ if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
+ mKeyguardShowing = keyguardShowing;
+ updateQsState();
+ }
+
+ public void setOverscrolling(boolean stackScrollerOverscrolling) {
+ if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
+ mStackScrollerOverscrolling = stackScrollerOverscrolling;
+ updateQsState();
+ }
+
+ public void setListening(boolean listening) {
+ if (DEBUG) Log.d(TAG, "setListening " + listening);
+ mQSPanel.setListening(listening);
+ mHeader.setListening(listening);
+ }
+
+ public void setQsExpansion(float expansion, float headerTranslation) {
+ if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
+ mQsExpansion = expansion;
+ final float translationScaleY = expansion - 1;
+ if (!mHeaderAnimating) {
+ setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
+ : headerTranslation);
+ }
+ mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
+ mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
+ updateBottom();
+ }
+
+ public void animateHeaderSlidingIn(long delay) {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
+ // If the QS is already expanded we don't need to slide in the header as it's already
+ // visible.
+ if (!mQsExpanded) {
+ mHeaderAnimating = true;
+ mDelay = delay;
+ getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
+ }
+ }
+
+ public void animateHeaderSlidingOut() {
+ if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
+ mHeaderAnimating = true;
+ animate().y(-mHeader.getHeight())
+ .setStartDelay(0)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animate().setListener(null);
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ })
+ .start();
+ }
+
+ private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ animate()
+ .translationY(0f)
+ .setStartDelay(mDelay)
+ .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setListener(mAnimateHeaderSlidingInListener)
+ .start();
+ setY(-mHeader.getHeight());
+ return true;
+ }
+ };
+
+ private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
+ = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHeaderAnimating = false;
+ updateQsState();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 1961860..4ffa527 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -117,6 +117,17 @@
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
R.layout.qs_paged_tile_layout, mQsContainer, false);
mQsContainer.addView((View) mTileLayout);
+ findViewById(android.R.id.edit).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ mHost.startRunnableDismissingKeyguard(new Runnable() {
+ @Override
+ public void run() {
+ showEdit(v);
+ }
+ });
+ }
+ });
mFooter = new QSFooter(this, context);
mQsContainer.addView(mFooter.getView());
@@ -369,19 +380,7 @@
final View.OnLongClickListener longClick = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
- if (mCustomizePanel != null) {
- if (!mCustomizePanel.isCustomizing()) {
- int[] loc = new int[2];
- getLocationInWindow(loc);
- int x = r.tileView.getLeft() + r.tileView.getWidth() / 2 + loc[0];
- int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r)
- + r.tileView.getHeight() / 2 + loc[1];
- mCustomizePanel.show(x, y);
- }
- } else {
- r.tile.longClick();
- }
- return true;
+ return false;
}
};
r.tileView.init(click, longClick);
@@ -395,6 +394,25 @@
}
}
+
+ private void showEdit(final View v) {
+ v.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCustomizePanel != null) {
+ if (!mCustomizePanel.isCustomizing()) {
+ int[] loc = new int[2];
+ v.getLocationInWindow(loc);
+ int x = loc[0];
+ int y = loc[1];
+ mCustomizePanel.show(x, y);
+ }
+ }
+
+ }
+ });
+ }
+
protected void onTileClick(QSTile<?> tile) {
tile.click();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index f822bd5..8f0f51f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -19,7 +19,6 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.StatusBarManager;
@@ -35,13 +34,11 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
import android.widget.TextView;
-
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.DejankUtils;
@@ -51,7 +48,6 @@
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.qs.QSContainer;
-import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -91,13 +87,10 @@
public static final long DOZE_ANIMATION_DURATION = 700;
private KeyguardAffordanceHelper mAfforanceHelper;
- protected BaseStatusBarHeader mHeader;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
private QSContainer mQsContainer;
- private QSPanel mQsPanel;
private KeyguardStatusView mKeyguardStatusView;
- private ObservableScrollView mScrollView;
private TextView mClockView;
private View mReserveNotificationSpace;
private View mQsNavbarScrim;
@@ -168,15 +161,12 @@
* If we are in a panel collapsing motion, we reset scrollY of our scroll view but still
* need to take this into account in our panel height calculation.
*/
- private int mScrollYOverride = -1;
private boolean mQsAnimatorExpand;
private boolean mIsLaunchTransitionFinished;
private boolean mIsLaunchTransitionRunning;
private Runnable mLaunchAnimationEndRunnable;
private boolean mOnlyAffordanceInThisMotion;
private boolean mKeyguardStatusViewAnimating;
- private boolean mHeaderAnimating;
- private ObjectAnimator mQsContainerAnimator;
private ValueAnimator mQsSizeChangeAnimator;
private boolean mShadeEmpty;
@@ -223,19 +213,11 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- ViewStub stub = (ViewStub) findViewById(R.id.status_bar_header);
- stub.setLayoutResource(R.layout.quick_status_bar_expanded_header);
- mHeader = (BaseStatusBarHeader) stub.inflate();
- mHeader.setOnClickListener(this);
mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container);
- mQsPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
+ mQsContainer.getHeader().setOnClickListener(this);
mClockView = (TextView) findViewById(R.id.clock_view);
- mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
- mScrollView.setListener(this);
- mScrollView.setFocusable(false);
- mReserveNotificationSpace = findViewById(R.id.reserve_notification_space);
mNotificationContainerParent = (NotificationsQuickSettingsContainer)
findViewById(R.id.notification_container_parent);
mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -243,7 +225,7 @@
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
- mNotificationStackScroller.setScrollView(mScrollView);
+ mNotificationStackScroller.setQsContainer(mQsContainer);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
@@ -285,12 +267,12 @@
public void updateResources() {
int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mHeader.getLayoutParams();
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mQsContainer.getLayoutParams();
if (lp.width != panelWidth) {
lp.width = panelWidth;
lp.gravity = panelGravity;
- mHeader.setLayoutParams(lp);
- mHeader.post(mUpdateHeader);
+ mQsContainer.setLayoutParams(lp);
+ mQsContainer.post(mUpdateHeader);
}
lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
@@ -299,13 +281,6 @@
lp.gravity = panelGravity;
mNotificationStackScroller.setLayoutParams(lp);
}
-
- lp = (FrameLayout.LayoutParams) mScrollView.getLayoutParams();
- if (lp.width != panelWidth) {
- lp.width = panelWidth;
- lp.gravity = panelGravity;
- mScrollView.setLayoutParams(lp);
- }
}
@Override
@@ -318,8 +293,8 @@
// Calculate quick setting heights.
int oldMaxHeight = mQsMaxExpansionHeight;
- mQsMinExpansionHeight = mKeyguardShowing ? 0 : mHeader.getCollapsedHeight() + mQsPeekHeight;
- mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getDesiredHeight();
+ mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQsContainer.getHeader().getHeight();
+ mQsMaxExpansionHeight = mQsContainer.getDesiredHeight();
positionClockAndNotifications();
if (mQsExpanded && mQsFullyExpanded) {
mQsExpansionHeight = mQsMaxExpansionHeight;
@@ -361,7 +336,7 @@
requestScrollerTopPaddingUpdate(false /* animate */);
requestPanelHeightUpdate();
int height = (int) mQsSizeChangeAnimator.getAnimatedValue();
- mQsContainer.setHeightOverride(height - mHeader.getExpandedHeight());
+ mQsContainer.setHeightOverride(height);
}
});
mQsSizeChangeAnimator.addListener(new AnimatorListenerAdapter() {
@@ -381,7 +356,7 @@
boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
int stackScrollerPadding;
if (mStatusBarState != StatusBarState.KEYGUARD) {
- int bottom = mHeader.getCollapsedHeight();
+ int bottom = mQsContainer.getHeader().getHeight();
stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
? bottom + mQsPeekHeight
: mKeyguardStatusBar.getHeight();
@@ -485,7 +460,7 @@
public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
mQsExpansionEnabled = qsExpansionEnabled;
- mHeader.setClickable(qsExpansionEnabled);
+ mQsContainer.setHeaderClickable(qsExpansionEnabled);
}
@Override
@@ -676,17 +651,6 @@
}
}
- @Override
- public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-
- // Block request when interacting with the scroll view so we can still intercept the
- // scrolling when QS is expanded.
- if (mScrollView.isHandlingTouchEvent()) {
- return;
- }
- super.requestDisallowInterceptTouchEvent(disallowIntercept);
- }
-
private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) {
float vel = getCurrentVelocity();
final boolean expandsQs = flingExpandsQs(vel);
@@ -808,7 +772,7 @@
}
private boolean isInQsArea(float x, float y) {
- return (x >= mScrollView.getX() && x <= mScrollView.getX() + mScrollView.getWidth()) &&
+ return (x >= mQsContainer.getX() && x <= mQsContainer.getX() + mQsContainer.getWidth()) &&
(y <= mNotificationStackScroller.getBottomMostNotificationBottom()
|| y <= mQsContainer.getY() + mQsContainer.getHeight());
}
@@ -948,7 +912,7 @@
amount = 0f;
}
float rounded = amount >= 1f ? amount : 0f;
- mStackScrollerOverscrolling = rounded != 0f && isRubberbanded;
+ setOverScrolling(rounded != 0f && isRubberbanded);
mQsExpansionFromOverscroll = rounded != 0f;
mLastOverscroll = rounded;
updateQsState();
@@ -964,12 +928,17 @@
@Override
public void run() {
mStackScrollerOverscrolling = false;
- mQsExpansionFromOverscroll = false;
+ setOverScrolling(false);
updateQsState();
}
}, false /* isClick */);
}
+ private void setOverScrolling(boolean overscrolling) {
+ mStackScrollerOverscrolling = overscrolling;
+ mQsContainer.setOverscrolling(overscrolling);
+ }
+
private void onQsExpansionStarted() {
onQsExpansionStarted(0);
}
@@ -979,11 +948,7 @@
cancelHeightAnimator();
// Reset scroll position and apply that position to the expanded height.
- float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount;
- if (mScrollView.getScrollY() != 0) {
- mScrollYOverride = mScrollView.getScrollY();
- }
- mScrollView.scrollTo(0, 0);
+ float height = mQsExpansionHeight - overscrollAmount;
setQsExpansion(height);
requestPanelHeightUpdate();
}
@@ -995,9 +960,7 @@
updateQsState();
requestPanelHeightUpdate();
mFalsingManager.setQsExpanded(expanded);
- mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
mStatusBar.setQsExpanded(expanded);
- mQsPanel.setExpanded(expanded);
mNotificationContainerParent.setQsExpanded(expanded);
}
}
@@ -1011,15 +974,18 @@
mStatusBarState = statusBarState;
mKeyguardShowing = keyguardShowing;
+ mQsContainer.setKeyguardShowing(mKeyguardShowing);
if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
&& statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
- animateHeaderSlidingIn();
+ long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
+ ? 0 : mStatusBar.calculateGoingToFullShadeDelay();
+ mQsContainer.animateHeaderSlidingIn(delay);
} else if (oldState == StatusBarState.SHADE_LOCKED
&& statusBarState == StatusBarState.KEYGUARD) {
animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- animateHeaderSlidingOut();
+ mQsContainer.animateHeaderSlidingOut();
} else {
mKeyguardStatusBar.setAlpha(1f);
mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
@@ -1050,95 +1016,6 @@
}
};
- private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
- = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHeaderAnimating = false;
- mQsContainerAnimator = null;
- mQsContainer.removeOnLayoutChangeListener(mQsContainerAnimatorUpdater);
- }
- };
-
- private final OnLayoutChangeListener mQsContainerAnimatorUpdater
- = new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- int oldHeight = oldBottom - oldTop;
- int height = bottom - top;
- if (height != oldHeight && mQsContainerAnimator != null) {
- PropertyValuesHolder[] values = mQsContainerAnimator.getValues();
- float newEndValue = mHeader.getCollapsedHeight() + mQsPeekHeight - height - top;
- float newStartValue = -height - top;
- values[0].setFloatValues(newStartValue, newEndValue);
- mQsContainerAnimator.setCurrentPlayTime(mQsContainerAnimator.getCurrentPlayTime());
- }
- }
- };
-
- private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
- = new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- getViewTreeObserver().removeOnPreDrawListener(this);
- long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
- ? 0
- : mStatusBar.calculateGoingToFullShadeDelay();
- mHeader.setTranslationY(-mHeader.getCollapsedHeight() - mQsPeekHeight);
- mHeader.animate()
- .translationY(0f)
- .setStartDelay(delay)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
- mQsContainer.setY(-mQsContainer.getHeight());
- mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
- mQsContainer.getTranslationY(),
- mHeader.getCollapsedHeight() + mQsPeekHeight - mQsContainer.getHeight()
- - mQsContainer.getTop());
- mQsContainerAnimator.setStartDelay(delay);
- mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
- mQsContainerAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
- mQsContainerAnimator.start();
- mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
- return true;
- }
- };
-
- private void animateHeaderSlidingIn() {
- // If the QS is already expanded we don't need to slide in the header as it's already
- // visible.
- if (!mQsExpanded) {
- mHeaderAnimating = true;
- getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
- }
- }
-
- private void animateHeaderSlidingOut() {
- mHeaderAnimating = true;
- mHeader.animate().y(-mHeader.getHeight())
- .setStartDelay(0)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mHeader.animate().setListener(null);
- mHeaderAnimating = false;
- updateQsState();
- }
- })
- .start();
- mQsContainer.animate()
- .y(-mQsContainer.getHeight())
- .setStartDelay(0)
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
- .start();
- }
-
private final Runnable mAnimateKeyguardStatusBarInvisibleEndRunnable = new Runnable() {
@Override
public void run() {
@@ -1262,19 +1139,10 @@
}
private void updateQsState() {
- boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
- mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
- ? View.VISIBLE
- : View.INVISIBLE);
- mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
- || (mQsExpanded && !mStackScrollerOverscrolling));
+ mQsContainer.setExpanded(mQsExpanded);
mNotificationStackScroller.setScrollingEnabled(
mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
- mQsPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
- mQsContainer.setVisibility(
- mKeyguardShowing && !expandVisually ? View.INVISIBLE : View.VISIBLE);
- mScrollView.setTouchEnabled(mQsExpanded);
updateEmptyShadeView();
mQsNavbarScrim.setVisibility(mStatusBarState == StatusBarState.SHADE && mQsExpanded
&& !mStackScrollerOverscrolling && mQsScrimEnabled
@@ -1298,11 +1166,10 @@
}
}
mQsExpansionHeight = height;
- mHeader.setExpansion(getHeaderExpansionFraction());
- setQsTranslation(height);
+ updateQsExpansion();
requestScrollerTopPaddingUpdate(false /* animate */);
if (mKeyguardShowing) {
- updateHeaderKeyguard();
+ updateHeaderKeyguardAlpha();
}
if (mStatusBarState == StatusBarState.SHADE_LOCKED
|| mStatusBarState == StatusBarState.KEYGUARD) {
@@ -1329,6 +1196,10 @@
}
}
+ private void updateQsExpansion() {
+ mQsContainer.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
+ }
+
private String getKeyguardOrLockScreenString() {
if (mStatusBarState == StatusBarState.KEYGUARD) {
return getContext().getString(R.string.accessibility_desc_lock_screen);
@@ -1337,23 +1208,6 @@
}
}
- private float getHeaderExpansionFraction() {
- if (!mKeyguardShowing) {
- return getQsExpansionFraction();
- } else {
- return 1f;
- }
- }
-
- private void setQsTranslation(float height) {
- if (!mHeaderAnimating) {
- mQsContainer.setY(height - mQsContainer.getDesiredHeight() + getHeaderTranslation());
- }
- if (mKeyguardShowing && !mHeaderAnimating) {
- mHeader.setY(interpolate(getQsExpansionFraction(), -mHeader.getHeight(), 0));
- }
- }
-
private float calculateQsTopPadding() {
if (mKeyguardShowing
&& (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
@@ -1372,7 +1226,7 @@
mQsMinExpansionHeight, max);
} else if (mQsSizeChangeAnimator != null) {
return (int) mQsSizeChangeAnimator.getAnimatedValue();
- } else if (mKeyguardShowing && mScrollYOverride == -1) {
+ } else if (mKeyguardShowing) {
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
@@ -1386,7 +1240,6 @@
private void requestScrollerTopPaddingUpdate(boolean animate) {
mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
- mScrollView.getScrollY(),
mAnimateNextTopPaddingChange || animate,
mKeyguardShowing
&& (mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted));
@@ -1428,7 +1281,6 @@
boolean isClick) {
float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
if (target == mQsExpansionHeight) {
- mScrollYOverride = -1;
if (onFinishRunnable != null) {
onFinishRunnable.run();
}
@@ -1438,7 +1290,6 @@
if (belowFalsingThreshold) {
vel = 0;
}
- mScrollView.setBlockFlinging(true);
ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
if (isClick) {
animator.setInterpolator(Interpolators.TOUCH_RESPONSE);
@@ -1458,8 +1309,6 @@
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mScrollView.setBlockFlinging(false);
- mScrollYOverride = -1;
mQsExpansionAnimator = null;
if (onFinishRunnable != null) {
onFinishRunnable.run();
@@ -1478,11 +1327,11 @@
if (!mQsExpansionEnabled || mCollapsedOnDown) {
return false;
}
- View header = mKeyguardShowing ? mKeyguardStatusBar : mHeader;
+ View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
boolean onHeader = x >= header.getX() && x <= header.getX() + header.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
- return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0) && isInQsArea(x, y);
+ return onHeader || (yDiff < 0 && isInQsArea(x, y));
} else {
return onHeader;
}
@@ -1494,7 +1343,7 @@
return mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mNotificationStackScroller.isScrolledToBottom();
} else {
- return mScrollView.isScrolledToBottom();
+ return true;
}
}
@@ -1571,11 +1420,7 @@
* collapsing QS / the panel when QS was scrolled
*/
private int getTempQsMaxExpansion() {
- int qsTempMaxExpansion = mQsMaxExpansionHeight;
- if (mScrollYOverride != -1) {
- qsTempMaxExpansion -= mScrollYOverride;
- }
- return qsTempMaxExpansion;
+ return mQsMaxExpansionHeight;
}
private int calculatePanelHeightShade() {
@@ -1613,20 +1458,12 @@
+ notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
- + mNotificationStackScroller.getMinStackHeight()
- - getScrollViewScrollY();
+ + mNotificationStackScroller.getMinStackHeight();
totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
}
return (int) totalHeight;
}
- private int getScrollViewScrollY() {
- if (mScrollYOverride != -1 && !mQsTracking) {
- return mScrollYOverride;
- } else {
- return mScrollView.getScrollY();
- }
- }
private void updateNotificationTranslucency() {
float alpha = 1f;
if (mClosingWithAlphaFadeOut && !mExpandingFromHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
@@ -1678,18 +1515,9 @@
*/
private void updateHeader() {
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD) {
- updateHeaderKeyguard();
- } else {
- updateHeaderShade();
+ updateHeaderKeyguardAlpha();
}
-
- }
-
- private void updateHeaderShade() {
- if (!mHeaderAnimating) {
- mHeader.setTranslationY(getHeaderTranslation());
- }
- setQsTranslation(mQsExpansionHeight);
+ updateQsExpansion();
}
private float getHeaderTranslation() {
@@ -1744,11 +1572,6 @@
&& !mDozing ? VISIBLE : INVISIBLE);
}
- private void updateHeaderKeyguard() {
- updateHeaderKeyguardAlpha();
- setQsTranslation(mQsExpansionHeight);
- }
-
private void updateKeyguardBottomAreaAlpha() {
float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
mKeyguardBottomArea.setAlpha(alpha);
@@ -1781,7 +1604,6 @@
mNotificationStackScroller.onExpansionStopped();
mHeadsUpManager.onExpandingFinished();
mIsExpanding = false;
- mScrollYOverride = -1;
if (isFullyCollapsed()) {
DejankUtils.postAfterTraversal(new Runnable() {
@Override
@@ -1811,9 +1633,8 @@
}
private void setListening(boolean listening) {
- mHeader.setListening(listening);
+ mQsContainer.setListening(listening);
mKeyguardStatusBar.setListening(listening);
- mQsPanel.setListening(listening);
}
@Override
@@ -1931,7 +1752,7 @@
@Override
public void onClick(View v) {
- if (v == mHeader) {
+ if (v == mQsContainer.getHeader()) {
onQsExpansionStarted();
if (mQsExpanded) {
flingSettings(0 /* vel */, false /* expand */, null, true /* isClick */);
@@ -2149,24 +1970,16 @@
return mConflictingQsExpansionGesture && mQsExpanded;
}
- public void notifyVisibleChildrenChanged() {
- if (mNotificationStackScroller.getNotGoneChildCount() != 0) {
- mReserveNotificationSpace.setVisibility(View.VISIBLE);
- } else {
- mReserveNotificationSpace.setVisibility(View.GONE);
- }
- }
-
public boolean isQsExpanded() {
return mQsExpanded;
}
public boolean isQsDetailShowing() {
- return mQsPanel.isShowingDetail();
+ return mQsContainer.getQsPanel().isShowingDetail();
}
public void closeQsDetail() {
- mQsPanel.closeDetail();
+ mQsContainer.getQsPanel().closeDetail();
}
@Override
@@ -2254,7 +2067,7 @@
private final Runnable mUpdateHeader = new Runnable() {
@Override
public void run() {
- mHeader.updateEverything();
+ mQsContainer.getHeader().updateEverything();
}
};
@@ -2400,8 +2213,7 @@
protected void setVerticalPanelTranslation(float translation) {
mNotificationStackScroller.setTranslationX(translation);
- mScrollView.setTranslationX(translation);
- mHeader.setTranslationX(translation);
+ mQsContainer.setTranslationX(translation);
}
private void updateStackHeight(float stackHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index fd28b09..7cc720d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -33,7 +33,7 @@
public class NotificationsQuickSettingsContainer extends FrameLayout
implements ViewStub.OnInflateListener {
- private View mScrollView;
+ private View mQsContainer;
private View mUserSwitcher;
private View mStackScroller;
private View mKeyguardStatusBar;
@@ -47,7 +47,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mScrollView = findViewById(R.id.scroll_view);
+ mQsContainer = findViewById(R.id.quick_settings_container);
mStackScroller = findViewById(R.id.notification_stack_scroller);
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
@@ -58,7 +58,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- reloadWidth(mScrollView);
+ reloadWidth(mQsContainer);
reloadWidth(mStackScroller);
}
@@ -80,11 +80,11 @@
boolean userSwitcherVisible = mInflated && mUserSwitcher.getVisibility() == View.VISIBLE;
boolean statusBarVisible = mKeyguardStatusBar.getVisibility() == View.VISIBLE;
- View stackQsTop = mQsExpanded ? mStackScroller : mScrollView;
- View stackQsBottom = !mQsExpanded ? mStackScroller : mScrollView;
+ View stackQsTop = mQsExpanded ? mStackScroller : mQsContainer;
+ View stackQsBottom = !mQsExpanded ? mStackScroller : mQsContainer;
// Invert the order of the scroll view and user switcher such that the notifications receive
// touches first but the panel gets drawn above.
- if (child == mScrollView) {
+ if (child == mQsContainer) {
return super.drawChild(canvas, userSwitcherVisible && statusBarVisible ? mUserSwitcher
: statusBarVisible ? mKeyguardStatusBar
: userSwitcherVisible ? mUserSwitcher
@@ -104,7 +104,7 @@
return super.drawChild(canvas,
stackQsTop,
drawingTime);
- }else {
+ } else {
return super.drawChild(canvas, child, drawingTime);
}
}
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 50a49a1..f382fe0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1600,12 +1600,6 @@
}
@Override
- protected void updateRowStates() {
- super.updateRowStates();
- mNotificationPanel.notifyVisibleChildrenChanged();
- }
-
- @Override
protected void setAreThereNotifications() {
if (SPEW) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 49e9c3d..a75ac82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -213,7 +213,6 @@
* animating.
*/
private boolean mOnlyScrollingInThisMotion;
- private ViewGroup mScrollView;
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
private boolean mDisallowScrollingInThisMotion;
@@ -281,6 +280,7 @@
setDimAmount((Float) animation.getAnimatedValue());
}
};
+ private ViewGroup mQsContainer;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -630,12 +630,8 @@
mLongPressListener = listener;
}
- public void setScrollView(ViewGroup scrollView) {
- mScrollView = scrollView;
- }
-
- public void setInterceptDelegateEnabled(boolean interceptDelegateEnabled) {
- mInterceptDelegateEnabled = interceptDelegateEnabled;
+ public void setQsContainer(ViewGroup qsContainer) {
+ mQsContainer = qsContainer;
}
public void onChildDismissed(View v) {
@@ -883,13 +879,6 @@
public boolean onTouchEvent(MotionEvent ev) {
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
|| ev.getActionMasked()== MotionEvent.ACTION_UP;
- if (mDelegateToScrollView) {
- if (isCancelOrUp) {
- mDelegateToScrollView = false;
- }
- transformTouchEvent(ev, this, mScrollView);
- return mScrollView.onTouchEvent(ev);
- }
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion) {
@@ -929,6 +918,9 @@
if (!isScrollingEnabled()) {
return false;
}
+ if (ev.getY() < mQsContainer.getBottom()) {
+ return false;
+ }
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
@@ -1776,15 +1768,13 @@
* account.
*
* @param qsHeight the top padding imposed by the quick settings panel
- * @param scrollY how much the notifications are scrolled inside the QS/notifications scroll
- * container
* @param animate whether to animate the change
* @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
* {@code qsHeight} is the final top padding
*/
- public void updateTopPadding(float qsHeight, int scrollY, boolean animate,
+ public void updateTopPadding(float qsHeight, boolean animate,
boolean ignoreIntrinsicPadding) {
- float start = qsHeight - scrollY;
+ float start = qsHeight;
float stackHeight = getHeight() - start;
int minStackHeight = getMinStackHeight();
if (stackHeight <= minStackHeight) {
@@ -1867,15 +1857,6 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mInterceptDelegateEnabled) {
- transformTouchEvent(ev, this, mScrollView);
- if (mScrollView.onInterceptTouchEvent(ev)) {
- mDelegateToScrollView = true;
- removeLongPressCallback();
- return true;
- }
- transformTouchEvent(ev, mScrollView, this);
- }
initDownStates(ev);
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 830b0f2..7149065 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1044,7 +1044,7 @@
// If Encrypted file systems is enabled or disabled, this call will return the
// correct directory.
- mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
+ mBaseStateDir = new File(Environment.getDataDirectory(), "backup");
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index bbf881b..e745263 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -54,7 +54,7 @@
public Trampoline(Context context) {
mContext = context;
- File dir = new File(Environment.getSecureDataDirectory(), "backup");
+ File dir = new File(Environment.getDataDirectory(), "backup");
dir.mkdirs();
mSuppressFile = new File(dir, BACKUP_SUPPRESS_FILENAME);
mGlobalDisable = SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index cbd477a..d09edc8 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -1473,7 +1473,7 @@
}
mSettingsFile = new AtomicFile(
- new File(Environment.getSystemSecureDirectory(), "storage.xml"));
+ new File(Environment.getDataSystemDirectory(), "storage.xml"));
synchronized (mLock) {
readSettingsLocked();
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2683be6..ca1e371 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3809,7 +3809,7 @@
}
private static String getDatabaseName(int userId) {
- File systemDir = Environment.getSystemSecureDirectory();
+ File systemDir = Environment.getDataSystemDirectory();
File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
if (userId == 0) {
// Migrate old file, if it exists, to the new location.
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8560a9e..75dabc96 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1127,7 +1127,8 @@
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
} else if (prev.app != null) {
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending stop: " + prev);
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ + " wasStopping=" + wasStopping + " visible=" + prev.visible);
if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
"Complete pause, no longer waiting: " + prev);
@@ -1142,7 +1143,8 @@
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.state = ActivityState.STOPPING;
- } else if (!hasVisibleBehindActivity() || mService.isSleepingOrShuttingDown()) {
+ } else if ((!prev.visible && !hasVisibleBehindActivity())
+ || mService.isSleepingOrShuttingDown()) {
// If we were visible then resumeTopActivities will release resources before
// stopping.
addToStopping(prev);
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index f8e3e48..965054f 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -438,9 +438,7 @@
if (sSyncStorageEngine != null) {
return;
}
- // This call will return the correct directory whether Encrypted File Systems is
- // enabled or not.
- File dataDir = Environment.getSecureDataDirectory();
+ File dataDir = Environment.getDataDirectory();
sSyncStorageEngine = new SyncStorageEngine(context, dataDir);
}
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index 62114cd..7e19c66 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -52,7 +52,7 @@
static final String TAG = "IntentFirewall";
// e.g. /data/system/ifw or /data/secure/system/ifw
- private static final File RULES_DIR = new File(Environment.getSystemSecureDirectory(), "ifw");
+ private static final File RULES_DIR = new File(Environment.getDataSystemDirectory(), "ifw");
private static final int LOG_PACKAGES_MAX_LENGTH = 150;
private static final int LOG_PACKAGES_SUFFICIENT_LENGTH = 125;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 29d52c1..0d6e3e5 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -53,6 +53,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
@@ -547,14 +548,14 @@
loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
}
- final ArrayList<ManagedServiceInfo> toRemove = new ArrayList<>();
- final SparseArray<ArrayList<ComponentName>> toAdd = new SparseArray<>();
+ final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
+ final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
synchronized (mMutex) {
- // Unbind automatically bound services, retain system services.
+ // Potentially unbind automatically bound services, retain system services.
for (ManagedServiceInfo service : mServices) {
if (!service.isSystem && !service.isGuest(this)) {
- toRemove.add(service);
+ removableBoundServices.add(service);
}
}
@@ -565,11 +566,11 @@
// decode the list of components
final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
if (null == userComponents) {
- toAdd.put(userIds[i], new ArrayList<ComponentName>());
+ toAdd.put(userIds[i], new HashSet<ComponentName>());
continue;
}
- final ArrayList<ComponentName> add = new ArrayList<>(userComponents);
+ final Set<ComponentName> add = new HashSet<>(userComponents);
// Remove components from disabled categories so that those services aren't run.
for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) {
@@ -594,19 +595,26 @@
mEnabledServicesPackageNames = newPackages;
}
- for (ManagedServiceInfo info : toRemove) {
+ for (ManagedServiceInfo info : removableBoundServices) {
final ComponentName component = info.component;
final int oldUser = info.userid;
- Slog.v(TAG, "disabling " + getCaption() + " for user "
- + oldUser + ": " + component);
- unregisterService(component, info.userid);
+ final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
+ if (allowedComponents != null) {
+ if (allowedComponents.contains(component)) {
+ // Already bound, don't need to bind again.
+ allowedComponents.remove(component);
+ } else {
+ // No longer allowed to be bound.
+ Slog.v(TAG, "disabling " + getCaption() + " for user "
+ + oldUser + ": " + component);
+ unregisterService(component, oldUser);
+ }
+ }
}
for (int i = 0; i < nUserIds; ++i) {
- final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
- final int N = add.size();
- for (int j = 0; j < N; j++) {
- final ComponentName component = add.get(j);
+ final Set<ComponentName> add = toAdd.get(userIds[i]);
+ for (ComponentName component : add) {
Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
+ component);
registerService(component, userIds[i]);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 23a58d0..928c19f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -212,8 +212,8 @@
mCallbacks = new Callbacks(mInstallThread.getLooper());
mSessionsFile = new AtomicFile(
- new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));
- mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");
+ new File(Environment.getDataSystemDirectory(), "install_sessions.xml"));
+ mSessionsDir = new File(Environment.getDataSystemDirectory(), "install_sessions");
mSessionsDir.mkdirs();
synchronized (mSessions) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e47d514..31d16cd 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12724,9 +12724,6 @@
String pkgName = pkg.packageName;
if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
- // TODO: b/23350563
- final boolean dataDirExists = Environment
- .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_SYSTEM, pkgName).exists();
synchronized(mPackages) {
if (mSettings.mRenamedPackages.containsKey(pkgName)) {
@@ -12752,18 +12749,15 @@
System.currentTimeMillis(), user);
updateSettingsLI(newPackage, installerPackageName, null, null, res, user);
- prepareAppDataAfterInstall(newPackage);
- // delete the partially installed application. the data directory will have to be
- // restored if it was already existing
- if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- // remove package from internal structures. Note that we want deletePackageX to
- // delete the package data and cache directories that it created in
- // scanPackageLocked, unless those directories existed before we even tried to
- // install.
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ prepareAppDataAfterInstall(newPackage);
+
+ } else {
+ // Remove package from internal structures, but keep around any
+ // data that might have already existed
deletePackageLI(pkgName, UserHandle.ALL, false, null, null,
- dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,
- res.removedInfo, true, null);
+ PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
}
} catch (PackageManagerException e) {
@@ -17423,8 +17417,9 @@
* recycled.
*/
private void reconcileUsers(String volumeUuid) {
+ // TODO: also reconcile DE directories
final File[] files = FileUtils
- .listFilesOrEmpty(Environment.getDataUserDirectory(volumeUuid));
+ .listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid));
for (File file : files) {
if (!file.isDirectory()) continue;
@@ -17553,8 +17548,8 @@
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ Integer.toHexString(flags));
- final File ceDir = Environment.getDataUserCredentialEncryptedDirectory(volumeUuid, userId);
- final File deDir = Environment.getDataUserDeviceEncryptedDirectory(volumeUuid, userId);
+ final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
+ final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
boolean restoreconNeeded = false;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index f57f75f..4b355de62 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -155,7 +155,7 @@
*/
public static boolean isValidRestriction(@NonNull String restriction) {
if (!USER_RESTRICTIONS.contains(restriction)) {
- Slog.wtf(TAG, "Unknown restriction: " + restriction);
+ Slog.e(TAG, "Unknown restriction: " + restriction);
return false;
}
return true;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eacf11f..2ed96c6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -116,6 +116,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -274,6 +275,8 @@
private static final int PROFILE_KEYGUARD_FEATURES =
PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_AFFECT_PROFILE;
+ private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
+
final Context mContext;
final Injector mInjector;
final IPackageManager mIPackageManager;
@@ -281,6 +284,13 @@
final UserManagerInternal mUserManagerInternal;
private final LockPatternUtils mLockPatternUtils;
+ /**
+ * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
+ * is requested for user u.
+ */
+ private final Set<Pair<String, Integer>> mPackagesToRemove =
+ new ArraySet<Pair<String, Integer>>();
+
final LocalService mLocalService;
// Stores and loads state on device and profile owners.
@@ -2015,35 +2025,19 @@
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin != null) {
getUserData(userHandle).mRemovingAdmins.add(adminReceiver);
-
sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- synchronized (DevicePolicyManagerService.this) {
- int userHandle = admin.getUserHandle().getIdentifier();
- DevicePolicyData policy = getUserData(userHandle);
- boolean doProxyCleanup = admin.info.usesPolicy(
- DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
- policy.mAdminList.remove(admin);
- policy.mAdminMap.remove(adminReceiver);
- validatePasswordOwnerLocked(policy);
- if (doProxyCleanup) {
- resetGlobalProxyLocked(getUserData(userHandle));
- }
- saveSettingsLocked(userHandle);
- updateMaximumTimeToLockLocked(userHandle);
- policy.mRemovingAdmins.remove(adminReceiver);
- }
- // The removed admin might have disabled camera, so update user
- // restrictions.
- pushUserRestrictions(userHandle);
+ removeAdminArtifacts(adminReceiver, userHandle);
+ removePackageIfRequired(adminReceiver.getPackageName(), userHandle);
}
});
}
}
+
public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle,
boolean throwForMissiongPermission) {
if (!mHasFeature) {
@@ -8465,4 +8459,131 @@
List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs();
return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
}
+
+ private void enforceCanManageDeviceAdmin() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS,
+ null);
+ }
+
+ @Override
+ public boolean isUninstallInQueue(final String packageName) {
+ enforceCanManageDeviceAdmin();
+ final int userId = mInjector.userHandleGetCallingUserId();
+ Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ return mPackagesToRemove.contains(packageUserPair);
+ }
+ }
+
+ @Override
+ public void uninstallPackageWithActiveAdmins(final String packageName) {
+ enforceCanManageDeviceAdmin();
+ Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
+
+ final int userId = mInjector.userHandleGetCallingUserId();
+
+ final ComponentName profileOwner = getProfileOwner(userId);
+ if (profileOwner != null && packageName.equals(profileOwner.getPackageName())) {
+ throw new IllegalArgumentException("Cannot uninstall a package with a profile owner");
+ }
+
+ final ComponentName deviceOwner = getDeviceOwnerComponent(/* callingUserOnly= */ false);
+ if (getDeviceOwnerUserId() == userId && deviceOwner != null
+ && packageName.equals(deviceOwner.getPackageName())) {
+ throw new IllegalArgumentException("Cannot uninstall a package with a device owner");
+ }
+
+ final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ mPackagesToRemove.add(packageUserPair);
+ }
+
+ final List<ComponentName> activeAdminsList = getActiveAdmins(userId);
+ if (activeAdminsList == null || activeAdminsList.size() == 0) {
+ startUninstallIntent(packageName, userId);
+ return;
+ }
+
+ for (ComponentName activeAdmin : activeAdminsList) {
+ if (packageName.equals(activeAdmin.getPackageName())) {
+ removeActiveAdmin(activeAdmin, userId);
+ }
+ }
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ for (ComponentName activeAdmin : activeAdminsList) {
+ removeAdminArtifacts(activeAdmin, userId);
+ }
+ startUninstallIntent(packageName, userId);
+ }
+ }, DEVICE_ADMIN_DEACTIVATE_TIMEOUT); // Start uninstall after timeout anyway.
+ }
+
+ private void removePackageIfRequired(final String packageName, final int userId) {
+ if (!packageHasActiveAdmins(packageName, userId)) {
+ // Will not do anything if uninstall was not requested or was already started.
+ startUninstallIntent(packageName, userId);
+ }
+ }
+
+ private void startUninstallIntent(final String packageName, final int userId) {
+ final Pair<String, Integer> packageUserPair = new Pair<>(packageName, userId);
+ synchronized (this) {
+ if (!mPackagesToRemove.contains(packageUserPair)) {
+ // Do nothing if uninstall was not requested or was already started.
+ return;
+ }
+ mPackagesToRemove.remove(packageUserPair);
+ }
+ try {
+ if (mInjector.getIPackageManager().getPackageInfo(packageName, 0, userId) == null) {
+ // Package does not exist. Nothing to do.
+ return;
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Failure talking to PackageManager while getting package info");
+ }
+
+ try { // force stop the package before uninstalling
+ mInjector.getIActivityManager().forceStopPackage(packageName, userId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Failure talking to ActivityManager while force stopping package");
+ }
+ final Uri packageURI = Uri.parse("package:" + packageName);
+ final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
+ uninstallIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(uninstallIntent, UserHandle.of(userId));
+ }
+
+ /**
+ * Removes the admin from the policy. Ideally called after the admin's
+ * {@link DeviceAdminReceiver#onDisabled(Context, Intent)} has been successfully completed.
+ *
+ * @param adminReceiver The admin to remove
+ * @param userHandle The user for which this admin has to be removed.
+ */
+ private void removeAdminArtifacts(final ComponentName adminReceiver, final int userHandle) {
+ synchronized (this) {
+ final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
+ if (admin == null) {
+ return;
+ }
+ final DevicePolicyData policy = getUserData(userHandle);
+ final boolean doProxyCleanup = admin.info.usesPolicy(
+ DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
+ policy.mAdminList.remove(admin);
+ policy.mAdminMap.remove(adminReceiver);
+ validatePasswordOwnerLocked(policy);
+ if (doProxyCleanup) {
+ resetGlobalProxyLocked(policy);
+ }
+ saveSettingsLocked(userHandle);
+ updateMaximumTimeToLockLocked(userHandle);
+ policy.mRemovingAdmins.remove(adminReceiver);
+ }
+ // The removed admin might have disabled camera, so update user
+ // restrictions.
+ pushUserRestrictions(userHandle);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 880f810..68fd0f6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -716,11 +716,11 @@
}
File getLegacyConfigFileWithTestOverride() {
- return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML_LEGACY);
+ return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML_LEGACY);
}
File getDeviceOwnerFileWithTestOverride() {
- return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML);
+ return new File(Environment.getDataSystemDirectory(), DEVICE_OWNER_XML);
}
File getProfileOwnerFileWithTestOverride(int userId) {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 06b6ee7..027c325 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -92,13 +92,18 @@
*/
// Implementations must call IpManager#completedPreDhcpAction().
+ // TODO: Remove this requirement, perhaps via some
+ // registerForPreDhcpAction()-style mechanism.
public void onPreDhcpAction() {}
public void onPostDhcpAction() {}
- // TODO: Kill with fire once DHCP and static configuration are moved
- // out of WifiStateMachine.
- public void onIPv4ProvisioningSuccess(DhcpResults dhcpResults) {}
- public void onIPv4ProvisioningFailure() {}
+ // This is purely advisory and not an indication of provisioning
+ // success or failure. This is only here for callers that want to
+ // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
+ // DHCPv4 or static IPv4 configuration failure or success can be
+ // determined by whether or not the passed-in DhcpResults object is
+ // null or not.
+ public void onNewDhcpResults(DhcpResults dhcpResults) {}
public void onProvisioningSuccess(LinkProperties newLp) {}
public void onProvisioningFailure(LinkProperties newLp) {}
@@ -122,6 +127,7 @@
private final Object mLock = new Object();
private final State mStoppedState = new StoppedState();
+ private final State mStoppingState = new StoppingState();
private final State mStartedState = new StartedState();
private final Context mContext;
@@ -179,6 +185,8 @@
// Super simple StateMachine.
addState(mStoppedState);
addState(mStartedState);
+ addState(mStoppingState);
+
setInitialState(mStoppedState);
setLogRecSize(MAX_LOG_RECORDS);
super.start();
@@ -203,13 +211,11 @@
public void startProvisioning(StaticIpConfiguration staticIpConfig) {
getInterfaceIndex();
-
sendMessage(CMD_START, staticIpConfig);
}
public void startProvisioning() {
getInterfaceIndex();
-
sendMessage(CMD_START);
}
@@ -236,6 +242,42 @@
* Internals.
*/
+ @Override
+ protected String getWhatToString(int what) {
+ // TODO: Investigate switching to reflection.
+ switch (what) {
+ case CMD_STOP:
+ return "CMD_STOP";
+ case CMD_START:
+ return "CMD_START";
+ case CMD_CONFIRM:
+ return "CMD_CONFIRM";
+ case EVENT_PRE_DHCP_ACTION_COMPLETE:
+ return "EVENT_PRE_DHCP_ACTION_COMPLETE";
+ case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+ return "EVENT_NETLINK_LINKPROPERTIES_CHANGED";
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ return "DhcpStateMachine.CMD_PRE_DHCP_ACTION";
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ return "DhcpStateMachine.CMD_POST_DHCP_ACTION";
+ case DhcpStateMachine.CMD_ON_QUIT:
+ return "DhcpStateMachine.CMD_ON_QUIT";
+ }
+ return "UNKNOWN:" + Integer.toString(what);
+ }
+
+ @Override
+ protected String getLogRecString(Message msg) {
+ final String logLine = String.format(
+ "iface{%s/%d} arg1{%d} arg2{%d} obj{%s}",
+ mInterfaceName, mInterfaceIndex,
+ msg.arg1, msg.arg2, Objects.toString(msg.obj));
+ if (VDBG) {
+ Log.d(TAG, getWhatToString(msg.what) + " " + logLine);
+ }
+ return logLine;
+ }
+
private void getInterfaceIndex() {
try {
mInterfaceIndex = NetworkInterface.getByName(mInterfaceName).getIndex();
@@ -260,16 +302,93 @@
}
}
+ // For now: use WifiStateMachine's historical notion of provisioned.
+ private static boolean isProvisioned(LinkProperties lp) {
+ // For historical reasons, we should connect even if all we have is
+ // an IPv4 address and nothing else.
+ return lp.isProvisioned() || lp.hasIPv4Address();
+ }
+
+ // TODO: Investigate folding all this into the existing static function
+ // LinkProperties.compareProvisioning() or some other single function that
+ // takes two LinkProperties objects and returns a ProvisioningChange
+ // object that is a correct and complete assessment of what changed, taking
+ // account of the asymmetries described in the comments in this function.
+ // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
+ private static ProvisioningChange compareProvisioning(
+ LinkProperties oldLp, LinkProperties newLp) {
+ ProvisioningChange delta;
+
+ final boolean wasProvisioned = isProvisioned(oldLp);
+ final boolean isProvisioned = isProvisioned(newLp);
+
+ if (!wasProvisioned && isProvisioned) {
+ delta = ProvisioningChange.GAINED_PROVISIONING;
+ } else if (wasProvisioned && isProvisioned) {
+ delta = ProvisioningChange.STILL_PROVISIONED;
+ } else if (!wasProvisioned && !isProvisioned) {
+ delta = ProvisioningChange.STILL_NOT_PROVISIONED;
+ } else {
+ // (wasProvisioned && !isProvisioned)
+ //
+ // Note that this is true even if we lose a configuration element
+ // (e.g., a default gateway) that would not be required to advance
+ // into provisioned state. This is intended: if we have a default
+ // router and we lose it, that's a sure sign of a problem, but if
+ // we connect to a network with no IPv4 DNS servers, we consider
+ // that to be a network without DNS servers and connect anyway.
+ //
+ // See the comment below.
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ // Additionally:
+ //
+ // Partial configurations (e.g., only an IPv4 address with no DNS
+ // servers and no default route) are accepted as long as DHCPv4
+ // succeeds. On such a network, isProvisioned() will always return
+ // false, because the configuration is not complete, but we want to
+ // connect anyway. It might be a disconnected network such as a
+ // Chromecast or a wireless printer, for example.
+ //
+ // Because on such a network isProvisioned() will always return false,
+ // delta will never be LOST_PROVISIONING. So check for loss of
+ // provisioning here too.
+ if ((oldLp.hasIPv4Address() && !newLp.hasIPv4Address()) ||
+ (oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned())) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ return delta;
+ }
+
+ private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+ switch (delta) {
+ case GAINED_PROVISIONING:
+ if (VDBG) { Log.d(TAG, "onProvisioningSuccess()"); }
+ mCallback.onProvisioningSuccess(newLp);
+ break;
+
+ case LOST_PROVISIONING:
+ if (VDBG) { Log.d(TAG, "onProvisioningFailure()"); }
+ mCallback.onProvisioningFailure(newLp);
+ break;
+
+ default:
+ if (VDBG) { Log.d(TAG, "onLinkPropertiesChange()"); }
+ mCallback.onLinkPropertiesChange(newLp);
+ break;
+ }
+ }
+
private ProvisioningChange setLinkProperties(LinkProperties newLp) {
if (mIpReachabilityMonitor != null) {
mIpReachabilityMonitor.updateLinkProperties(newLp);
}
- // TODO: Figure out whether and how to incorporate static configuration
- // into the notion of provisioning.
ProvisioningChange delta;
synchronized (mLock) {
- delta = LinkProperties.compareProvisioning(mLinkProperties, newLp);
+ delta = compareProvisioning(mLinkProperties, newLp);
mLinkProperties = new LinkProperties(newLp);
}
@@ -351,15 +470,45 @@
private void handleIPv4Success(DhcpResults dhcpResults) {
mDhcpResults = new DhcpResults(dhcpResults);
- setLinkProperties(assembleLinkProperties());
- mCallback.onIPv4ProvisioningSuccess(dhcpResults);
+ final LinkProperties newLp = assembleLinkProperties();
+ final ProvisioningChange delta = setLinkProperties(newLp);
+
+ if (VDBG) {
+ Log.d(TAG, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
+ }
+ mCallback.onNewDhcpResults(dhcpResults);
+
+ dispatchCallback(delta, newLp);
}
private void handleIPv4Failure() {
+ // TODO: Figure out to de-dup this and the same code in DhcpClient.
clearIPv4Address();
mDhcpResults = null;
- setLinkProperties(assembleLinkProperties());
- mCallback.onIPv4ProvisioningFailure();
+ final LinkProperties newLp = assembleLinkProperties();
+ ProvisioningChange delta = setLinkProperties(newLp);
+ // If we've gotten here and we're still not provisioned treat that as
+ // a total loss of provisioning.
+ //
+ // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
+ // there was no usable IPv6 obtained before the DHCPv4 timeout.
+ //
+ // Regardless: GAME OVER.
+ //
+ // TODO: Make the DHCP client not time out and just continue in
+ // exponential backoff. Callers such as Wi-Fi which need a timeout
+ // should implement it themselves.
+ if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
+ if (VDBG) { Log.d(TAG, "onNewDhcpResults(null)"); }
+ mCallback.onNewDhcpResults(null);
+
+ dispatchCallback(delta, newLp);
+ if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ transitionTo(mStoppingState);
+ }
}
class StoppedState extends State {
@@ -391,13 +540,8 @@
break;
case DhcpStateMachine.CMD_ON_QUIT:
- // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
- // Shutting down DHCPv4 progresses simultaneously with
- // transitioning to StoppedState, so we can receive this
- // message after we've already transitioned here.
- //
- // TODO: Figure out if this is actually useful and if not
- // expunge it.
+ // Everything is already stopped.
+ Log.e(TAG, "Unexpected CMD_ON_QUIT (already stopped).");
break;
default:
@@ -407,6 +551,30 @@
}
}
+ class StoppingState extends State {
+ @Override
+ public void enter() {
+ if (mDhcpStateMachine == null) {
+ // There's no DHCPv4 for which to wait; proceed to stopped.
+ transitionTo(mStoppedState);
+ }
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case DhcpStateMachine.CMD_ON_QUIT:
+ mDhcpStateMachine = null;
+ transitionTo(mStoppedState);
+ break;
+
+ default:
+ deferMessage(msg);
+ }
+ return HANDLED;
+ }
+ }
+
class StartedState extends State {
@Override
public void enter() {
@@ -439,7 +607,9 @@
if (applyStaticIpConfig()) {
handleIPv4Success(new DhcpResults(mStaticIpConfig));
} else {
- handleIPv4Failure();
+ if (VDBG) { Log.d(TAG, "onProvisioningFailure()"); }
+ mCallback.onProvisioningFailure(getLinkProperties());
+ transitionTo(mStoppingState);
}
} else {
// Start DHCPv4.
@@ -457,7 +627,6 @@
if (mDhcpStateMachine != null) {
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
mDhcpStateMachine.doQuit();
- mDhcpStateMachine = null;
}
resetLinkProperties();
@@ -500,28 +669,15 @@
break;
}
final ProvisioningChange delta = setLinkProperties(newLp);
-
- // NOTE: The only receiver of these callbacks currently
- // treats all three of them identically, namely it calls
- // IpManager#getLinkProperties() and makes its own determination.
- switch (delta) {
- case GAINED_PROVISIONING:
- mCallback.onProvisioningSuccess(newLp);
- break;
-
- case LOST_PROVISIONING:
- mCallback.onProvisioningFailure(newLp);
- break;
-
- default:
- // TODO: Only notify on STILL_PROVISIONED?
- mCallback.onLinkPropertiesChange(newLp);
- break;
+ dispatchCallback(delta, newLp);
+ if (delta == ProvisioningChange.LOST_PROVISIONING) {
+ transitionTo(mStoppedState);
}
break;
}
case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ if (VDBG) { Log.d(TAG, "onPreDhcpAction()"); }
mCallback.onPreDhcpAction();
break;
@@ -529,6 +685,7 @@
// Note that onPostDhcpAction() is likely to be
// asynchronous, and thus there is no guarantee that we
// will be able to observe any of its effects here.
+ if (VDBG) { Log.d(TAG, "onPostDhcpAction()"); }
mCallback.onPostDhcpAction();
final DhcpResults dhcpResults = (DhcpResults) msg.obj;
@@ -546,11 +703,9 @@
}
case DhcpStateMachine.CMD_ON_QUIT:
- // CMD_ON_QUIT is really more like "EVENT_ON_QUIT".
- // Regardless, we ignore it.
- //
- // TODO: Figure out if this is actually useful and if not
- // expunge it.
+ // DHCPv4 quit early for some reason.
+ Log.e(TAG, "Unexpected CMD_ON_QUIT.");
+ mDhcpStateMachine = null;
break;
default:
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 429839f..0d6c70b 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -92,7 +92,33 @@
int NO_SMS_TO_ACK = 48; /* ACK received when there is no SMS to ack */
int NETWORK_ERR = 49; /* Received error from network */
int REQUEST_RATE_LIMITED = 50; /* Operation denied due to overly-frequent requests */
-
+ // Below is list of OEM specific error codes which can by used by OEMs in case they don't want to
+ // reveal particular replacement for Generic failure
+ int OEM_ERROR_1 = 501;
+ int OEM_ERROR_2 = 502;
+ int OEM_ERROR_3 = 503;
+ int OEM_ERROR_4 = 504;
+ int OEM_ERROR_5 = 505;
+ int OEM_ERROR_6 = 506;
+ int OEM_ERROR_7 = 507;
+ int OEM_ERROR_8 = 508;
+ int OEM_ERROR_9 = 509;
+ int OEM_ERROR_10 = 510;
+ int OEM_ERROR_11 = 511;
+ int OEM_ERROR_12 = 512;
+ int OEM_ERROR_13 = 513;
+ int OEM_ERROR_14 = 514;
+ int OEM_ERROR_15 = 515;
+ int OEM_ERROR_16 = 516;
+ int OEM_ERROR_17 = 517;
+ int OEM_ERROR_18 = 518;
+ int OEM_ERROR_19 = 519;
+ int OEM_ERROR_20 = 520;
+ int OEM_ERROR_21 = 521;
+ int OEM_ERROR_22 = 522;
+ int OEM_ERROR_23 = 523;
+ int OEM_ERROR_24 = 524;
+ int OEM_ERROR_25 = 525;
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */