Merge "eUICC API error code cleanup." into oc-dr1-dev
diff --git a/Android.mk b/Android.mk
index 3750548..933ac62 100644
--- a/Android.mk
+++ b/Android.mk
@@ -357,6 +357,7 @@
core/java/android/view/IPinnedStackController.aidl \
core/java/android/view/IPinnedStackListener.aidl \
core/java/android/view/IRotationWatcher.aidl \
+ core/java/android/view/IWallpaperVisibilityListener.aidl \
core/java/android/view/IWindow.aidl \
core/java/android/view/IWindowFocusObserver.aidl \
core/java/android/view/IWindowId.aidl \
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 3665d1b..4ee38fe 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -58,7 +58,7 @@
static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
final boolean result = deviceAddress == null
- || (device == null || !deviceAddress.equals(device.getAddress()));
+ || (device != null && deviceAddress.equals(device.getAddress()));
if (DEBUG) debugLogMatchResult(result, device, deviceAddress);
return result;
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9b0bab4..fdb0f2ba 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6852,7 +6852,7 @@
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
- ai.resourceDirs = state.resourceDirs;
+ ai.resourceDirs = state.overlayPaths;
}
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
@@ -7000,6 +7000,7 @@
return null;
}
if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
+ updateApplicationInfo(a.info.applicationInfo, flags, state);
return a.info;
}
// Make shallow copies so we can store the metadata safely
@@ -7088,6 +7089,7 @@
return null;
}
if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
+ updateApplicationInfo(s.info.applicationInfo, flags, state);
return s.info;
}
// Make shallow copies so we can store the metadata safely
@@ -7183,6 +7185,7 @@
if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
&& ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
|| p.info.uriPermissionPatterns == null)) {
+ updateApplicationInfo(p.info.applicationInfo, flags, state);
return p.info;
}
// Make shallow copies so we can store the metadata safely
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 4e53914..470336c 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -55,7 +55,7 @@
public ArraySet<String> disabledComponents;
public ArraySet<String> enabledComponents;
- public String[] resourceDirs;
+ public String[] overlayPaths;
public PackageUserState() {
installed = true;
@@ -83,8 +83,8 @@
installReason = o.installReason;
disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
- resourceDirs =
- o.resourceDirs == null ? null : Arrays.copyOf(o.resourceDirs, o.resourceDirs.length);
+ overlayPaths =
+ o.overlayPaths == null ? null : Arrays.copyOf(o.overlayPaths, o.overlayPaths.length);
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 784ed7a..921d518 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6803,6 +6803,22 @@
public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity";
/**
+ * Whether the assist gesture should silence alerts.
+ *
+ * @hide
+ */
+ public static final String ASSIST_GESTURE_SILENCE_ALERTS_ENABLED =
+ "assist_gesture_silence_alerts_enabled";
+
+ /**
+ * Whether the assist gesture should wake the phone.
+ *
+ * @hide
+ */
+ public static final String ASSIST_GESTURE_WAKE_ENABLED =
+ "assist_gesture_wake_enabled";
+
+ /**
* Whether Assist Gesture Deferred Setup has been completed
*
* @hide
@@ -7096,6 +7112,9 @@
AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
ASSIST_GESTURE_ENABLED,
ASSIST_GESTURE_SENSITIVITY,
+ ASSIST_GESTURE_SETUP_COMPLETE,
+ ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
+ ASSIST_GESTURE_WAKE_ENABLED,
VR_DISPLAY_MODE,
NOTIFICATION_BADGING
};
diff --git a/core/java/android/view/IWallpaperVisibilityListener.aidl b/core/java/android/view/IWallpaperVisibilityListener.aidl
new file mode 100644
index 0000000..349f984
--- /dev/null
+++ b/core/java/android/view/IWallpaperVisibilityListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Listener to be invoked when wallpaper visibility changes.
+ * {@hide}
+ */
+oneway interface IWallpaperVisibilityListener {
+ /**
+ * Method that will be invoked when wallpaper becomes visible or hidden.
+ * @param visible True if wallpaper is being displayed; false otherwise.
+ * @param displayId The id of the display where wallpaper visibility changed.
+ */
+ void onWallpaperVisibilityChanged(boolean visible, int displayId);
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 2b73c14..e576a0f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -39,6 +39,7 @@
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedStackListener;
import android.view.IRotationWatcher;
+import android.view.IWallpaperVisibilityListener;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
import android.view.KeyEvent;
@@ -256,6 +257,19 @@
Bitmap screenshotWallpaper();
/**
+ * Registers a wallpaper visibility listener.
+ * @return Current visibility.
+ */
+ boolean registerWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
+ int displayId);
+
+ /**
+ * Remove a visibility watcher that was added using registerWallpaperVisibilityListener.
+ */
+ void unregisterWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
+ int displayId);
+
+ /**
* Used only for assist -- request a screenshot of the current application.
*/
boolean requestAssistScreenshot(IAssistScreenshotReceiver receiver);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index de4d03e..489de56 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -996,6 +996,9 @@
observer.mNative = null;
}
+ /** Not actually public - internal use only. This doc to make lint happy */
+ public static native void disableVsync();
+
static native void setupShadersDiskCache(String cacheFile);
private static native void nRotateProcessStatsBuffer();
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 1e8207a..f712d5f 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -293,9 +293,19 @@
* @param setSelected whether to set the specified day as selected
*/
private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
+ boolean dateClamped = false;
+ // Clamp the target day in milliseconds to the min or max if outside the range.
+ if (timeInMillis < mMinDate.getTimeInMillis()) {
+ timeInMillis = mMinDate.getTimeInMillis();
+ dateClamped = true;
+ } else if (timeInMillis > mMaxDate.getTimeInMillis()) {
+ timeInMillis = mMaxDate.getTimeInMillis();
+ dateClamped = true;
+ }
+
getTempCalendarForTime(timeInMillis);
- if (setSelected) {
+ if (setSelected || dateClamped) {
mSelectedDay.setTimeInMillis(timeInMillis);
}
@@ -353,13 +363,6 @@
public void onRangeChanged() {
mAdapter.setRange(mMinDate, mMaxDate);
- // Clamp the selected day to the new min/max.
- if (mSelectedDay.before(mMinDate)) {
- mSelectedDay.setTimeInMillis(mMinDate.getTimeInMillis());
- } else if (mSelectedDay.after(mMaxDate)) {
- mSelectedDay.setTimeInMillis(mMaxDate.getTimeInMillis());
- }
-
// Changing the min/max date changes the selection position since we
// don't really have stable IDs. Jumps immediately to the new position.
setDate(mSelectedDay.getTimeInMillis(), false, false);
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index f4c18c3..1bee692 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -16,6 +16,7 @@
package com.android.internal.app;
+import android.app.PendingIntent;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.os.ParcelUuid;
@@ -26,7 +27,6 @@
*/
interface ISoundTriggerService {
-
SoundTrigger.GenericSoundModel getSoundModel(in ParcelUuid soundModelId);
void updateSoundModel(in SoundTrigger.GenericSoundModel soundModel);
@@ -36,8 +36,17 @@
int startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback,
in SoundTrigger.RecognitionConfig config);
- /**
- * Stops recognition.
- */
int stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
+
+ int loadGenericSoundModel(in SoundTrigger.GenericSoundModel soundModel);
+ int loadKeyphraseSoundModel(in SoundTrigger.KeyphraseSoundModel soundModel);
+
+ int startRecognitionForIntent(in ParcelUuid soundModelId, in PendingIntent callbackIntent,
+ in SoundTrigger.RecognitionConfig config);
+
+ int stopRecognitionForIntent(in ParcelUuid soundModelId);
+
+ int unloadSoundModel(in ParcelUuid soundModelId);
+
+ boolean isRecognitionActive(in ParcelUuid parcelUuid);
}
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 96b443d..1f84061 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -25,6 +25,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -101,7 +102,7 @@
/**
* Returns the given list, or an immutable empty list if the provided list is null
*
- * This can be used to guaranty null-safety without paying the price of extra allocations
+ * This can be used to guarantee null-safety without paying the price of extra allocations
*
* @see Collections#emptyList
*/
@@ -110,6 +111,17 @@
}
/**
+ * Returns the given set, or an immutable empty set if the provided set is null
+ *
+ * This can be used to guarantee null-safety without paying the price of extra allocations
+ *
+ * @see Collections#emptySet
+ */
+ public static @NonNull <T> Set<T> emptyIfNull(@Nullable Set<T> cur) {
+ return cur == null ? Collections.emptySet() : cur;
+ }
+
+ /**
* Returns the size of the given list, or 0 if the list is null
*/
public static int size(@Nullable Collection<?> cur) {
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index de67c50..26b0034 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <android-base/stringprintf.h>
#include <binder/IInterface.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
@@ -194,10 +195,34 @@
/*
* It's an Error: Reraise the exception and ask the runtime to abort.
*/
+
+ // Try to get the exception string. Sometimes logcat isn't available,
+ // so try to add it to the abort message.
+ std::string exc_msg = "(Unknown exception message)";
+ {
+ ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(excep));
+ jmethodID method_id = env->GetMethodID(exc_class.get(),
+ "toString",
+ "()Ljava/lang/String;");
+ ScopedLocalRef<jstring> jstr(
+ env,
+ reinterpret_cast<jstring>(
+ env->CallObjectMethod(excep, method_id)));
+ env->ExceptionClear(); // Just for good measure.
+ if (jstr.get() != nullptr) {
+ ScopedUtfChars jstr_utf(env, jstr.get());
+ exc_msg = jstr_utf.c_str();
+ }
+ }
+
env->Throw(excep);
ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
env->ExceptionDescribe();
- env->FatalError("java.lang.Error thrown during binder transaction.");
+
+ std::string error_msg = base::StringPrintf(
+ "java.lang.Error thrown during binder transaction: %s",
+ exc_msg.c_str());
+ env->FatalError(error_msg.c_str());
}
bail:
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 2657140..286c1a2 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -926,6 +926,10 @@
return createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_Mutable);
}
+static void android_view_ThreadedRenderer_disableVsync(JNIEnv*, jclass) {
+ RenderProxy::disableVsync();
+}
+
// ----------------------------------------------------------------------------
// FrameMetricsObserver
// ----------------------------------------------------------------------------
@@ -1024,6 +1028,7 @@
(void*)android_view_ThreadedRenderer_copySurfaceInto },
{ "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
(void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
+ { "disableVsync", "()V", (void*)android_view_ThreadedRenderer_disableVsync },
};
int register_android_view_ThreadedRenderer(JNIEnv* env) {
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index d154730..df2b35b 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -32,7 +32,8 @@
OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
- OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState, width, height);
+ OffscreenBuffer* buffer = mRenderState.layerPool().get(
+ mRenderState, width, height, mWideColorGamut);
startRepaintLayer(buffer, Rect(width, height));
return buffer;
}
@@ -103,7 +104,8 @@
OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) {
const uint32_t width = area.getWidth();
const uint32_t height = area.getHeight();
- OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState, width, height);
+ OffscreenBuffer* buffer = mRenderState.layerPool().get(
+ mRenderState, width, height, mWideColorGamut);
if (!area.isEmpty() && width != 0 && height != 0) {
mCaches.textureState().activateTexture(0);
mCaches.textureState().bindTexture(buffer->texture.id());
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 4d76a3d..01ca367 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -54,12 +54,13 @@
uint8_t spotShadowAlpha;
};
- BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque,
+ BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, bool wideColorGamut,
const LightInfo& lightInfo)
: mGlopReceiver(DefaultGlopReceiver)
, mRenderState(renderState)
, mCaches(caches)
, mOpaque(opaque)
+ , mWideColorGamut(wideColorGamut)
, mLightInfo(lightInfo) {
}
@@ -118,6 +119,7 @@
RenderState& mRenderState;
Caches& mCaches;
bool mOpaque;
+ bool mWideColorGamut;
bool mHasDrawn = false;
// render target state - setup by start/end layer/frame
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index aad81df..b587248 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -69,6 +69,7 @@
bool Properties::forceDrawFrame = false;
bool Properties::filterOutTestOverhead = false;
+bool Properties::disableVsync = false;
static int property_get_int(const char* key, int defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {'\0',};
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 9db6449..91b4a2d 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -318,6 +318,12 @@
// any overhead they add
static bool filterOutTestOverhead;
+ // Workaround a device lockup in edge cases by switching to async mode
+ // instead of the default vsync (b/38372997). Only system_server should hit this.
+ // Any existing RenderProxy & Surface combination will be unaffected, only things
+ // created after changing this.
+ static bool disableVsync;
+
// Used for testing only to change the render pipeline.
#ifdef HWUI_GLES_WRAP_ENABLED
static void overrideRenderPipelineType(RenderPipelineType);
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 959059f..4ef31d5 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -120,6 +120,10 @@
void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height,
GLenum format, GLenum type, const void* pixels) {
GL_CHECKPOINT(MODERATE);
+
+ // We don't have color space information, we assume the data is gamma encoded
+ mIsLinear = false;
+
bool needsAlloc = updateLayout(width, height, internalFormat, format, GL_TEXTURE_2D);
if (!mId) {
glGenTextures(1, &mId);
@@ -309,11 +313,16 @@
bool rgba16fNeedsConversion = bitmap.colorType() == kRGBA_F16_SkColorType
&& internalFormat != GL_RGBA16F;
+ // RGBA16F is always linear extended sRGB
+ if (internalFormat == GL_RGBA16F) {
+ mIsLinear = true;
+ }
+
mConnector.reset();
- // RGBA16F is always extended sRGB, alpha masks don't have color profiles
+ // Alpha masks don't have color profiles
// If an RGBA16F bitmap needs conversion, we know the target will be sRGB
- if (internalFormat != GL_RGBA16F && internalFormat != GL_ALPHA && !rgba16fNeedsConversion) {
+ if (!mIsLinear && internalFormat != GL_ALPHA && !rgba16fNeedsConversion) {
SkColorSpace* colorSpace = bitmap.info().colorSpace();
// If the bitmap is sRGB we don't need conversion
if (colorSpace != nullptr && !colorSpace->isSRGB()) {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 55b74ed..7f742e6 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -88,7 +88,8 @@
* The image data is undefined after calling this.
*/
void resize(uint32_t width, uint32_t height, GLint internalFormat, GLint format) {
- upload(internalFormat, width, height, format, GL_UNSIGNED_BYTE, nullptr);
+ upload(internalFormat, width, height, format,
+ internalFormat == GL_RGBA16F ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE, nullptr);
}
/**
@@ -155,7 +156,7 @@
* Returns true if this texture uses a linear encoding format.
*/
constexpr bool isLinear() const {
- return mInternalFormat == GL_RGBA16F;
+ return mIsLinear;
}
/**
@@ -219,6 +220,9 @@
GLenum mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
GLenum mMagFilter = GL_LINEAR;
+ // Indicates whether the content of the texture is in linear space
+ bool mIsLinear = false;
+
Caches& mCaches;
std::unique_ptr<ColorSpaceConnector> mConnector;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 095d32e..6d5ef1d 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -61,7 +61,7 @@
const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
@@ -85,7 +85,8 @@
mRenderThread.getGrContext(), renderTargetDesc, &props));
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
- renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut,
+ contentDrawBounds, surface);
layerUpdateQueue->clear();
// Draw visual debugging features
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index d5471de..aa29c8e 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -35,7 +35,7 @@
bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector< sp<RenderNode> >& renderNodes,
FrameInfoVisualizer* profiler) override;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index bbbbd5c..0bab793 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -72,16 +72,18 @@
}
void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo) {
updateLighting(lightGeometry, lightInfo);
ATRACE_NAME("draw layers");
renderVectorDrawableCache();
- renderLayersImpl(*layerUpdateQueue, opaque);
+ renderLayersImpl(*layerUpdateQueue, opaque, wideColorGamut);
layerUpdateQueue->clear();
}
-void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque) {
+void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers,
+ bool opaque, bool wideColorGamut) {
+ // TODO: Handle wide color gamut
// Render all layers that need to be updated, in order.
for (size_t i = 0; i < layers.entries().size(); i++) {
RenderNode* layerNode = layers.entries()[i].renderNode.get();
@@ -129,12 +131,13 @@
}
bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator) {
+ const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
SkSurface* layer = node->getLayerSurface();
if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
+ // TODO: Handle wide color gamut requests
node->setLayerSurface(
SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
info, 0, &props));
@@ -203,13 +206,13 @@
}
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
- sk_sp<SkSurface> surface) {
+ const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+ const Rect &contentDrawBounds, sk_sp<SkSurface> surface) {
renderVectorDrawableCache();
// draw all layers up front
- renderLayersImpl(layers, opaque);
+ renderLayersImpl(layers, opaque, wideColorGamut);
// initialize the canvas for the current frame
SkCanvas* canvas = surface->getCanvas();
@@ -227,7 +230,7 @@
}
}
- renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
+ renderFrameImpl(layers, clip, nodes, opaque, wideColorGamut, contentDrawBounds, canvas);
if (skpCaptureEnabled() && recordingPicture) {
sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
@@ -260,8 +263,8 @@
}
void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
- SkCanvas* canvas) {
+ const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+ const Rect &contentDrawBounds, SkCanvas* canvas) {
SkAutoCanvasRestore saver(canvas, true);
canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
@@ -388,7 +391,7 @@
// each time a pixel would have been drawn.
// Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
// initialized.
- renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas);
+ renderFrameImpl(layers, clip, nodes, true, false, contentDrawBounds, &overdrawCanvas);
sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
// Draw overdraw colors to the canvas. The color filter will convert counts to colors.
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 6f5e719..19ffc46 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -39,15 +39,15 @@
void unpinImages() override;
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo) override;
bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator) override;
+ const DamageAccumulator& damageAccumulator, bool wideColorGamut) override;
void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
- sk_sp<SkSurface> surface);
+ const std::vector< sp<RenderNode> >& nodes, bool opaque, bool wideColorGamut,
+ const Rect &contentDrawBounds, sk_sp<SkSurface> surface);
std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
@@ -55,7 +55,7 @@
static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
- static void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque);
+ static void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, bool wideColorGamut);
static bool skpCaptureEnabled() { return false; }
@@ -110,8 +110,8 @@
private:
void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
- SkCanvas* canvas);
+ const std::vector< sp<RenderNode> >& nodes, bool opaque, bool wideColorGamut,
+ const Rect &contentDrawBounds, SkCanvas* canvas);
/**
* Debugging feature. Draws a semi-transparent overlay on each pixel, indicating
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index f1ef9e6..e1ef71f7 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -66,7 +66,7 @@
const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
@@ -76,7 +76,8 @@
return false;
}
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
- renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer);
+ renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut,
+ contentDrawBounds, backBuffer);
layerUpdateQueue->clear();
// Draw visual debugging features
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 3481312..263206d 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -33,7 +33,7 @@
bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector< sp<RenderNode> >& renderNodes,
FrameInfoVisualizer* profiler) override;
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index a9bbb27..90b27c8 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -35,17 +35,19 @@
////////////////////////////////////////////////////////////////////////////////
OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t viewportWidth, uint32_t viewportHeight)
+ uint32_t viewportWidth, uint32_t viewportHeight, bool wideColorGamut)
: GpuMemoryTracker(GpuObjectType::OffscreenBuffer)
, renderState(renderState)
, viewportWidth(viewportWidth)
, viewportHeight(viewportHeight)
- , texture(caches) {
+ , texture(caches)
+ , wideColorGamut(wideColorGamut) {
uint32_t width = computeIdealDimension(viewportWidth);
uint32_t height = computeIdealDimension(viewportHeight);
ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height);
caches.textureState().activateTexture(0);
- texture.resize(width, height, caches.rgbaInternalFormat(), GL_RGBA);
+ texture.resize(width, height,
+ wideColorGamut ? GL_RGBA16F : caches.rgbaInternalFormat(), GL_RGBA);
texture.blend = true;
texture.setWrap(GL_CLAMP_TO_EDGE);
// not setting filter on texture, since it's set when drawing, based on transform
@@ -127,7 +129,10 @@
int deltaInt = int(lhs.width) - int(rhs.width);
if (deltaInt != 0) return deltaInt;
- return int(lhs.height) - int(rhs.height);
+ deltaInt = int(lhs.height) - int(rhs.height);
+ if (deltaInt != 0) return deltaInt;
+
+ return int(lhs.wideColorGamut) - int(rhs.wideColorGamut);
}
void OffscreenBufferPool::clear() {
@@ -139,10 +144,10 @@
}
OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState,
- const uint32_t width, const uint32_t height) {
+ const uint32_t width, const uint32_t height, bool wideColorGamut) {
OffscreenBuffer* layer = nullptr;
- Entry entry(width, height);
+ Entry entry(width, height, wideColorGamut);
auto iter = mPool.find(entry);
if (iter != mPool.end()) {
@@ -154,7 +159,8 @@
layer->viewportHeight = height;
mSize -= layer->getSizeInBytes();
} else {
- layer = new OffscreenBuffer(renderState, Caches::getInstance(), width, height);
+ layer = new OffscreenBuffer(renderState, Caches::getInstance(),
+ width, height, wideColorGamut);
}
return layer;
@@ -174,7 +180,7 @@
return layer;
}
putOrDelete(layer);
- return get(renderState, width, height);
+ return get(renderState, width, height, layer->wideColorGamut);
}
void OffscreenBufferPool::dump() {
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index 26d4e36..d9422c9 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -43,7 +43,7 @@
class OffscreenBuffer : GpuMemoryTracker {
public:
OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t viewportWidth, uint32_t viewportHeight);
+ uint32_t viewportWidth, uint32_t viewportHeight, bool wideColorGamut = false);
~OffscreenBuffer();
Rect getTextureCoordinates();
@@ -68,6 +68,8 @@
uint32_t viewportHeight;
Texture texture;
+ bool wideColorGamut = false;
+
// Portion of layer that has been drawn to. Used to minimize drawing area when
// drawing back to screen / parent FBO.
Region region;
@@ -90,7 +92,7 @@
~OffscreenBufferPool();
WARN_UNUSED_RESULT OffscreenBuffer* get(RenderState& renderState,
- const uint32_t width, const uint32_t height);
+ const uint32_t width, const uint32_t height, bool wideColorGamut = false);
WARN_UNUSED_RESULT OffscreenBuffer* resize(OffscreenBuffer* layer,
const uint32_t width, const uint32_t height);
@@ -122,14 +124,16 @@
struct Entry {
Entry() {}
- Entry(const uint32_t layerWidth, const uint32_t layerHeight)
+ Entry(const uint32_t layerWidth, const uint32_t layerHeight, bool wideColorGamut)
: width(OffscreenBuffer::computeIdealDimension(layerWidth))
- , height(OffscreenBuffer::computeIdealDimension(layerHeight)) {}
+ , height(OffscreenBuffer::computeIdealDimension(layerHeight))
+ , wideColorGamut(wideColorGamut) {}
explicit Entry(OffscreenBuffer* layer)
: layer(layer)
, width(layer->texture.width())
- , height(layer->texture.height()) {
+ , height(layer->texture.height())
+ , wideColorGamut(layer->wideColorGamut) {
}
static int compare(const Entry& lhs, const Entry& rhs);
@@ -149,6 +153,7 @@
OffscreenBuffer* layer = nullptr;
uint32_t width = 0;
uint32_t height = 0;
+ bool wideColorGamut = false;
}; // struct Entry
std::multiset<Entry> mPool;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a79bf35..7799248 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -421,7 +421,7 @@
SkRect windowDirty = computeDirtyRect(frame, &dirty);
bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
- mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes, &(profiler()));
+ mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, mRenderNodes, &(profiler()));
waitOnFences();
@@ -563,7 +563,8 @@
// purposes when the frame is actually drawn
node->setPropertyFieldsDirty(RenderNode::GENERIC);
- mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mLightInfo);
+ mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue,
+ mOpaque, mWideColorGamut, mLightInfo);
node->incStrong(nullptr);
mPrefetchedLayers.insert(node);
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 76623f9..b1f4050 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -76,7 +76,7 @@
* @return true if the layer has been created or updated
*/
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator) {
- return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator);
+ return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator, mWideColorGamut);
}
/**
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index ecf686c..d6240e7 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -357,6 +357,9 @@
}
}
mCurrentSurface = surface;
+ if (Properties::disableVsync) {
+ eglSwapInterval(mEglDisplay, 0);
+ }
return true;
}
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 46ac0d2..f9b6e38 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -59,7 +59,7 @@
virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector< sp<RenderNode> >& renderNodes,
FrameInfoVisualizer* profiler) = 0;
@@ -73,11 +73,11 @@
virtual bool isContextReady() = 0;
virtual void onDestroyHardwareResources() = 0;
virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo) = 0;
virtual TaskManager* getTaskManager() = 0;
virtual bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator) = 0;
+ const DamageAccumulator& damageAccumulator, bool wideColorGamut) = 0;
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
virtual void unpinImages() = 0;
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index e15d0eb..7283eb1 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -58,7 +58,7 @@
bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector< sp<RenderNode> >& renderNodes,
FrameInfoVisualizer* profiler) {
@@ -77,7 +77,7 @@
frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
BakedOpRenderer renderer(caches, mRenderThread.renderState(),
- opaque, lightInfo);
+ opaque, wideColorGamut, lightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
ProfileRenderer profileRenderer(renderer);
profiler->draw(profileRenderer);
@@ -184,14 +184,14 @@
}
void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo) {
static const std::vector< sp<RenderNode> > emptyNodeList;
auto& caches = Caches::getInstance();
FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
layerUpdateQueue->clear();
- BakedOpRenderer renderer(caches, mRenderThread.renderState(),
- opaque, lightInfo);
+ // TODO: Handle wide color gamut contexts
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, lightInfo);
LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
@@ -205,12 +205,13 @@
}
bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator) {
+ const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
RenderState& renderState = mRenderThread.renderState();
OffscreenBufferPool& layerPool = renderState.layerPool();
bool transformUpdateNeeded = false;
if (node->getLayer() == nullptr) {
- node->setLayer(layerPool.get(renderState, node->getWidth(), node->getHeight()));
+ node->setLayer(layerPool.get(renderState,
+ node->getWidth(), node->getHeight(), wideColorGamut));
transformUpdateNeeded = true;
} else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
// TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 0e8c3f5..4ca19fb 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -36,7 +36,7 @@
bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
const FrameBuilder::LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo,
const std::vector< sp<RenderNode> >& renderNodes,
FrameInfoVisualizer* profiler) override;
@@ -50,11 +50,11 @@
bool isContextReady() override;
void onDestroyHardwareResources() override;
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
const BakedOpRenderer::LightInfo& lightInfo) override;
TaskManager* getTaskManager() override;
bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator) override;
+ const DamageAccumulator& damageAccumulator, bool wideColorGamut) override;
bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
void unpinImages() override;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index ec56c31..80c2955 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -18,6 +18,7 @@
#include "DeferredLayerUpdater.h"
#include "DisplayList.h"
+#include "Properties.h"
#include "Readback.h"
#include "Rect.h"
#include "renderthread/CanvasContext.h"
@@ -709,6 +710,10 @@
thread.queue(task);
}
+void RenderProxy::disableVsync() {
+ Properties::disableVsync = true;
+}
+
void RenderProxy::post(RenderTask* task) {
mRenderThread.queue(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index e1e2808..31f0ce6 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -138,6 +138,8 @@
static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
static void onBitmapDestroyed(uint32_t pixelRefId);
+
+ ANDROID_API static void disableVsync();
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index 398e7a8..a5e85df 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -83,7 +83,7 @@
sLightGeometry, caches);
frameBuilder.deferRenderNode(*node);
- BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
+ BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
benchmark::DoNotOptimize(&renderer);
}
@@ -142,7 +142,7 @@
sLightGeometry, Caches::getInstance());
frameBuilder.deferRenderNode(*node);
- BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
+ BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
benchmark::DoNotOptimize(&renderer);
}
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index c46592c..b0ef11f 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -37,7 +37,7 @@
class ValidatingBakedOpRenderer : public BakedOpRenderer {
public:
ValidatingBakedOpRenderer(RenderState& renderState, std::function<void(const Glop& glop)> validator)
- : BakedOpRenderer(Caches::getInstance(), renderState, true, sLightInfo)
+ : BakedOpRenderer(Caches::getInstance(), renderState, true, false, sLightInfo)
, mValidator(validator) {
mGlopReceiver = ValidatingGlopReceiver;
}
diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
index 380062a..603599c 100644
--- a/libs/hwui/tests/unit/BakedOpRendererTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
@@ -24,7 +24,8 @@
const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) {
- BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(), true, sLightInfo);
+ BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(),
+ true, false, sLightInfo);
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200u, 200u);
layer.dirty(Rect(200, 200));
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index 6c42ca1..19d7ef5 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -45,7 +45,7 @@
FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
sLightGeometery, Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
- BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
+ BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
@@ -62,6 +62,6 @@
FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
sLightGeometery, Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
- BakedOpRenderer renderer(caches, renderState, true, sLightInfo);
+ BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 6cd595a..919852f 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -41,6 +41,19 @@
EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
}
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, constructWideColorGamut) {
+ OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u, true);
+ EXPECT_EQ(49u, layer.viewportWidth);
+ EXPECT_EQ(149u, layer.viewportHeight);
+
+ EXPECT_EQ(64u, layer.texture.width());
+ EXPECT_EQ(192u, layer.texture.height());
+
+ EXPECT_TRUE(layer.wideColorGamut);
+
+ EXPECT_EQ(64u * 192u * 8u, layer.getSizeInBytes());
+}
+
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, getTextureCoordinates) {
OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
EXPECT_EQ(Rect(0, 1, 1, 0),
@@ -88,6 +101,47 @@
EXPECT_EQ(0u, pool.getCount());
}
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClearWideColorGamut) {
+ OffscreenBufferPool pool;
+
+ auto layer = pool.get(renderThread.renderState(), 100u, 200u, true);
+ EXPECT_EQ(100u, layer->viewportWidth);
+ EXPECT_EQ(200u, layer->viewportHeight);
+ EXPECT_TRUE(layer->wideColorGamut);
+
+ ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize());
+
+ pool.putOrDelete(layer);
+ ASSERT_EQ(layer->getSizeInBytes(), pool.getSize());
+
+ auto layer2 = pool.get(renderThread.renderState(), 102u, 202u, true);
+ EXPECT_EQ(layer, layer2) << "layer should be recycled";
+ ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer";
+
+ pool.putOrDelete(layer2);
+ EXPECT_EQ(1u, pool.getCount());
+ pool.clear();
+ EXPECT_EQ(0u, pool.getSize());
+ EXPECT_EQ(0u, pool.getCount());
+
+ // add non wide gamut layer
+ auto layer3 = pool.get(renderThread.renderState(), 100u, 200u);
+ EXPECT_FALSE(layer3->wideColorGamut);
+ pool.putOrDelete(layer3);
+ EXPECT_EQ(1u, pool.getCount());
+
+ auto layer4 = pool.get(renderThread.renderState(), 100u, 200u, true);
+ EXPECT_TRUE(layer4->wideColorGamut);
+ EXPECT_EQ(1u, pool.getCount());
+ ASSERT_NE(layer3, layer4);
+
+ pool.putOrDelete(layer4);
+
+ pool.clear();
+ EXPECT_EQ(0u, pool.getSize());
+ EXPECT_EQ(0u, pool.getCount());
+}
+
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resize) {
OffscreenBufferPool pool;
@@ -123,6 +177,43 @@
pool.putOrDelete(layer2);
}
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resizeWideColorGamut) {
+ OffscreenBufferPool pool;
+
+ auto layer = pool.get(renderThread.renderState(), 64u, 64u, true);
+
+ // resize in place
+ ASSERT_EQ(layer, pool.resize(layer, 60u, 55u));
+ EXPECT_EQ(60u, layer->viewportWidth);
+ EXPECT_EQ(55u, layer->viewportHeight);
+ EXPECT_EQ(64u, layer->texture.width());
+ EXPECT_EQ(64u, layer->texture.height());
+
+ EXPECT_TRUE(layer->wideColorGamut);
+ EXPECT_EQ(64u * 64u * 8u, layer->getSizeInBytes());
+
+ // resized to use different object in pool
+ auto layer2 = pool.get(renderThread.renderState(), 128u, 128u, true);
+ pool.putOrDelete(layer2);
+ ASSERT_EQ(1u, pool.getCount());
+
+ // add a non-wide gamut layer
+ auto layer3 = pool.get(renderThread.renderState(), 128u, 128u);
+ pool.putOrDelete(layer3);
+ ASSERT_EQ(2u, pool.getCount());
+
+ ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u));
+ EXPECT_EQ(120u, layer2->viewportWidth);
+ EXPECT_EQ(125u, layer2->viewportHeight);
+ EXPECT_EQ(128u, layer2->texture.width());
+ EXPECT_EQ(128u, layer2->texture.height());
+
+ EXPECT_TRUE(layer2->wideColorGamut);
+ EXPECT_EQ(128u * 128u * 8u, layer2->getSizeInBytes());
+
+ pool.putOrDelete(layer2);
+}
+
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, putAndDestroy) {
OffscreenBufferPool pool;
// layer too big to return to the pool
@@ -153,3 +244,4 @@
EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
}
+
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 686d06f..4c3e182 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -450,7 +450,7 @@
LayerUpdateQueue layerUpdateQueue;
layerUpdateQueue.enqueueLayerWithDamage(child.get(),
android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
- SkiaPipeline::renderLayersImpl(layerUpdateQueue, true);
+ SkiaPipeline::renderLayersImpl(layerUpdateQueue, true, false);
EXPECT_EQ(1, drawCounter); //assert index 0 is drawn on the layer
RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index a895cba..b397b15 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -51,7 +51,8 @@
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
+ opaque, false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
@@ -72,10 +73,12 @@
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
+ true, false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
+ false, false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
}
@@ -94,7 +97,8 @@
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
+ true, false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED);
@@ -135,7 +139,7 @@
lightGeometry.center = { 0.0f, 0.0f, 0.0f };
BakedOpRenderer::LightInfo lightInfo;
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
- pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, lightInfo);
+ pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo);
ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorRED);
ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 1), SK_ColorWHITE);
@@ -166,32 +170,38 @@
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
// Single draw, should be white.
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
+ false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
// 1 Overdraw, should be blue blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
+ false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
// 2 Overdraw, should be green blended onto white
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
+ false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0);
// 3 Overdraw, should be pink blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
+ false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0);
// 4 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
+ false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
// 5 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
+ false, contentDrawBounds, surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
}
@@ -278,7 +288,7 @@
SkRect dirty = SkRect::MakeWH(800, 600);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
sk_sp<DeferLayer<DeferTestCanvas>> surface(new DeferLayer<DeferTestCanvas>());
- pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false, contentDrawBounds, surface);
EXPECT_EQ(4, surface->canvas()->mDrawCounter);
}
@@ -308,7 +318,7 @@
SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
- pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
+ pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
@@ -339,7 +349,7 @@
SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>());
- pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true,
+ pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 7f8140a..92ffae0 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -15,7 +15,9 @@
*/
package android.media.soundtrigger;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
+import android.app.PendingIntent;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -23,6 +25,10 @@
import android.annotation.SystemService;
import android.content.Context;
import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.SoundModel;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.os.Handler;
import android.os.ParcelUuid;
import android.os.RemoteException;
@@ -178,4 +184,144 @@
return mGenericSoundModel;
}
}
+
+
+ /**
+ * Default message type.
+ * @hide
+ */
+ public static final int FLAG_MESSAGE_TYPE_UNKNOWN = -1;
+ /**
+ * Contents of EXTRA_MESSAGE_TYPE extra for a RecognitionEvent.
+ * @hide
+ */
+ public static final int FLAG_MESSAGE_TYPE_RECOGNITION_EVENT = 0;
+ /**
+ * Contents of EXTRA_MESSAGE_TYPE extra for recognition error events.
+ * @hide
+ */
+ public static final int FLAG_MESSAGE_TYPE_RECOGNITION_ERROR = 1;
+ /**
+ * Contents of EXTRA_MESSAGE_TYPE extra for a recognition paused events.
+ * @hide
+ */
+ public static final int FLAG_MESSAGE_TYPE_RECOGNITION_PAUSED = 2;
+ /**
+ * Contents of EXTRA_MESSAGE_TYPE extra for recognition resumed events.
+ * @hide
+ */
+ public static final int FLAG_MESSAGE_TYPE_RECOGNITION_RESUMED = 3;
+
+ /**
+ * Extra key in the intent for the type of the message.
+ * @hide
+ */
+ public static final String EXTRA_MESSAGE_TYPE = "android.media.soundtrigger.MESSAGE_TYPE";
+ /**
+ * Extra key in the intent that holds the RecognitionEvent parcelable.
+ * @hide
+ */
+ public static final String EXTRA_RECOGNITION_EVENT = "android.media.soundtrigger.RECOGNITION_EVENT";
+ /**
+ * Extra key in the intent that holds the status in an error message.
+ * @hide
+ */
+ public static final String EXTRA_STATUS = "android.media.soundtrigger.STATUS";
+
+ /**
+ * Loads a given sound model into the sound trigger. Note the model will be unloaded if there is
+ * an error/the system service is restarted.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int loadSoundModel(SoundModel soundModel) {
+ if (soundModel == null) {
+ return STATUS_ERROR;
+ }
+
+ try {
+ switch (soundModel.type) {
+ case SoundModel.TYPE_GENERIC_SOUND:
+ return mSoundTriggerService.loadGenericSoundModel(
+ (GenericSoundModel) soundModel);
+ case SoundModel.TYPE_KEYPHRASE:
+ return mSoundTriggerService.loadKeyphraseSoundModel(
+ (KeyphraseSoundModel) soundModel);
+ default:
+ Slog.e(TAG, "Unkown model type");
+ return STATUS_ERROR;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Starts recognition on the given model id. All events from the model will be sent to the
+ * PendingIntent.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int startRecognition(UUID soundModelId, PendingIntent callbackIntent,
+ RecognitionConfig config) {
+ if (soundModelId == null || callbackIntent == null || config == null) {
+ return STATUS_ERROR;
+ }
+ try {
+ return mSoundTriggerService.startRecognitionForIntent(new ParcelUuid(soundModelId),
+ callbackIntent, config);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Stops the given model's recognition.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int stopRecognition(UUID soundModelId) {
+ if (soundModelId == null) {
+ return STATUS_ERROR;
+ }
+ try {
+ return mSoundTriggerService.stopRecognitionForIntent(new ParcelUuid(soundModelId));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes the given model from memory. Will also stop any pending recognitions.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public int unloadSoundModel(UUID soundModelId) {
+ if (soundModelId == null) {
+ return STATUS_ERROR;
+ }
+ try {
+ return mSoundTriggerService.unloadSoundModel(
+ new ParcelUuid(soundModelId));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns true if the given model has had detection started on it.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
+ public boolean isRecognitionActive(UUID soundModelId) {
+ if (soundModelId == null) {
+ return false;
+ }
+ try {
+ return mSoundTriggerService.isRecognitionActive(
+ new ParcelUuid(soundModelId));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 2a4ab0f..3b29a6c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -20,6 +20,8 @@
import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress;
import static com.android.internal.util.ArrayUtils.isEmpty;
+import static com.android.internal.util.CollectionUtils.emptyIfNull;
+import static com.android.internal.util.CollectionUtils.size;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -154,6 +156,25 @@
onReadyToShowUI();
}
+ // If filtering to get single device by mac address, also search in the set of already
+ // bonded devices to allow linking those directly
+ String singleMacAddressFilter = null;
+ if (mRequest.isSingleDevice()) {
+ int numFilters = size(mBluetoothFilters);
+ for (int i = 0; i < numFilters; i++) {
+ BluetoothDeviceFilter filter = mBluetoothFilters.get(i);
+ if (!TextUtils.isEmpty(filter.getAddress())) {
+ singleMacAddressFilter = filter.getAddress();
+ break;
+ }
+ }
+ }
+ if (singleMacAddressFilter != null) {
+ for (BluetoothDevice dev : emptyIfNull(mBluetoothAdapter.getBondedDevices())) {
+ onDeviceFound(DeviceFilterPair.findMatch(dev, mBluetoothFilters));
+ }
+ }
+
if (shouldScan(mBluetoothFilters)) {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
@@ -211,6 +232,8 @@
}
private void onDeviceFound(@Nullable DeviceFilterPair device) {
+ if (device == null) return;
+
if (mDevicesFound.contains(device)) {
return;
}
@@ -444,12 +467,9 @@
}
for (int i = 0; i < scanResults.size(); i++) {
- DeviceFilterPair<android.net.wifi.ScanResult> deviceFilterPair =
- DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters);
- if (deviceFilterPair != null) onDeviceFound(deviceFilterPair);
+ onDeviceFound(DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters));
}
}
-
}
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
index a36f583..17d820a 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/PageRangeUtils.java
@@ -426,7 +426,7 @@
// be based off the start of the written ones instead of zero.
// The written pages are always non-null and not empty.
final int offset = -pagesWrittenToFile[0].getStart();
- PageRangeUtils.offset(pagesInDocRequested, offset);
+ PageRangeUtils.offset(pagesInDocRequested.clone(), offset);
return pagesInDocRequested;
} else if (Arrays.equals(pagesInDocRequested, ALL_PAGES_RANGE)
&& isAllPages(pagesWrittenToFile, pageCount)) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 474de90..1cbb745 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -88,21 +88,16 @@
private static final String XMLTAG_TIMEZONE = "timezone";
public static CharSequence getTimeZoneOffsetAndName(Context context, TimeZone tz, Date now) {
- final Locale locale = Locale.getDefault();
- final CharSequence gmtText = getGmtOffsetText(context, locale, tz, now);
- final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
- final ZoneGetterData data = new ZoneGetterData(context);
-
- final boolean useExemplarLocationForLocalNames =
- shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
- final CharSequence zoneName = getTimeZoneDisplayName(data, timeZoneNames,
- useExemplarLocationForLocalNames, tz, tz.getID());
- if (zoneName == null) {
+ Locale locale = Locale.getDefault();
+ CharSequence gmtText = getGmtOffsetText(context, locale, tz, now);
+ TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
+ String zoneNameString = getZoneLongName(timeZoneNames, tz, now);
+ if (zoneNameString == null) {
return gmtText;
}
// We don't use punctuation here to avoid having to worry about localizing that too!
- return TextUtils.concat(gmtText, " ", zoneName);
+ return TextUtils.concat(gmtText, " ", zoneNameString);
}
public static List<Map<String, Object>> getZonesList(Context context) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 9d09737..e067de1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -34,6 +34,8 @@
public static final String CATEGORY_SOUND = "com.android.settings.category.ia.sound";
public static final String CATEGORY_STORAGE = "com.android.settings.category.ia.storage";
public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
+ public static final String CATEGORY_SECURITY_LOCKSCREEN =
+ "com.android.settings.category.ia.lockscreen";
public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
public static final String CATEGORY_SYSTEM_LANGUAGE =
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java
index 703e9d2..a3345ee 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/utils/ZoneGetterTest.java
@@ -47,9 +47,9 @@
}
@Test
- public void getTimeZoneOffsetAndName_setLondon_returnLondon() {
- // Check it will ends with 'London', not 'British Summer Time' or sth else
- testTimeZoneOffsetAndNameInner(TIME_ZONE_LONDON_ID, "London");
+ public void getTimeZoneOffsetAndName_setLondon_returnBritishSummerTime() {
+ // Check it will ends with 'British Summer Time', not 'London' or sth else
+ testTimeZoneOffsetAndNameInner(TIME_ZONE_LONDON_ID, "British Summer Time");
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index 40353e7..9fc8a96 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -54,13 +54,14 @@
allKeys.add(CategoryKey.CATEGORY_SOUND);
allKeys.add(CategoryKey.CATEGORY_STORAGE);
allKeys.add(CategoryKey.CATEGORY_SECURITY);
+ allKeys.add(CategoryKey.CATEGORY_SECURITY_LOCKSCREEN);
allKeys.add(CategoryKey.CATEGORY_ACCOUNT);
allKeys.add(CategoryKey.CATEGORY_SYSTEM);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
// DO NOT REMOVE ANYTHING ABOVE
- assertThat(allKeys.size()).isEqualTo(13);
+ assertThat(allKeys.size()).isEqualTo(14);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b777d41..06d00be 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -45,8 +45,8 @@
import com.android.ims.ImsConfig;
import com.android.internal.content.PackageHelper;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
@@ -2617,9 +2617,9 @@
loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type);
// Set the preferred cdma subscription source to target desired value or default
- // value defined in CdmaSubscriptionSourceManager
+ // value defined in Phone
type = SystemProperties.getInt("ro.telephony.default_cdma_sub",
- CdmaSubscriptionSourceManager.PREFERRED_CDMA_SUBSCRIPTION);
+ Phone.PREFERRED_CDMA_SUBSCRIPTION);
loadSetting(stmt, Settings.Global.CDMA_SUBSCRIPTION_MODE, type);
loadIntegerSetting(stmt, Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java
index 4a5d8b4..2d794fb 100644
--- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java
+++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/ColorExtractor.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.VisibleForTesting;
+import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -41,15 +42,12 @@
private static final String TAG = "ColorExtractor";
- @VisibleForTesting
- static final int FALLBACK_COLOR = 0xff83888d;
+ public static final int FALLBACK_COLOR = 0xff83888d;
private int mMainFallbackColor = FALLBACK_COLOR;
private int mSecondaryFallbackColor = FALLBACK_COLOR;
private final SparseArray<GradientColors[]> mGradientColors;
private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners;
- // Colors to return when the wallpaper isn't visible
- private final GradientColors mWpHiddenColors;
private final Context mContext;
private final ExtractionType mExtractionType;
@@ -60,9 +58,6 @@
@VisibleForTesting
public ColorExtractor(Context context, ExtractionType extractionType) {
mContext = context;
- mWpHiddenColors = new GradientColors();
- mWpHiddenColors.setMainColor(FALLBACK_COLOR);
- mWpHiddenColors.setSecondaryColor(FALLBACK_COLOR);
mExtractionType = extractionType;
mGradientColors = new SparseArray<>();
@@ -123,7 +118,6 @@
if (which != WallpaperManager.FLAG_LOCK && which != WallpaperManager.FLAG_SYSTEM) {
throw new IllegalArgumentException("which should be FLAG_SYSTEM or FLAG_NORMAL");
}
-
return mGradientColors.get(which)[type];
}
@@ -134,7 +128,6 @@
GradientColors[] lockColors = mGradientColors.get(WallpaperManager.FLAG_LOCK);
extractInto(colors, lockColors[TYPE_NORMAL], lockColors[TYPE_DARK],
lockColors[TYPE_EXTRA_DARK]);
-
changed = true;
}
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
@@ -149,7 +142,7 @@
}
}
- private void triggerColorsChanged(int which) {
+ protected void triggerColorsChanged(int which) {
for (OnColorsChangedListener listener: mOnColorsChangedListeners) {
listener.onColorsChanged(this, which);
}
@@ -258,4 +251,4 @@
public interface OnColorsChangedListener {
void onColorsChanged(ColorExtractor colorExtractor, int which);
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/ColorExtractorTest.java b/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/ColorExtractorTest.java
index fd698d0..b5f4a8c 100644
--- a/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/ColorExtractorTest.java
+++ b/packages/SystemUI/colorextraction/tests/src/com/google/android/colorextraction/ColorExtractorTest.java
@@ -39,7 +39,7 @@
import org.junit.runner.RunWith;
/**
- * Tests tonal palette generation.
+ * Tests color extraction generation.
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -101,14 +101,12 @@
};
ColorExtractor extractor = new ColorExtractor(mContext, type);
- assertEquals("Extracted colors not being used!",
- extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_NORMAL),
- colorsExpectedNormal);
- assertEquals("Extracted colors not being used!",
- extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_DARK),
- colorsExpectedDark);
- assertEquals("Extracted colors not being used!",
- extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_EXTRA_DARK),
- colorsExpectedExtraDark);
+ GradientColors colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM,
+ ColorExtractor.TYPE_NORMAL);
+ assertEquals("Extracted colors not being used!", colors, colorsExpectedNormal);
+ colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_DARK);
+ assertEquals("Extracted colors not being used!", colors, colorsExpectedDark);
+ colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_EXTRA_DARK);
+ assertEquals("Extracted colors not being used!", colors, colorsExpectedExtraDark);
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java
new file mode 100644
index 0000000..3ca5690
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DozeServicePlugin.java
@@ -0,0 +1,21 @@
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+@ProvidesInterface(action = DozeServicePlugin.ACTION, version = DozeServicePlugin.VERSION)
+public interface DozeServicePlugin extends Plugin {
+ String ACTION = "com.android.systemui.action.PLUGIN_DOZE";
+ int VERSION = 1;
+
+ public interface RequestDoze {
+ void onRequestShowDoze();
+
+ void onRequestHideDoze();
+ }
+
+ void onDreamingStarted();
+
+ void onDreamingStopped();
+
+ void setDozeRequester(RequestDoze requester);
+}
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 9076199..18ffd0f 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -16,12 +16,12 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/volume_dialog"
- android:layout_width="@dimen/volume_dialog_panel_width"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
- android:layout_gravity="center_vertical|end"
+ android:background="@drawable/volume_dialog_background"
android:paddingTop="@dimen/volume_dialog_padding_top"
- android:translationZ="8dp" >
+ android:translationZ="4dp" >
<LinearLayout
android:id="@+id/volume_dialog_content"
@@ -57,7 +57,6 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:visibility="gone"
android:textAppearance="@style/TextAppearance.Volume.Header" />
<com.android.keyguard.AlphaOptimizedImageButton
xmlns:android="http://schemas.android.com/apk/res/android"
diff --git a/packages/SystemUI/res/layout/volume_dialog_wrapped.xml b/packages/SystemUI/res/layout/volume_dialog_wrapped.xml
deleted file mode 100644
index 57489fd..0000000
--- a/packages/SystemUI/res/layout/volume_dialog_wrapped.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.android.systemui.HardwareUiLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="@dimen/top_padding"
- android:layout_marginBottom="@dimen/bottom_padding">
-
- <include layout="@layout/volume_dialog"/>
-
-</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d3cbe4a..81ca230 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -262,6 +262,9 @@
<!-- Doze: alpha to apply to small icons when dozing -->
<integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff -->
+ <!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
+ <bool name="doze_double_tap_reports_touch_coordinates">false</bool>
+
<!-- Hotspot tile: number of days to show after feature is used. -->
<integer name="days_to_show_hotspot_tile">30</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index fc9e585..e3a84d3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -216,6 +216,8 @@
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
+ <dimen name="volume_dialog_panel_width">@dimen/standard_notification_panel_width</dimen>
+
<!-- Gravity for the notification panel -->
<integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
@@ -800,7 +802,6 @@
<dimen name="hwui_edge_margin">16dp</dimen>
- <dimen name="volume_dialog_panel_width">315dp</dimen>
<dimen name="global_actions_panel_width">125dp</dimen>
<dimen name="global_actions_top_padding">100dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
index 6a86bb2..38811ac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
@@ -21,6 +21,7 @@
import android.view.View;
import android.widget.Button;
import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionInfo;
import android.telephony.euicc.EuiccManager;
import java.lang.ref.WeakReference;
@@ -58,8 +59,11 @@
public static boolean isEsimLocked(Context context, int subId) {
EuiccManager euiccManager =
(EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
- return euiccManager.isEnabled()
- && SubscriptionManager.from(context).getActiveSubscriptionInfo(subId).isEmbedded();
+ if (!euiccManager.isEnabled()) {
+ return false;
+ }
+ SubscriptionInfo sub = SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
+ return sub != null && sub.isEmbedded();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 73a2a43..1b694b3 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -28,6 +28,7 @@
import com.android.internal.util.Preconditions;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.PluginDependencyProvider;
@@ -38,9 +39,9 @@
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
-import com.android.systemui.statusbar.phone.StatusBarWindowManager;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
+import com.android.systemui.statusbar.phone.StatusBarWindowManager;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -77,7 +78,6 @@
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
-import com.android.systemui.tuner.TunablePadding;
import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerServiceImpl;
@@ -86,8 +86,6 @@
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.volume.VolumeDialogControllerImpl;
-import com.google.android.colorextraction.ColorExtractor;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
@@ -109,6 +107,7 @@
* services, registered receivers, etc.
*/
public class Dependency extends SystemUI {
+ private static final String TAG = "Dependency";
/**
* Key for getting a background Looper for background work.
@@ -268,7 +267,7 @@
mProviders.put(AccessibilityManagerWrapper.class,
() -> new AccessibilityManagerWrapper(mContext));
- mProviders.put(ColorExtractor.class, () -> new ColorExtractor(mContext));
+ mProviders.put(SysuiColorExtractor.class, () -> new SysuiColorExtractor(mContext));
mProviders.put(TunablePaddingService.class, () -> new TunablePaddingService());
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
new file mode 100644
index 0000000..5f393d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.colorextraction;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.IWallpaperVisibilityListener;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import com.google.android.colorextraction.ColorExtractor;
+import com.google.android.colorextraction.types.ExtractionType;
+import com.google.android.colorextraction.types.Tonal;
+
+/**
+ * ColorExtractor aware of wallpaper visibility
+ */
+public class SysuiColorExtractor extends ColorExtractor {
+ private static final String TAG = "SysuiColorExtractor";
+ private boolean mWallpaperVisible;
+ // Colors to return when the wallpaper isn't visible
+ private final GradientColors mWpHiddenColors;
+
+ public SysuiColorExtractor(Context context) {
+ this(context, new Tonal(), true);
+ }
+
+ @VisibleForTesting
+ public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) {
+ super(context, type);
+
+ mWpHiddenColors = new GradientColors();
+ mWpHiddenColors.setMainColor(FALLBACK_COLOR);
+ mWpHiddenColors.setSecondaryColor(FALLBACK_COLOR);
+
+ if (registerVisibility) {
+ try {
+ IWindowManager windowManagerService = WindowManagerGlobal.getWindowManagerService();
+ Handler handler = Handler.getMain();
+ boolean visible = windowManagerService.registerWallpaperVisibilityListener(
+ new IWallpaperVisibilityListener.Stub() {
+ @Override
+ public void onWallpaperVisibilityChanged(boolean newVisibility,
+ int displayId) throws RemoteException {
+ handler.post(() -> setWallpaperVisible(newVisibility));
+ }
+ }, Display.DEFAULT_DISPLAY);
+ setWallpaperVisible(visible);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can't listen to wallpaper visibility changes", e);
+ }
+ }
+ }
+
+ /**
+ * Get TYPE_NORMAL colors when wallpaper is visible, or fallback otherwise.
+ *
+ * @param which FLAG_LOCK or FLAG_SYSTEM
+ * @return colors
+ */
+ @Override
+ public GradientColors getColors(int which) {
+ return getColors(which, TYPE_NORMAL);
+ }
+
+ /**
+ * Wallpaper colors when the wallpaper is visible, fallback otherwise.
+ *
+ * @param which FLAG_LOCK or FLAG_SYSTEM
+ * @param type TYPE_NORMAL, TYPE_DARK or TYPE_EXTRA_DARK
+ * @return colors
+ */
+ @Override
+ public GradientColors getColors(int which, int type) {
+ return getColors(which, type, false /* ignoreVisibility */);
+ }
+
+ /**
+ * Get TYPE_NORMAL colors, possibly ignoring wallpaper visibility.
+ *
+ * @param which FLAG_LOCK or FLAG_SYSTEM
+ * @param ignoreWallpaperVisibility whether you want fallback colors or not if the wallpaper
+ * isn't visible
+ * @return
+ */
+ public GradientColors getColors(int which, boolean ignoreWallpaperVisibility) {
+ return getColors(which, TYPE_NORMAL, ignoreWallpaperVisibility);
+ }
+
+ /**
+ *
+ * @param which FLAG_LOCK or FLAG_SYSTEM
+ * @param type TYPE_NORMAL, TYPE_DARK or TYPE_EXTRA_DARK
+ * @param ignoreWallpaperVisibility true if true wallpaper colors should be returning
+ * if it's visible or not
+ * @return colors
+ */
+ public GradientColors getColors(int which, int type, boolean ignoreWallpaperVisibility) {
+ if (mWallpaperVisible || ignoreWallpaperVisibility) {
+ return super.getColors(which, type);
+ } else {
+ return mWpHiddenColors;
+ }
+ }
+
+ @VisibleForTesting
+ void setWallpaperVisible(boolean visible) {
+ if (mWallpaperVisible != visible) {
+ mWallpaperVisible = visible;
+ triggerColorsChanged(WallpaperManager.FLAG_SYSTEM);
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 3e424d0..5aaa6c7 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -38,6 +38,8 @@
void setAnimateWakeup(boolean animateWakeup);
+ void onDoubleTap(float x, float y);
+
interface Callback {
default void onNotificationHeadsUp() {}
default void onPowerSaveChanged(boolean active) {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 73f5222..23da716 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -81,17 +81,18 @@
mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
null /* setting */,
dozeParameters.getPulseOnSigMotion(),
- DozeLog.PULSE_REASON_SENSOR_SIGMOTION),
+ DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */),
mPickupSensor = new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
Settings.Secure.DOZE_PULSE_ON_PICK_UP,
config.pulseOnPickupAvailable(),
- DozeLog.PULSE_REASON_SENSOR_PICKUP),
+ DozeLog.PULSE_REASON_SENSOR_PICKUP, false /* touchCoords */),
new TriggerSensor(
findSensorWithType(config.doubleTapSensorType()),
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
true /* configured */,
- DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
+ DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP,
+ dozeParameters.doubleTapReportsTouchCoordinates())
};
mProxSensor = new ProxSensor();
@@ -207,16 +208,19 @@
final boolean mConfigured;
final int mPulseReason;
final String mSetting;
+ final boolean mReportsTouchCoordinates;
private boolean mRequested;
private boolean mRegistered;
private boolean mDisabled;
- public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason) {
+ public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
+ boolean reportsTouchCoordinates) {
mSensor = sensor;
mSetting = setting;
mConfigured = configured;
mPulseReason = pulseReason;
+ mReportsTouchCoordinates = reportsTouchCoordinates;
}
public void setListening(boolean listen) {
@@ -276,7 +280,13 @@
}
mRegistered = false;
- mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck);
+ float screenX = -1;
+ float screenY = -1;
+ if (mReportsTouchCoordinates && event.values.length >= 2) {
+ screenX = event.values[0];
+ screenY = event.values[1];
+ }
+ mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY);
updateListener(); // reregister, this sensor only fires once
}));
}
@@ -309,7 +319,12 @@
* Called when a sensor requests a pulse
* @param pulseReason Requesting sensor, e.g. {@link DozeLog#PULSE_REASON_SENSOR_PICKUP}
* @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity.
+ * @param screenX the location on the screen where the sensor fired or -1
+ * if the sensor doesn't support reporting screen locations.
+ * @param screenY the location on the screen where the sensor fired or -1
+ * if the sensor doesn't support reporting screen locations.
*/
- void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck);
+ void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck,
+ float screenX, float screenY);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 3271caf..d9fb087 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -16,23 +16,27 @@
package com.android.systemui.doze;
+import android.content.Context;
import android.os.PowerManager;
import android.os.SystemClock;
import android.service.dreams.DreamService;
import android.util.Log;
import com.android.systemui.Dependency;
-import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.DozeServicePlugin;
import com.android.systemui.plugins.PluginManager;
-
+import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;
+import com.android.systemui.plugins.PluginListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-public class DozeService extends DreamService implements DozeMachine.Service {
+public class DozeService extends DreamService
+ implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private DozeMachine mDozeMachine;
+ private DozeServicePlugin mDozePlugin;
public DozeService() {
setDebug(DEBUG);
@@ -48,23 +52,44 @@
finish();
return;
}
-
+ Dependency.get(PluginManager.class).addPluginListener(this,
+ DozeServicePlugin.class, false /* Allow multiple */);
mDozeMachine = new DozeFactory().assembleMachine(this);
}
@Override
+ public void onPluginConnected(DozeServicePlugin plugin, Context pluginContext) {
+ mDozePlugin = plugin;
+ mDozePlugin.setDozeRequester(this);
+ }
+
+ @Override
+ public void onPluginDisconnected(DozeServicePlugin plugin) {
+ if (mDozePlugin != null) {
+ mDozePlugin.onDreamingStopped();
+ mDozePlugin = null;
+ }
+ }
+
+ @Override
public void onDreamingStarted() {
super.onDreamingStarted();
mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
startDozing();
setDozeScreenBrightness(getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze));
+ if (mDozePlugin != null) {
+ mDozePlugin.onDreamingStarted();
+ }
}
@Override
public void onDreamingStopped() {
super.onDreamingStopped();
mDozeMachine.requestState(DozeMachine.State.FINISH);
+ if (mDozePlugin != null) {
+ mDozePlugin.onDreamingStopped();
+ }
}
@Override
@@ -79,4 +104,18 @@
PowerManager pm = getSystemService(PowerManager.class);
pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
}
+
+ @Override
+ public void onRequestShowDoze() {
+ if (mDozeMachine != null) {
+ mDozeMachine.requestState(DozeMachine.State.DOZE_AOD);
+ }
+ }
+
+ @Override
+ public void onRequestHideDoze() {
+ if (mDozeMachine != null) {
+ mDozeMachine.requestState(DozeMachine.State.DOZE);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 693a690..ae936db 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -98,12 +98,14 @@
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
}
- private void onSensor(int pulseReason, boolean sensorPerformedProxCheck) {
+ private void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
+ float screenX, float screenY) {
boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
if (isDoubleTap) {
+ mDozeHost.onDoubleTap(screenX, screenY);
mMachine.wakeUp();
} else {
mDozeHost.extendPulse();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index e8dcf6c..80a6418 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -25,6 +25,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.HardwareUiLayout;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.volume.VolumeDialogImpl;
@@ -1227,7 +1228,7 @@
mClickListener = clickListener;
mLongClickListener = longClickListener;
mGradientDrawable = new GradientDrawable(mContext);
- mColorExtractor = Dependency.get(ColorExtractor.class);
+ mColorExtractor = Dependency.get(SysuiColorExtractor.class);
// Window initialization
Window window = getWindow();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
index eaf715f..5b3ec08 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/CellTileView.java
@@ -35,9 +35,7 @@
public CellTileView(Context context) {
super(context);
mSignalDrawable = new SignalDrawable(mContext);
- float dark = Utils.getColorAttr(context, android.R.attr.colorForeground) == 0xff000000
- ? 1 : 0;
- mSignalDrawable.setDarkIntensity(dark);
+ mSignalDrawable.setDarkIntensity(isDark(mContext));
mSignalDrawable.setIntrinsicSize(context.getResources().getDimensionPixelSize(
R.dimen.qs_tile_icon_size));
}
@@ -50,6 +48,10 @@
}
}
+ private static int isDark(Context context) {
+ return Utils.getColorAttr(context, android.R.attr.colorForeground) == 0xff000000 ? 1 : 0;
+ }
+
public static class SignalIcon extends Icon {
private final int mState;
@@ -64,7 +66,11 @@
@Override
public Drawable getDrawable(Context context) {
- return null;
+ //TODO: Not the optimal solution to create this drawable
+ SignalDrawable d = new SignalDrawable(context);
+ d.setDarkIntensity(isDark(context));
+ d.setLevel(getState());
+ return d;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index f124e86..697db5f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -73,6 +73,7 @@
private int mOpenY;
private boolean mAnimatingOpen;
private boolean mSwitchState;
+ private View mFooter;
public QSDetail(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -116,9 +117,10 @@
mDetailDoneButton.setOnClickListener(doneListener);
}
- public void setQsPanel(QSPanel panel, QuickStatusBarHeader header) {
+ public void setQsPanel(QSPanel panel, QuickStatusBarHeader header, View footer) {
mQsPanel = panel;
mHeader = header;
+ mFooter = footer;
mHeader.setCallback(mQsPanelCallback);
mQsPanel.setCallback(mQsPanelCallback);
}
@@ -214,6 +216,7 @@
mDetailAdapter = null;
listener = mTeardownDetailWhenDone;
mHeader.setVisibility(View.VISIBLE);
+ mFooter.setVisibility(View.VISIBLE);
mQsPanel.setGridContentVisibility(true);
mQsPanelCallback.onScanStateChanged(false);
}
@@ -345,6 +348,7 @@
if (mDetailAdapter != null) {
mQsPanel.setGridContentVisibility(false);
mHeader.setVisibility(View.INVISIBLE);
+ mFooter.setVisibility(View.INVISIBLE);
}
mAnimatingOpen = false;
checkPendingAnimations();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 3f00276a..90275c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -80,7 +80,7 @@
mFooter = view.findViewById(R.id.qs_footer);
mContainer = view.findViewById(id.quick_settings_container);
- mQSDetail.setQsPanel(mQSPanel, mHeader);
+ mQSDetail.setQsPanel(mQSPanel, mHeader, mFooter);
// If the quick settings row is not shown, then there is no need for the animation from
// the row to the full QS panel.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index d434f2f..56fca1f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -27,6 +27,7 @@
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.Log;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -244,8 +245,9 @@
mDialog = new SystemUIDialog(mContext);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
- View dialogView = LayoutInflater.from(mContext)
- .inflate(R.layout.quick_settings_footer_dialog, null, false);
+ View dialogView = LayoutInflater.from(
+ new ContextThemeWrapper(mContext, R.style.Theme_SystemUI_Dialog))
+ .inflate(R.layout.quick_settings_footer_dialog, null, false);
mDialog.setView(dialogView);
mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
index 603f66b..315a815 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
@@ -18,12 +18,14 @@
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.plugins.qs.QSTile.SlashState;
import com.android.systemui.qs.SlashDrawable;
public class SlashImageView extends ImageView {
- private SlashDrawable mSlash;
+ @VisibleForTesting
+ protected SlashDrawable mSlash;
public SlashImageView(Context context) {
super(context);
@@ -38,10 +40,13 @@
@Override
public void setImageDrawable(Drawable drawable) {
- if (mSlash != null) {
- mSlash.setDrawable(drawable);
- } else {
+ if (drawable == null) {
+ mSlash = null;
+ super.setImageDrawable(null);
+ } else if (mSlash == null) {
super.setImageDrawable(drawable);
+ } else {
+ mSlash.setDrawable(drawable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 703be27..36677a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -183,12 +183,6 @@
@Override
public void onBluetoothDevicesChanged() {
- mUiHandler.post(new Runnable() {
- @Override
- public void run() {
- mDetailAdapter.updateItems();
- }
- });
refreshState();
if (isShowingDetail()) {
mDetailAdapter.updateItems();
@@ -202,6 +196,9 @@
}
protected class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
+ // We probably won't ever have space in the UI for more than 20 devices, so don't
+ // get info for them.
+ private static final int MAX_DEVICES = 20;
private QSDetailItems mItems;
@Override
@@ -264,13 +261,14 @@
final Collection<CachedBluetoothDevice> devices = mController.getDevices();
if (devices != null) {
int connectedDevices = 0;
+ int count = 0;
for (CachedBluetoothDevice device : devices) {
- if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
+ if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item();
item.icon = R.drawable.ic_qs_bluetooth_on;
item.line1 = device.getName();
item.tag = device;
- int state = device.getMaxConnectionState();
+ int state = mController.getMaxConnectionState(device);
if (state == BluetoothProfile.STATE_CONNECTED) {
item.icon = R.drawable.ic_qs_bluetooth_connected;
item.line2 = mContext.getString(R.string.quick_settings_connected);
@@ -284,6 +282,9 @@
} else {
items.add(item);
}
+ if (++count == MAX_DEVICES) {
+ break;
+ }
}
}
mItems.setItems(items.toArray(new Item[items.size()]));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 319b463..d710244 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -46,6 +46,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -113,7 +114,7 @@
private final float mScrimAlpha;
private GradientDrawable mBackgroundScrim;
- private final ColorExtractor mColorExtractor;
+ private final SysuiColorExtractor mColorExtractor;
private Animator mBackgroundScrimAnimator;
private RecentsTransitionHelper mTransitionHelper;
@@ -146,7 +147,7 @@
mBackgroundScrim = new GradientDrawable(context);
mBackgroundScrim.setCallback(this);
mBackgroundScrim.setAlpha((int) (mScrimAlpha * 255));
- mColorExtractor = Dependency.get(ColorExtractor.class);
+ mColorExtractor = Dependency.get(SysuiColorExtractor.class);
LayoutInflater inflater = LayoutInflater.from(context);
if (RecentsDebugFlags.Static.EnableStackActionButton) {
@@ -829,17 +830,23 @@
}
@Override
- public void onColorsChanged(ColorExtractor extractor, int which) {
+ public void onColorsChanged(ColorExtractor colorExtractor, int which) {
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
- mBackgroundScrim.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM));
+ // Recents doesn't care about the wallpaper being visible or not, it always
+ // wants to scrim with wallpaper colors
+ mBackgroundScrim.setColors(
+ mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, true));
}
}
public void onStart() {
mColorExtractor.addOnColorsChangedListener(this);
+ // Getting system scrim colors ignoring wallpaper visibility since it should never be grey.
+ ColorExtractor.GradientColors systemColors = mColorExtractor.getColors(
+ WallpaperManager.FLAG_SYSTEM, true);
// We don't want to interpolate colors because we're defining the initial state.
// Gradient should be set/ready when you open "Recents".
- mBackgroundScrim.setColors(mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM), false);
+ mBackgroundScrim.setColors(systemColors, false);
}
public void onStop() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index d7e7abe..6b7397b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -157,6 +157,10 @@
return 2 * getPulseVisibleDuration();
}
+ public boolean doubleTapReportsTouchCoordinates() {
+ return mContext.getResources().getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
+ }
+
/**
* Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index f502bb5..bc278e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -36,6 +36,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.ScrimView;
@@ -78,7 +79,7 @@
private final View mHeadsUpScrim;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final ColorExtractor mColorExtractor;
+ private final SysuiColorExtractor mColorExtractor;
private ColorExtractor.GradientColors mLockColors;
private ColorExtractor.GradientColors mLockColorsDark;
private ColorExtractor.GradientColors mSystemColors;
@@ -131,15 +132,17 @@
mLightBarController = lightBarController;
mScrimBehindAlpha = context.getResources().getFloat(R.dimen.scrim_behind_alpha);
- mColorExtractor = Dependency.get(ColorExtractor.class);
+ mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
- mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK);
- mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM);
+ mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
+ ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */);
+ mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
+ ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */);
// Darker gradient for the top scrim (mScrimInFront)
mLockColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
- ColorExtractor.TYPE_DARK);
+ ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
mSystemColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
- ColorExtractor.TYPE_DARK);
+ ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
mNeedsDrawableColorUpdate = true;
updateHeadsUpScrim(false);
@@ -659,18 +662,18 @@
@Override
public void onColorsChanged(ColorExtractor colorExtractor, int which) {
if ((which & WallpaperManager.FLAG_LOCK) != 0) {
- mLockColors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK,
- ColorExtractor.TYPE_NORMAL);
- mLockColorsDark = colorExtractor.getColors(WallpaperManager.FLAG_LOCK,
- ColorExtractor.TYPE_DARK);
+ mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
+ ColorExtractor.TYPE_NORMAL, true /* ignoreVisibility */);
+ mLockColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
+ ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
mNeedsDrawableColorUpdate = true;
scheduleUpdate();
}
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
- mSystemColors = colorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
- ColorExtractor.TYPE_NORMAL);
- mSystemColorsDark = colorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
- ColorExtractor.TYPE_DARK);
+ mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
+ ColorExtractor.TYPE_NORMAL, mKeyguardShowing);
+ mSystemColorsDark = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
+ ColorExtractor.TYPE_DARK, mKeyguardShowing);
mNeedsDrawableColorUpdate = true;
scheduleUpdate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e8b6e07..c9d450d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -32,7 +32,6 @@
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
-import android.R.style;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
@@ -169,6 +168,7 @@
import com.android.systemui.assist.AssistManager;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.ExtensionFragmentListener;
@@ -303,7 +303,7 @@
private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
= "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
public static final String TAG = "StatusBar";
- public static final boolean DEBUG = true;
+ public static final boolean DEBUG = false;
public static final boolean SPEW = false;
public static final boolean DUMPTRUCK = true; // extra dumpsys info
public static final boolean DEBUG_GESTURES = false;
@@ -734,7 +734,7 @@
private HashMap<String, Entry> mPendingNotifications = new HashMap<>();
private boolean mClearAllEnabled;
@Nullable private View mAmbientIndicationContainer;
- private ColorExtractor mColorExtractor;
+ private SysuiColorExtractor mColorExtractor;
private ForegroundServiceController mForegroundServiceController;
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
@@ -781,7 +781,7 @@
mOverlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
- mColorExtractor = Dependency.get(ColorExtractor.class);
+ mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
@@ -4516,10 +4516,10 @@
// Ignore visibility since we calculate the theme based on the real colors,
// not the current state.
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- useDarkTheme = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK)
+ useDarkTheme = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true /* vis */)
.supportsDarkText();
} else {
- useDarkTheme = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM)
+ useDarkTheme = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, true /* vis */)
.supportsDarkText();
}
@@ -5325,6 +5325,37 @@
mAnimateWakeup = animateWakeup;
}
+ @Override
+ public void onDoubleTap(float screenX, float screenY) {
+ if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
+ && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
+ mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
+ float viewX = screenX - mTmpInt2[0];
+ float viewY = screenY - mTmpInt2[1];
+ if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
+ && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
+ dispatchDoubleTap(viewX, viewY);
+ }
+ }
+ }
+
+ public void dispatchDoubleTap(float viewX, float viewY) {
+ dispatchTap(mAmbientIndicationContainer, viewX, viewY);
+ dispatchTap(mAmbientIndicationContainer, viewX, viewY);
+ }
+
+ private void dispatchTap(View view, float x, float y) {
+ long now = SystemClock.elapsedRealtime();
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
+ }
+
+ private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
+ MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
+ view.dispatchTouchEvent(ev);
+ ev.recycle();
+ }
+
private boolean shouldAnimateWakeup() {
return mAnimateWakeup;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index df30e20..9daa199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -37,6 +37,9 @@
void disconnect(CachedBluetoothDevice device);
boolean canConfigBluetooth();
+ int getMaxConnectionState(CachedBluetoothDevice device);
+ int getBondState(CachedBluetoothDevice device);
+
public interface Callback {
void onBluetoothStateChange(boolean enabled);
void onBluetoothDevicesChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 36d24b3..dc4b115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -18,6 +18,8 @@
import android.app.ActivityManager;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -33,8 +35,10 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.WeakHashMap;
public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
CachedBluetoothDevice.Callback {
@@ -44,18 +48,22 @@
private final LocalBluetoothManager mLocalBluetoothManager;
private final UserManager mUserManager;
private final int mCurrentUser;
+ private final WeakHashMap<CachedBluetoothDevice, ActuallyCachedState> mCachedState =
+ new WeakHashMap<>();
+ private final Handler mBgHandler;
private boolean mEnabled;
private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
private CachedBluetoothDevice mLastDevice;
- private final H mHandler = new H();
+ private final H mHandler = new H(Looper.getMainLooper());
private int mState;
public BluetoothControllerImpl(Context context, Looper bgLooper) {
mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class);
+ mBgHandler = new Handler(bgLooper);
if (mLocalBluetoothManager != null) {
- mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper));
+ mLocalBluetoothManager.getEventManager().setReceiverHandler(mBgHandler);
mLocalBluetoothManager.getEventManager().registerCallback(this);
onBluetoothStateChanged(
mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
@@ -106,6 +114,16 @@
}
@Override
+ public int getBondState(CachedBluetoothDevice device) {
+ return getCachedState(device).mBondState;
+ }
+
+ @Override
+ public int getMaxConnectionState(CachedBluetoothDevice device) {
+ return getCachedState(device).mMaxConnectionState;
+ }
+
+ @Override
public void addCallback(Callback cb) {
mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
@@ -225,12 +243,14 @@
@Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
+ mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+ mCachedState.remove(cachedDevice);
updateConnected();
mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
}
@@ -243,11 +263,44 @@
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+ mCachedState.remove(cachedDevice);
mLastDevice = cachedDevice;
updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
}
+ private ActuallyCachedState getCachedState(CachedBluetoothDevice device) {
+ ActuallyCachedState state = mCachedState.get(device);
+ if (state == null) {
+ state = new ActuallyCachedState(device, mHandler);
+ mBgHandler.post(state);
+ mCachedState.put(device, state);
+ return state;
+ }
+ return state;
+ }
+
+ private static class ActuallyCachedState implements Runnable {
+
+ private final WeakReference<CachedBluetoothDevice> mDevice;
+ private final Handler mUiHandler;
+ private int mBondState = BluetoothDevice.BOND_NONE;
+ private int mMaxConnectionState = BluetoothProfile.STATE_DISCONNECTED;
+
+ private ActuallyCachedState(CachedBluetoothDevice device, Handler uiHandler) {
+ mDevice = new WeakReference<>(device);
+ mUiHandler = uiHandler;
+ }
+
+ @Override
+ public void run() {
+ mBondState = mDevice.get().getBondState();
+ mMaxConnectionState = mDevice.get().getMaxConnectionState();
+ mUiHandler.removeMessages(H.MSG_PAIRED_DEVICES_CHANGED);
+ mUiHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
+ }
+ }
+
private final class H extends Handler {
private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>();
@@ -256,6 +309,10 @@
private static final int MSG_ADD_CALLBACK = 3;
private static final int MSG_REMOVE_CALLBACK = 4;
+ public H(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 1d3b533..e11b23e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -18,7 +18,6 @@
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.ObjectAnimator;
@@ -62,7 +61,6 @@
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.view.WindowManager;
@@ -77,7 +75,6 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.HardwareUiLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.VolumeDialogController;
@@ -103,8 +100,7 @@
*
* Methods ending in "H" must be called on the (ui) handler.
*/
-public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable,
- ColorExtractor.OnColorsChangedListener {
+public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
private static final String TAG = Util.logTag(VolumeDialogImpl.class);
public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
@@ -114,8 +110,6 @@
private final Context mContext;
private final H mHandler = new H();
- private final GradientDrawable mGradientDrawable;
- private final ColorExtractor mColorExtractor;
private VolumeDialogController mController;
private Window mWindow;
@@ -170,9 +164,6 @@
(AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
- mGradientDrawable = new GradientDrawable(mContext);
- mGradientDrawable.setAlpha((int) (ScrimController.GRADIENT_SCRIM_ALPHA * 255));
- mColorExtractor = Dependency.get(ColorExtractor.class);
}
public void init(int windowType, Callback callback) {
@@ -194,7 +185,6 @@
@Override
public void destroy() {
mController.removeCallback(mControllerCallbackH);
- mColorExtractor.removeOnColorsChangedListener(this);
}
private void initDialog() {
@@ -205,7 +195,7 @@
mShowing = false;
mWindow = mDialog.getWindow();
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
- mWindow.setBackgroundDrawable(mGradientDrawable);
+ mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
@@ -213,49 +203,55 @@
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
mDialog.setCanceledOnTouchOutside(true);
final Resources res = mContext.getResources();
+ final WindowManager.LayoutParams lp = mWindow.getAttributes();
+ lp.type = mWindowType;
+ lp.format = PixelFormat.TRANSLUCENT;
+ lp.setTitle(VolumeDialogImpl.class.getSimpleName());
+ lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+ lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top);
+ lp.gravity = Gravity.TOP;
+ lp.windowAnimations = -1;
+ mWindow.setAttributes(lp);
mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
- mDialog.setContentView(R.layout.volume_dialog_wrapped);
- mDialogView = mDialog.findViewById(R.id.volume_dialog);
- mDialogView.setOnHoverListener((v, event) -> {
- int action = event.getActionMasked();
- mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
- || (action == MotionEvent.ACTION_HOVER_MOVE);
- rescheduleTimeoutH();
- return true;
+ mDialog.setContentView(R.layout.volume_dialog);
+ mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
+ mDialogView.setOnHoverListener(new View.OnHoverListener() {
+ @Override
+ public boolean onHover(View v, MotionEvent event) {
+ int action = event.getActionMasked();
+ mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
+ || (action == MotionEvent.ACTION_HOVER_MOVE);
+ rescheduleTimeoutH();
+ return true;
+ }
});
-
- mColorExtractor.addOnColorsChangedListener(this);
- mGradientDrawable.setScreenSize(displaySize.x, displaySize.y);
- ColorExtractor.GradientColors colors = mColorExtractor.getColors(
- mKeyguard.isKeyguardLocked() ? WallpaperManager.FLAG_LOCK
- : WallpaperManager.FLAG_SYSTEM);
- mGradientDrawable.setColors(colors, false);
-
- mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
- mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
+ mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
+ mDialogRowsView = (ViewGroup) mDialogContentView.findViewById(R.id.volume_dialog_rows);
mExpanded = false;
- mExpandButton = mDialogView.findViewById(R.id.volume_expand_button);
+ mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
mExpandButton.setOnClickListener(mClickExpand);
mExpandButton.setVisibility(
AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE);
+ updateWindowWidthH();
updateExpandButtonH();
- mMotion = new VolumeDialogMotion(mDialog, (View) mDialogView.getParent(),
- mDialogContentView, mExpandButton, mGradientDrawable, animating -> {
- if (animating) return;
- if (mPendingStateChanged) {
- mHandler.sendEmptyMessage(H.STATE_CHANGED);
- mPendingStateChanged = false;
- }
- if (mPendingRecheckAll) {
- mHandler.sendEmptyMessage(H.RECHECK_ALL);
- mPendingRecheckAll = false;
+ mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton,
+ new VolumeDialogMotion.Callback() {
+ @Override
+ public void onAnimatingChanged(boolean animating) {
+ if (animating) return;
+ if (mPendingStateChanged) {
+ mHandler.sendEmptyMessage(H.STATE_CHANGED);
+ mPendingStateChanged = false;
+ }
+ if (mPendingRecheckAll) {
+ mHandler.sendEmptyMessage(H.RECHECK_ALL);
+ mPendingRecheckAll = false;
+ }
}
});
@@ -280,20 +276,11 @@
addExistingRows();
}
mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
- mZenFooter = mDialog.findViewById(R.id.volume_zen_footer);
+ mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
mZenFooter.init(mZenModeController);
- mZenPanel = mDialog.findViewById(R.id.tuner_zen_mode_panel);
+ mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
mZenPanel.init(mZenModeController);
mZenPanel.setCallback(mZenPanelCallback);
-
- final WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.width = MATCH_PARENT;
- lp.height = MATCH_PARENT;
- lp.type = mWindowType;
- lp.format = PixelFormat.TRANSLUCENT;
- lp.setTitle(VolumeDialogImpl.class.getSimpleName());
- lp.windowAnimations = -1;
- mWindow.setAttributes(lp);
}
@Override
@@ -307,6 +294,20 @@
return ColorStateList.valueOf(mContext.getColor(colorResId));
}
+ private void updateWindowWidthH() {
+ final ViewGroup.LayoutParams lp = mDialogView.getLayoutParams();
+ final DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+ if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels);
+ int w = dm.widthPixels;
+ final int max = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.volume_dialog_panel_width);
+ if (w > max) {
+ w = max;
+ }
+ lp.width = w;
+ mDialogView.setLayoutParams(lp);
+ }
+
public void setStreamImportant(int stream, boolean important) {
mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
}
@@ -547,8 +548,10 @@
}
private void updateDialogBottomMarginH() {
+ final long diff = System.currentTimeMillis() - mCollapseTime;
+ final boolean collapsing = mCollapseTime != 0 && diff < getConservativeCollapseDuration();
final ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams();
- final int bottomMargin =
+ final int bottomMargin = collapsing ? mDialogContentView.getHeight() :
mContext.getResources().getDimensionPixelSize(R.dimen.volume_dialog_margin_bottom);
if (bottomMargin != mlp.bottomMargin) {
if (D.BUG) Log.d(TAG, "bottomMargin " + mlp.bottomMargin + " -> " + bottomMargin);
@@ -578,7 +581,7 @@
TransitionManager.endTransitions(mDialogView);
final VolumeRow activeRow = getActiveRow();
if (!dismissing) {
- mWindow.setLayout(mWindow.getAttributes().width, MATCH_PARENT);
+ mWindow.setLayout(mWindow.getAttributes().width, ViewGroup.LayoutParams.MATCH_PARENT);
TransitionManager.beginDelayedTransition(mDialogView, getTransistion());
}
updateRowsH(activeRow);
@@ -640,7 +643,7 @@
final boolean isActive = row == activeRow;
final boolean shouldBeVisible = shouldBeVisibleH(row, isActive);
Util.setVisOrGone(row.view, shouldBeVisible);
- Util.setVisOrGone(row.header, shouldBeVisible && mExpanded);
+ Util.setVisOrGone(row.header, shouldBeVisible);
if (row.view.isShown()) {
updateVolumeRowSliderTintH(row, isActive);
}
@@ -697,18 +700,12 @@
final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
&& (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
&& !mZenPanel.isEditing();
-
- if (wasVisible != visible) {
- mZenFooter.update();
- if (visible) {
- HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter);
- } else {
- mHandler.postDelayed(() ->
- HardwareUiLayout.get(mZenFooter).setDivisionView(mZenFooter),
- mExpandButtonAnimationDuration);
- }
- Util.setVisOrGone(mZenFooter, visible);
+ TransitionManager.beginDelayedTransition(mDialogView, getTransistion());
+ if (wasVisible != visible && !visible) {
+ prepareForCollapse();
}
+ Util.setVisOrGone(mZenFooter, visible);
+ mZenFooter.update();
final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
final boolean fullVisible = mShowFullZen && !visible;
@@ -968,7 +965,8 @@
@Override
public void onTransitionEnd(Transition transition) {
- mWindow.setLayout(MATCH_PARENT, MATCH_PARENT);
+ mWindow.setLayout(
+ mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
@@ -977,7 +975,8 @@
@Override
public void onTransitionPause(Transition transition) {
- mWindow.setLayout(MATCH_PARENT, MATCH_PARENT);
+ mWindow.setLayout(
+ mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
@@ -1029,6 +1028,7 @@
initDialog();
mDensity = density;
}
+ updateWindowWidthH();
mConfigurableTexts.update();
mZenFooter.onConfigurationChanged();
}
@@ -1084,26 +1084,10 @@
if (mExpandButtonAnimationRunning) return;
final boolean newExpand = !mExpanded;
Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand);
- if (!newExpand) {
- HardwareUiLayout.get(mDialogContentView).setCollapse();
- }
updateExpandedH(newExpand, false /* dismissing */);
}
};
- @Override
- public void onColorsChanged(ColorExtractor extractor, int which) {
- if (mKeyguard.isKeyguardLocked()) {
- if ((WallpaperManager.FLAG_LOCK & which) != 0) {
- mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_LOCK));
- }
- } else {
- if ((WallpaperManager.FLAG_SYSTEM & which) != 0) {
- mGradientDrawable.setColors(extractor.getColors(WallpaperManager.FLAG_SYSTEM));
- }
- }
- }
-
private final class H extends Handler {
private static final int SHOW = 1;
private static final int DISMISS = 2;
@@ -1175,8 +1159,8 @@
event.setPackageName(mContext.getPackageName());
ViewGroup.LayoutParams params = getWindow().getAttributes();
- boolean isFullScreen = (params.width == MATCH_PARENT) &&
- (params.height == MATCH_PARENT);
+ boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
+ (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
event.setFullScreen(isFullScreen);
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
index 2df2227..01d31e2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.systemui.volume;
import android.animation.Animator;
@@ -41,10 +42,8 @@
private final View mDialogView;
private final ViewGroup mContents; // volume rows + zen footer
private final View mChevron;
- private final Drawable mBackground;
private final Handler mHandler = new Handler();
private final Callback mCallback;
- private final int mBackgroundTargetAlpha;
private boolean mAnimating; // show or dismiss animation is running
private boolean mShowing; // show animation is running
@@ -53,14 +52,12 @@
private ValueAnimator mContentsPositionAnimator;
public VolumeDialogMotion(Dialog dialog, View dialogView, ViewGroup contents, View chevron,
- Drawable background, Callback callback) {
+ Callback callback) {
mDialog = dialog;
mDialogView = dialogView;
mContents = contents;
mChevron = chevron;
mCallback = callback;
- mBackground = background;
- mBackgroundTargetAlpha = mBackground.getAlpha();
mDialog.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
@@ -71,9 +68,8 @@
@Override
public void onShow(DialogInterface dialog) {
if (D.BUG) Log.d(TAG, "mDialog.onShow");
- final int w = mDialogView.getWidth() / 4;
- mDialogView.setTranslationX(w);
- mBackground.setAlpha(0);
+ final int h = mDialogView.getHeight();
+ mDialogView.setTranslationY(-h);
startShowAnimation();
}
});
@@ -122,7 +118,7 @@
}
private int chevronDistance() {
- return 0;
+ return mChevron.getHeight() / 6;
}
private int chevronPosY() {
@@ -133,29 +129,26 @@
private void startShowAnimation() {
if (D.BUG) Log.d(TAG, "startShowAnimation");
mDialogView.animate()
- .translationX(0)
.translationY(0)
- .alpha(1)
.setDuration(scaledDuration(300))
.setInterpolator(new LogDecelerateInterpolator())
.setListener(null)
.setUpdateListener(animation -> {
- mBackground.setAlpha(
- (int) (animation.getAnimatedFraction() * mBackgroundTargetAlpha));
if (mChevronPositionAnimator != null) {
final float v = (Float) mChevronPositionAnimator.getAnimatedValue();
if (mChevronPositionAnimator == null) return;
// reposition chevron
final int posY = chevronPosY();
+ mChevron.setTranslationY(posY + v + -mDialogView.getTranslationY());
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
- mBackground.setAlpha(mBackgroundTargetAlpha);
if (mChevronPositionAnimator == null) return;
// reposition chevron
final int posY = chevronPosY();
+ mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
}
})
.start();
@@ -171,13 +164,19 @@
if (D.BUG) Log.d(TAG, "show.onAnimationEnd");
setShowing(false);
}
-
@Override
public void onAnimationCancel(Animator animation) {
if (D.BUG) Log.d(TAG, "show.onAnimationCancel");
mCancelled = true;
}
});
+ mContentsPositionAnimator.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float v = (Float) animation.getAnimatedValue();
+ mContents.setTranslationY(v + -mDialogView.getTranslationY());
+ }
+ });
mContentsPositionAnimator.setInterpolator(new LogDecelerateInterpolator());
mContentsPositionAnimator.start();
@@ -219,30 +218,34 @@
setShowing(false);
}
mDialogView.animate()
- .translationX(mDialogView.getWidth() / 4)
- .alpha(0)
+ .translationY(-mDialogView.getHeight())
.setDuration(scaledDuration(250))
.setInterpolator(new LogAccelerateInterpolator())
- .setUpdateListener(animation -> {
- final float v = 1 - mChevronPositionAnimator.getAnimatedFraction();
- mBackground.setAlpha((int) (v * mBackgroundTargetAlpha));
+ .setUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mContents.setTranslationY(-mDialogView.getTranslationY());
+ final int posY = chevronPosY();
+ mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
+ }
})
.setListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
-
@Override
public void onAnimationEnd(Animator animation) {
if (mCancelled) return;
if (D.BUG) Log.d(TAG, "dismiss.onAnimationEnd");
- mHandler.postDelayed(() -> {
- if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
- mDialog.dismiss();
- onComplete.run();
- setDismissing(false);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
+ mDialog.dismiss();
+ onComplete.run();
+ setDismissing(false);
+ }
}, PRE_DISMISS_DELAY);
}
-
@Override
public void onAnimationCancel(Animator animation) {
if (D.BUG) Log.d(TAG, "dismiss.onAnimationCancel");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
new file mode 100644
index 0000000..7ed1e2c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.colorextraction;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
+import android.graphics.Color;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
+
+import com.android.systemui.SysuiTestCase;
+
+import com.google.android.colorextraction.ColorExtractor;
+import com.google.android.colorextraction.types.Tonal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests color extraction generation.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SysuiColorExtractorTests extends SysuiTestCase {
+
+ private static int[] sWhich = new int[]{
+ WallpaperManager.FLAG_SYSTEM,
+ WallpaperManager.FLAG_LOCK};
+ private static int[] sTypes = new int[]{
+ ColorExtractor.TYPE_NORMAL,
+ ColorExtractor.TYPE_DARK,
+ ColorExtractor.TYPE_EXTRA_DARK};
+
+ @Test
+ public void getColors_usesGreyIfWallpaperNotVisible() {
+ ColorExtractor.GradientColors fallbackColors = new ColorExtractor.GradientColors();
+ fallbackColors.setMainColor(ColorExtractor.FALLBACK_COLOR);
+ fallbackColors.setSecondaryColor(ColorExtractor.FALLBACK_COLOR);
+
+ SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(), new Tonal(), false);
+ simulateEvent(extractor);
+ extractor.setWallpaperVisible(false);
+
+ for (int which : sWhich) {
+ for (int type : sTypes) {
+ assertEquals("Not using fallback!", extractor.getColors(which, type),
+ fallbackColors);
+ }
+ }
+ }
+
+ @Test
+ public void getColors_doesntUseFallbackIfVisible() {
+ ColorExtractor.GradientColors colors = new ColorExtractor.GradientColors();
+ colors.setMainColor(Color.RED);
+ colors.setSecondaryColor(Color.RED);
+
+ SysuiColorExtractor extractor = new SysuiColorExtractor(getContext(),
+ (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
+ outGradientColorsExtraDark) -> {
+ outGradientColorsNormal.set(colors);
+ outGradientColorsDark.set(colors);
+ outGradientColorsExtraDark.set(colors);
+ return true;
+ }, false);
+ simulateEvent(extractor);
+ extractor.setWallpaperVisible(true);
+
+ for (int which : sWhich) {
+ for (int type : sTypes) {
+ assertEquals("Not using extracted colors!",
+ extractor.getColors(which, type), colors);
+ }
+ }
+ }
+
+ private void simulateEvent(SysuiColorExtractor extractor) {
+ // Let's fake a color event
+ List<Pair<Color, Integer>> dummyColors = new ArrayList<>();
+ dummyColors.add(new Pair<>(Color.valueOf(Color.BLACK), 1));
+ extractor.onColorsChanged(new WallpaperColors(dummyColors),
+ WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index 56c07f9..2345110 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -28,6 +28,8 @@
boolean pulseExtended;
boolean animateWakeup;
boolean dozing;
+ float doubleTapX;
+ float doubleTapY;
@Override
public void addCallback(@NonNull Callback callback) {
@@ -88,4 +90,10 @@
public void setAnimateWakeup(boolean animateWakeup) {
this.animateWakeup = animateWakeup;
}
+
+ @Override
+ public void onDoubleTap(float x, float y) {
+ doubleTapX = y;
+ doubleTapY = y;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
index 59eca50..6a85511 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
@@ -23,6 +23,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import org.junit.After;
+import org.junit.Ignore;
import android.support.test.filters.SmallTest;
import android.support.test.filters.FlakyTest;
import android.testing.AndroidTestingRunner;
@@ -38,8 +40,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
-import org.junit.After;
-import org.junit.Ignore;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,7 +67,7 @@
mQsDetail = (QSDetail) LayoutInflater.from(mContext).inflate(R.layout.qs_detail, null);
mQsPanel = mock(QSPanel.class);
mQuickHeader = mock(QuickStatusBarHeader.class);
- mQsDetail.setQsPanel(mQsPanel, mQuickHeader);
+ mQsDetail.setQsPanel(mQsPanel, mQuickHeader, mock(View.class));
mMockDetailAdapter = mock(DetailAdapter.class);
when(mMockDetailAdapter.createDetailView(any(), any(), any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java
new file mode 100644
index 0000000..aef584f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/SlashImageViewTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.qs.QSTile.SlashState;
+import com.android.systemui.qs.tileimpl.SlashImageView;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class SlashImageViewTest extends SysuiTestCase {
+ private TestableSlashImageView mSlashView;
+
+ @Test
+ public void testSetSlashStateCreatesSlashDrawable() {
+ SlashState mockState = mock(SlashState.class);
+ Drawable mockDrawable = mock(Drawable.class);
+ mSlashView = new TestableSlashImageView(mContext);
+ assertTrue(mSlashView.getSlashDrawable() == null);
+
+ mSlashView.setImageDrawable(mockDrawable);
+ mSlashView.setState(mockState);
+
+ assertTrue(mSlashView.getSlashDrawable() != null);
+ }
+
+ @Test
+ public void testSetNullDrawableRemovesSlashDrawable() {
+ SlashState mockState = mock(SlashState.class);
+ Drawable mockDrawable = mock(Drawable.class);
+
+ mSlashView = new TestableSlashImageView(mContext);
+ mSlashView.setImageDrawable(mockDrawable);
+ mSlashView.setState(mockState);
+ mSlashView.setImageDrawable(null);
+
+ assertTrue(mSlashView.getSlashDrawable() == null);
+ }
+
+ // Expose getSlashDrawable
+ private static class TestableSlashImageView extends SlashImageView {
+ TestableSlashImageView(Context c) {
+ super(c);
+ }
+
+ private SlashDrawable getSlashDrawable() {
+ return mSlash;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 2eb9560..4cc8bca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -14,16 +14,21 @@
package com.android.systemui.statusbar.policy;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.Log;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -80,4 +85,56 @@
BluetoothAdapter.STATE_DISCONNECTED);
assertTrue(mBluetoothControllerImpl.isBluetoothConnected());
}
+
+ @Test
+ public void testDefaultConnectionState() {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
+ assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+ }
+
+ @Test
+ public void testAsyncBondState() throws Exception {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
+ mBluetoothControllerImpl.addCallback(callback);
+
+ // Grab the main looper, we'll need it later.
+ TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
+
+ // Trigger the state getting.
+ assertEquals(BluetoothDevice.BOND_NONE, mBluetoothControllerImpl.getBondState(device));
+
+ mTestableLooper.processMessages(1);
+ mainLooper.processAllMessages();
+
+ assertEquals(BluetoothDevice.BOND_BONDED, mBluetoothControllerImpl.getBondState(device));
+ verify(callback).onBluetoothDevicesChanged();
+ mainLooper.destroy();
+ }
+
+ @Test
+ public void testAsyncConnectionState() throws Exception {
+ CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ when(device.getMaxConnectionState()).thenReturn(BluetoothProfile.STATE_CONNECTED);
+ BluetoothController.Callback callback = mock(BluetoothController.Callback.class);
+ mBluetoothControllerImpl.addCallback(callback);
+
+ // Grab the main looper, we'll need it later.
+ TestableLooper mainLooper = new TestableLooper(Looper.getMainLooper());
+
+ // Trigger the state getting.
+ assertEquals(BluetoothProfile.STATE_DISCONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+
+ mTestableLooper.processMessages(1);
+ mainLooper.processAllMessages();
+
+ assertEquals(BluetoothProfile.STATE_CONNECTED,
+ mBluetoothControllerImpl.getMaxConnectionState(device));
+ verify(callback).onBluetoothDevicesChanged();
+ mainLooper.destroy();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
index 0ba0319..9ec096a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
@@ -83,4 +83,14 @@
public boolean canConfigBluetooth() {
return false;
}
+
+ @Override
+ public int getMaxConnectionState(CachedBluetoothDevice device) {
+ return 0;
+ }
+
+ @Override
+ public int getBondState(CachedBluetoothDevice device) {
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 76456f3..ad442c7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1804,7 +1804,7 @@
}
AppErrorResult res = (AppErrorResult) data.get("result");
if (mShowDialogs && !mSleeping && !mShuttingDown) {
- Dialog d = new StrictModeViolationDialog(mContext,
+ Dialog d = new StrictModeViolationDialog(mUiContext,
ActivityManagerService.this, res, proc);
d.show();
proc.crashDialog = d;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ba8fa31..f720cd5 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -600,6 +600,7 @@
void finishUserStopping(final int userId, final UserState uss) {
// On to the next.
final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+ shutdownIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
// This is the result receiver for the final shutdown broadcast.
final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
@Override
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index f23caf2..0fdf2da 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -30,6 +30,7 @@
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.TextureView;
+import android.view.ThreadedRenderer;
import android.view.View;
import android.view.WindowManager;
import android.view.TextureView.SurfaceTextureListener;
@@ -95,6 +96,8 @@
public OverlayDisplayWindow(Context context, String name,
int width, int height, int densityDpi, int gravity, boolean secure,
Listener listener) {
+ // Workaround device freeze (b/38372997)
+ ThreadedRenderer.disableVsync();
mContext = context;
mName = name;
mGravity = gravity;
diff --git a/services/core/java/com/android/server/job/GrantedUriPermissions.java b/services/core/java/com/android/server/job/GrantedUriPermissions.java
index e413d8d..c23b109 100644
--- a/services/core/java/com/android/server/job/GrantedUriPermissions.java
+++ b/services/core/java/com/android/server/job/GrantedUriPermissions.java
@@ -29,7 +29,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-public class GrantedUriPermissions {
+public final class GrantedUriPermissions {
private final int mGrantFlags;
private final int mSourceUserId;
private final String mTag;
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index 2d2f61f..a53c088 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -26,7 +26,7 @@
import java.io.PrintWriter;
-public class JobSchedulerShellCommand extends ShellCommand {
+public final class JobSchedulerShellCommand extends ShellCommand {
public static final int CMD_ERR_NO_PACKAGE = -1000;
public static final int CMD_ERR_NO_JOB = -1001;
public static final int CMD_ERR_CONSTRAINTS = -1002;
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 637db11..5d3f6f7 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -55,13 +55,13 @@
* job lands, and again when it is complete.
* - Cancelling is trickier, because there are also interactions from the client. It's possible
* the {@link com.android.server.job.JobServiceContext.JobServiceHandler} tries to process a
- * {@link #doCancelLocked(int)} after the client has already finished. This is handled by having
+ * {@link #doCancelLocked} after the client has already finished. This is handled by having
* {@link com.android.server.job.JobServiceContext.JobServiceHandler#handleCancelLocked} check whether
* the context is still valid.
* To mitigate this, we avoid sending duplicate onStopJob()
* calls to the client after they've specified jobFinished().
*/
-public class JobServiceContext extends IJobCallback.Stub implements ServiceConnection {
+public final class JobServiceContext implements ServiceConnection {
private static final boolean DEBUG = JobSchedulerService.DEBUG;
private static final String TAG = "JobServiceContext";
/** Amount of time a job is allowed to execute for before being considered timed-out. */
@@ -112,6 +112,7 @@
* Writes can only be done from the handler thread, or {@link #executeRunnableJob(JobStatus)}.
*/
private JobStatus mRunningJob;
+ private JobCallback mRunningCallback;
/** Used to store next job to run when current job is to be preempted. */
private int mPreferredUid;
IJobService service;
@@ -133,6 +134,36 @@
// Debugging: time this job was last stopped.
public long mStoppedTime;
+ final class JobCallback extends IJobCallback.Stub {
+ public String mStoppedReason;
+ public long mStoppedTime;
+
+ @Override
+ public void acknowledgeStartMessage(int jobId, boolean ongoing) {
+ doAcknowledgeStartMessage(this, jobId, ongoing);
+ }
+
+ @Override
+ public void acknowledgeStopMessage(int jobId, boolean reschedule) {
+ doAcknowledgeStopMessage(this, jobId, reschedule);
+ }
+
+ @Override
+ public JobWorkItem dequeueWork(int jobId) {
+ return doDequeueWork(this, jobId);
+ }
+
+ @Override
+ public boolean completeWork(int jobId, int workId) {
+ return doCompleteWork(this, jobId, workId);
+ }
+
+ @Override
+ public void jobFinished(int jobId, boolean reschedule) {
+ doJobFinished(this, jobId, reschedule);
+ }
+ }
+
JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
JobPackageTracker tracker, Looper looper) {
this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
@@ -168,6 +199,7 @@
mPreferredUid = NO_PREFERRED_UID;
mRunningJob = job;
+ mRunningCallback = new JobCallback();
final boolean isDeadlineExpired =
job.hasDeadlineConstraint() &&
(job.getLatestRunTimeElapsed() < SystemClock.elapsedRealtime());
@@ -182,7 +214,7 @@
job.changedAuthorities.toArray(triggeredAuthorities);
}
final JobInfo ji = job.getJob();
- mParams = new JobParameters(this, job.getJobId(), ji.getExtras(),
+ mParams = new JobParameters(mRunningCallback, job.getJobId(), ji.getExtras(),
ji.getTransientExtras(), ji.getClipData(), ji.getClipGrantFlags(),
isDeadlineExpired, triggeredUris, triggeredAuthorities);
mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
@@ -198,6 +230,7 @@
Slog.d(TAG, job.getServiceComponent().getShortClassName() + " unavailable.");
}
mRunningJob = null;
+ mRunningCallback = null;
mParams = null;
mExecutionStartTimeElapsed = 0L;
mVerb = VERB_FINISHED;
@@ -263,28 +296,29 @@
return false;
}
- @Override
- public void jobFinished(int jobId, boolean reschedule) {
- doCallback(reschedule, "app called jobFinished");
+ void doJobFinished(JobCallback cb, int jobId, boolean reschedule) {
+ doCallback(cb, reschedule, "app called jobFinished");
}
- @Override
- public void acknowledgeStopMessage(int jobId, boolean reschedule) {
- doCallback(reschedule, null);
+ void doAcknowledgeStopMessage(JobCallback cb, int jobId, boolean reschedule) {
+ doCallback(cb, reschedule, null);
}
- @Override
- public void acknowledgeStartMessage(int jobId, boolean ongoing) {
- doCallback(ongoing, "finished start");
+ void doAcknowledgeStartMessage(JobCallback cb, int jobId, boolean ongoing) {
+ doCallback(cb, ongoing, "finished start");
}
- @Override
- public JobWorkItem dequeueWork(int jobId) {
- final int callingUid = Binder.getCallingUid();
+ JobWorkItem doDequeueWork(JobCallback cb, int jobId) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallingUidLocked(callingUid);
+ assertCallerLocked(cb);
+ if (mVerb == VERB_STOPPING || mVerb == VERB_FINISHED) {
+ // This job is either all done, or on its way out. Either way, it
+ // should not dispatch any more work. We will pick up any remaining
+ // work the next time we start the job again.
+ return null;
+ }
final JobWorkItem work = mRunningJob.dequeueWorkLocked();
if (work == null && !mRunningJob.hasExecutingWorkLocked()) {
// This will finish the job.
@@ -297,13 +331,11 @@
}
}
- @Override
- public boolean completeWork(int jobId, int workId) {
- final int callingUid = Binder.getCallingUid();
+ boolean doCompleteWork(JobCallback cb, int jobId, int workId) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- assertCallingUidLocked(callingUid);
+ assertCallerLocked(cb);
return mRunningJob.completeWorkLocked(ActivityManager.getService(), workId);
}
} finally {
@@ -369,8 +401,8 @@
* whether the client exercising the callback is the client we expect.
* @return True if the binder calling is coming from the client we expect.
*/
- private boolean verifyCallingUidLocked(final int callingUid) {
- if (mRunningJob == null || callingUid != mRunningJob.getUid()) {
+ private boolean verifyCallerLocked(JobCallback cb) {
+ if (mRunningCallback != cb) {
if (DEBUG) {
Slog.d(TAG, "Stale callback received, ignoring.");
}
@@ -379,16 +411,15 @@
return true;
}
- private void assertCallingUidLocked(final int callingUid) {
- if (!verifyCallingUidLocked(callingUid)) {
+ private void assertCallerLocked(JobCallback cb) {
+ if (!verifyCallerLocked(cb)) {
StringBuilder sb = new StringBuilder(128);
- sb.append("Bad calling uid ");
- sb.append(callingUid);
- if (mStoppedReason != null) {
+ sb.append("Caller no longer running");
+ if (cb.mStoppedReason != null) {
sb.append(", last stopped ");
- TimeUtils.formatDuration(SystemClock.elapsedRealtime() - mStoppedTime, sb);
+ TimeUtils.formatDuration(SystemClock.elapsedRealtime() - cb.mStoppedTime, sb);
sb.append(" because: ");
- sb.append(mStoppedReason);
+ sb.append(cb.mStoppedReason);
}
throw new SecurityException(sb.toString());
}
@@ -421,12 +452,11 @@
handleServiceBoundLocked();
}
- void doCallback(boolean reschedule, String reason) {
- final int callingUid = Binder.getCallingUid();
+ void doCallback(JobCallback cb, boolean reschedule, String reason) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- if (!verifyCallingUidLocked(callingUid)) {
+ if (!verifyCallerLocked(cb)) {
return;
}
doCallbackLocked(reschedule, reason);
@@ -559,7 +589,7 @@
* VERB_BINDING -> Cancelled before bind completed. Mark as cancelled and wait for
* {@link #onServiceConnected(android.content.ComponentName, android.os.IBinder)}
* _STARTING -> Mark as cancelled and wait for
- * {@link JobServiceContext#acknowledgeStartMessage(int, boolean)}
+ * {@link JobServiceContext#doAcknowledgeStartMessage}
* _EXECUTING -> call {@link #sendStopMessageLocked}}, but only if there are no callbacks
* in the message queue.
* _ENDING -> No point in doing anything here, so we ignore.
@@ -671,6 +701,7 @@
mContext.unbindService(JobServiceContext.this);
mWakeLock = null;
mRunningJob = null;
+ mRunningCallback = null;
mParams = null;
mVerb = VERB_FINISHED;
mCancelled = false;
@@ -684,6 +715,10 @@
if (reason != null && mStoppedReason == null) {
mStoppedReason = reason;
mStoppedTime = SystemClock.elapsedRealtime();
+ if (mRunningCallback != null) {
+ mRunningCallback.mStoppedReason = mStoppedReason;
+ mRunningCallback.mStoppedTime = mStoppedTime;
+ }
}
}
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 22eed3b..f0cd8a8 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -66,7 +66,7 @@
* and {@link com.android.server.job.JobStore.ReadJobMapFromDiskRunnable} lock on that
* object.
*/
-public class JobStore {
+public final class JobStore {
private static final String TAG = "JobStore";
private static final boolean DEBUG = JobSchedulerService.DEBUG;
@@ -263,7 +263,7 @@
* Runnable that writes {@link #mJobSet} out to xml.
* NOTE: This Runnable locks on mLock
*/
- private class WriteJobsMapToDiskRunnable implements Runnable {
+ private final class WriteJobsMapToDiskRunnable implements Runnable {
@Override
public void run() {
final long startElapsed = SystemClock.elapsedRealtime();
@@ -444,7 +444,7 @@
* Runnable that reads list of persisted job from xml. This is run once at start up, so doesn't
* need to go through {@link JobStore#add(com.android.server.job.controllers.JobStatus)}.
*/
- private class ReadJobMapFromDiskRunnable implements Runnable {
+ private final class ReadJobMapFromDiskRunnable implements Runnable {
private final JobSet jobSet;
/**
@@ -796,7 +796,7 @@
}
}
- static class JobSet {
+ static final class JobSet {
// Key is the getUid() originator of the jobs in each sheaf
private SparseArray<ArraySet<JobStatus>> mJobs;
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 68dd00f..39f2a96 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -33,7 +33,7 @@
* for a certain amount of time (maybe hours or days) are considered idle. When the app comes
* out of idle state, it will be allowed to run scheduled jobs.
*/
-public class AppIdleController extends StateController {
+public final class AppIdleController extends StateController {
private static final String LOG_TAG = "AppIdleController";
private static final boolean DEBUG = false;
@@ -171,7 +171,7 @@
}
}
- private class AppIdleStateChangeListener
+ private final class AppIdleStateChangeListener
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index d275bd9..9111969 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -39,7 +39,7 @@
* be charging when it's been plugged in for more than two minutes, and the system has broadcast
* ACTION_BATTERY_OK.
*/
-public class BatteryController extends StateController {
+public final class BatteryController extends StateController {
private static final String TAG = "JobScheduler.Batt";
private static final Object sCreationLock = new Object();
@@ -121,7 +121,7 @@
}
}
- public class ChargingTracker extends BroadcastReceiver {
+ public final class ChargingTracker extends BroadcastReceiver {
/**
* Track whether we're "charging", where charging means that we're ready to commit to
* doing work.
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index f426818..17c8928 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -43,7 +43,7 @@
* status due to user-requested network policies, so we need to check
* constraints on a per-UID basis.
*/
-public class ConnectivityController extends StateController implements
+public final class ConnectivityController extends StateController implements
ConnectivityManager.OnNetworkActiveListener {
private static final String TAG = "JobScheduler.Conn";
private static final boolean DEBUG = false;
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index cfafc38..ff807ec 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -39,7 +39,7 @@
/**
* Controller for monitoring changes to content URIs through a ContentObserver.
*/
-public class ContentObserverController extends StateController {
+public final class ContentObserverController extends StateController {
private static final String TAG = "JobScheduler.Content";
private static final boolean DEBUG = false;
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 5ccf812..85993b9 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -37,7 +37,7 @@
* When device is dozing, set constraint for all jobs, except whitelisted apps, as not satisfied.
* When device is not dozing, set constraint for all jobs as satisfied.
*/
-public class DeviceIdleJobsController extends StateController {
+public final class DeviceIdleJobsController extends StateController {
private static final String LOG_TAG = "DeviceIdleJobsController";
private static final boolean LOG_DEBUG = false;
diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java
index 7e92293..9eda046 100644
--- a/services/core/java/com/android/server/job/controllers/IdleController.java
+++ b/services/core/java/com/android/server/job/controllers/IdleController.java
@@ -33,7 +33,7 @@
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateChangedListener;
-public class IdleController extends StateController {
+public final class IdleController extends StateController {
private static final String TAG = "IdleController";
// Policy: we decide that we're "idle" if the device has been unused /
@@ -107,7 +107,7 @@
mIdleTracker.startTracking();
}
- class IdlenessTracker extends BroadcastReceiver {
+ final class IdlenessTracker extends BroadcastReceiver {
private AlarmManager mAlarm;
private PendingIntent mIdleTriggerIntent;
boolean mIdle;
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 53bf402..446b0d6 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -698,7 +698,8 @@
static final int CONSTRAINTS_OF_INTEREST =
CONSTRAINT_CHARGING | CONSTRAINT_BATTERY_NOT_LOW | CONSTRAINT_STORAGE_NOT_LOW |
CONSTRAINT_TIMING_DELAY |
- CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING |
+ CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
+ CONSTRAINT_NOT_ROAMING | CONSTRAINT_METERED |
CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
// Soft override covers all non-"functional" constraints
@@ -865,6 +866,9 @@
if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
pw.print(" NOT_ROAMING");
}
+ if ((constraints&CONSTRAINT_METERED) != 0) {
+ pw.print(" METERED");
+ }
if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
pw.print(" APP_NOT_IDLE");
}
diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java
index 4fe8eca..c24e563 100644
--- a/services/core/java/com/android/server/job/controllers/StorageController.java
+++ b/services/core/java/com/android/server/job/controllers/StorageController.java
@@ -35,7 +35,7 @@
/**
* Simple controller that tracks the status of the device's storage.
*/
-public class StorageController extends StateController {
+public final class StorageController extends StateController {
private static final String TAG = "JobScheduler.Stor";
private static final Object sCreationLock = new Object();
@@ -112,7 +112,7 @@
}
}
- public class StorageTracker extends BroadcastReceiver {
+ public final class StorageTracker extends BroadcastReceiver {
/**
* Track whether storage is low.
*/
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 01c841e..d90699a 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -38,7 +38,7 @@
* This class sets an alarm for the next expiring job, and determines whether a job's minimum
* delay has been satisfied.
*/
-public class TimeController extends StateController {
+public final class TimeController extends StateController {
private static final String TAG = "JobScheduler.Time";
/** Deadline alarm tag for logging purposes */
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9c04801..bf3e5d3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -49,6 +49,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
@@ -677,13 +678,6 @@
@GuardedBy("mPackages")
final SparseIntArray mIsolatedOwners = new SparseIntArray();
- // List of APK paths to load for each user and package. This data is never
- // persisted by the package manager. Instead, the overlay manager will
- // ensure the data is up-to-date in runtime.
- @GuardedBy("mPackages")
- final SparseArray<ArrayMap<String, ArrayList<String>>> mEnabledOverlayPaths =
- new SparseArray<ArrayMap<String, ArrayList<String>>>();
-
/**
* Tracks new system packages [received in an OTA] that we expect to
* find updated user-installed versions. Keys are package name, values
@@ -3584,8 +3578,6 @@
return null;
}
- rebaseEnabledOverlays(packageInfo.applicationInfo, userId);
-
packageInfo.packageName = packageInfo.applicationInfo.packageName =
resolveExternalPackageNameLPr(p);
@@ -4097,7 +4089,6 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
}
return ai;
@@ -4146,7 +4137,6 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(
p, flags, ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(p);
}
return ai;
@@ -4163,26 +4153,6 @@
return null;
}
- private void rebaseEnabledOverlays(@NonNull ApplicationInfo ai, int userId) {
- List<String> paths = new ArrayList<>();
- ArrayMap<String, ArrayList<String>> userSpecificOverlays =
- mEnabledOverlayPaths.get(userId);
- if (userSpecificOverlays != null) {
- if (!"android".equals(ai.packageName)) {
- ArrayList<String> frameworkOverlays = userSpecificOverlays.get("android");
- if (frameworkOverlays != null) {
- paths.addAll(frameworkOverlays);
- }
- }
-
- ArrayList<String> appOverlays = userSpecificOverlays.get(ai.packageName);
- if (appOverlays != null) {
- paths.addAll(appOverlays);
- }
- }
- ai.resourceDirs = paths.size() > 0 ? paths.toArray(new String[paths.size()]) : null;
- }
-
private String normalizePackageNameLPr(String packageName) {
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
return normalizedPackageName != null ? normalizedPackageName : packageName;
@@ -4564,24 +4534,6 @@
return updateFlagsForComponent(flags, userId, intent /*cookie*/);
}
- private ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, PackageUserState state,
- int userId) {
- ActivityInfo ret = PackageParser.generateActivityInfo(ai, flags, state, userId);
- if (ret != null) {
- rebaseEnabledOverlays(ret.applicationInfo, userId);
- }
- return ret;
- }
-
- private ActivityInfo generateActivityInfo(PackageParser.Activity a, int flags,
- PackageUserState state, int userId) {
- ActivityInfo ai = PackageParser.generateActivityInfo(a, flags, state, userId);
- if (ai != null) {
- rebaseEnabledOverlays(ai.applicationInfo, userId);
- }
- return ai;
- }
-
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
@@ -4609,11 +4561,12 @@
if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
return null;
}
- return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
+ return PackageParser.generateActivityInfo(
+ a, flags, ps.readUserState(userId), userId);
}
if (mResolveComponentName.equals(component)) {
- return generateActivityInfo(mResolveActivity, flags, new PackageUserState(),
- userId);
+ return PackageParser.generateActivityInfo(
+ mResolveActivity, flags, new PackageUserState(), userId);
}
}
return null;
@@ -4667,7 +4620,8 @@
if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
return null;
}
- return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
+ return PackageParser.generateActivityInfo(
+ a, flags, ps.readUserState(userId), userId);
}
}
return null;
@@ -4803,12 +4757,8 @@
if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) {
return null;
}
- ServiceInfo si = PackageParser.generateServiceInfo(s, flags,
- ps.readUserState(userId), userId);
- if (si != null) {
- rebaseEnabledOverlays(si.applicationInfo, userId);
- }
- return si;
+ return PackageParser.generateServiceInfo(
+ s, flags, ps.readUserState(userId), userId);
}
}
return null;
@@ -4831,12 +4781,8 @@
if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
return null;
}
- ProviderInfo pi = PackageParser.generateProviderInfo(p, flags,
- ps.readUserState(userId), userId);
- if (pi != null) {
- rebaseEnabledOverlays(pi.applicationInfo, userId);
- }
- return pi;
+ return PackageParser.generateProviderInfo(
+ p, flags, ps.readUserState(userId), userId);
}
}
return null;
@@ -8262,7 +8208,6 @@
ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
}
} else {
@@ -8289,7 +8234,6 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
ai.packageName = resolveExternalPackageNameLPr(p);
list.add(ai);
}
@@ -8443,7 +8387,6 @@
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
- rebaseEnabledOverlays(ai, userId);
finalList.add(ai);
}
}
@@ -13367,7 +13310,8 @@
return null;
}
final PackageUserState userState = ps.readUserState(userId);
- ActivityInfo ai = generateActivityInfo(activity, mFlags, userState, userId);
+ ActivityInfo ai =
+ PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
if (ai == null) {
return null;
}
@@ -17896,16 +17840,17 @@
// Instant apps must have target SDK >= O and have targetSanboxVersion >= 2
if (instantApp && pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
- Slog.w(TAG, "Instant app package " + pkg.packageName
- + " does not target O, this will be a fatal error.");
- // STOPSHIP: Make this a fatal error
- pkg.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
+ Slog.w(TAG, "Instant app package " + pkg.packageName + " does not target O");
+ res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+ "Instant app package must target O");
+ return;
}
if (instantApp && pkg.applicationInfo.targetSandboxVersion != 2) {
Slog.w(TAG, "Instant app package " + pkg.packageName
- + " does not target targetSandboxVersion 2, this will be a fatal error.");
- // STOPSHIP: Make this a fatal error
- pkg.applicationInfo.targetSandboxVersion = 2;
+ + " does not target targetSandboxVersion 2");
+ res.setError(INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+ "Instant app package must use targetSanboxVersion 2");
+ return;
}
if (pkg.applicationInfo.isStaticSharedLibrary()) {
@@ -22346,11 +22291,6 @@
dumpCompilerStatsLPr(pw, packageName);
}
- if (!checkin && dumpState.isDumping(DumpState.DUMP_ENABLED_OVERLAYS)) {
- if (dumpState.onTitlePrinted()) pw.println();
- dumpEnabledOverlaysLPr(pw);
- }
-
if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
mSettings.dumpReadMessagesLPr(pw, dumpState);
@@ -22547,23 +22487,6 @@
}
}
- private void dumpEnabledOverlaysLPr(PrintWriter pw) {
- pw.println("Enabled overlay paths:");
- final int N = mEnabledOverlayPaths.size();
- for (int i = 0; i < N; i++) {
- final int userId = mEnabledOverlayPaths.keyAt(i);
- pw.println(String.format(" User %d:", userId));
- final ArrayMap<String, ArrayList<String>> userSpecificOverlays =
- mEnabledOverlayPaths.valueAt(i);
- final int M = userSpecificOverlays.size();
- for (int j = 0; j < M; j++) {
- final String targetPackageName = userSpecificOverlays.keyAt(j);
- final ArrayList<String> overlayPackagePaths = userSpecificOverlays.valueAt(j);
- pw.println(String.format(" %s: %s", targetPackageName, overlayPackagePaths));
- }
- }
- }
-
private String dumpDomainString(String packageName) {
List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName)
.getList();
@@ -24741,11 +24664,10 @@
Slog.e(TAG, "failed to find package " + targetPackageName);
return false;
}
-
- ArrayList<String> paths = null;
- if (overlayPackageNames != null) {
+ ArrayList<String> overlayPaths = null;
+ if (overlayPackageNames != null && overlayPackageNames.size() > 0) {
final int N = overlayPackageNames.size();
- paths = new ArrayList<>(N);
+ overlayPaths = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
final String packageName = overlayPackageNames.get(i);
final PackageParser.Package pkg = mPackages.get(packageName);
@@ -24753,22 +24675,17 @@
Slog.e(TAG, "failed to find package " + packageName);
return false;
}
- paths.add(pkg.baseCodePath);
+ overlayPaths.add(pkg.baseCodePath);
}
}
- ArrayMap<String, ArrayList<String>> userSpecificOverlays =
- mEnabledOverlayPaths.get(userId);
- if (userSpecificOverlays == null) {
- userSpecificOverlays = new ArrayMap<>();
- mEnabledOverlayPaths.put(userId, userSpecificOverlays);
+ final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
+ String[] frameworkOverlayPaths = null;
+ if (!"android".equals(targetPackageName)) {
+ frameworkOverlayPaths =
+ mSettings.mPackages.get("android").getOverlayPaths(userId);
}
-
- if (paths != null && paths.size() > 0) {
- userSpecificOverlays.put(targetPackageName, paths);
- } else {
- userSpecificOverlays.remove(targetPackageName);
- }
+ ps.setOverlayPaths(overlayPaths, frameworkOverlayPaths, userId);
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 14f65eb..d17267f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -31,6 +31,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
+import com.google.android.collect.Lists;
import java.io.File;
import java.util.ArrayList;
@@ -329,6 +330,27 @@
modifyUserState(userId).installReason = installReason;
}
+ void setOverlayPaths(List<String> overlayPaths, String[] frameworkOverlayPaths, int userId) {
+ if (overlayPaths == null && frameworkOverlayPaths == null) {
+ modifyUserState(userId).overlayPaths = null;
+ return;
+ }
+ final List<String> paths;
+ if (frameworkOverlayPaths == null) {
+ paths = overlayPaths;
+ } else {
+ paths = Lists.newArrayList(frameworkOverlayPaths);
+ if (overlayPaths != null) {
+ paths.addAll(overlayPaths);
+ }
+ }
+ modifyUserState(userId).overlayPaths = paths.toArray(new String[paths.size()]);
+ }
+
+ String[] getOverlayPaths(int userId) {
+ return readUserState(userId).overlayPaths;
+ }
+
/** Only use for testing. Do NOT use in production code. */
@VisibleForTesting
SparseArray<PackageUserState> getUserState() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 24cbdbf..b006c2d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4858,6 +4858,15 @@
pw.print(ps.getEnabled(user.id));
pw.print(" instant=");
pw.println(ps.getInstantApp(user.id));
+
+ String[] overlayPaths = ps.getOverlayPaths(user.id);
+ if (overlayPaths != null && overlayPaths.length > 0) {
+ pw.println("Overlay paths:");
+ for (String path : overlayPaths) {
+ pw.println(path);
+ }
+ }
+
String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
if (lastDisabledAppCaller != null) {
pw.print(prefix); pw.print(" lastDisabledCaller: ");
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 28ffc94..02f2afc 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -391,7 +391,8 @@
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 71ecaf6..350a333 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -891,8 +891,24 @@
return mPendingRelaunchCount > 0;
}
+ boolean shouldFreezeBounds() {
+ final Task task = getTask();
+
+ // For freeform windows, we can't freeze the bounds at the moment because this would make
+ // the resizing unresponsive.
+ if (task == null || task.inFreeformWorkspace()) {
+ return false;
+ }
+
+ // We freeze the bounds while drag resizing to deal with the time between
+ // the divider/drag handle being released, and the handling it's new
+ // configuration. If we are relaunched outside of the drag resizing state,
+ // we need to be careful not to do this.
+ return getTask().isDragResizing();
+ }
+
void startRelaunching() {
- if (canFreezeBounds()) {
+ if (shouldFreezeBounds()) {
freezeBounds();
}
@@ -909,9 +925,8 @@
}
void finishRelaunching() {
- if (canFreezeBounds()) {
- unfreezeBounds();
- }
+ unfreezeBounds();
+
if (mPendingRelaunchCount > 0) {
mPendingRelaunchCount--;
} else {
@@ -926,9 +941,7 @@
if (mPendingRelaunchCount == 0) {
return;
}
- if (canFreezeBounds()) {
- unfreezeBounds();
- }
+ unfreezeBounds();
mPendingRelaunchCount = 0;
}
@@ -1032,14 +1045,6 @@
}
}
- private boolean canFreezeBounds() {
- final Task task = getTask();
-
- // For freeform windows, we can't freeze the bounds at the moment because this would make
- // the resizing unresponsive.
- return task != null && !task.inFreeformWorkspace();
- }
-
/**
* Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
* freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
@@ -1064,9 +1069,10 @@
* Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
*/
private void unfreezeBounds() {
- if (!mFrozenBounds.isEmpty()) {
- mFrozenBounds.remove();
+ if (mFrozenBounds.isEmpty()) {
+ return;
}
+ mFrozenBounds.remove();
if (!mFrozenMergedConfig.isEmpty()) {
mFrozenMergedConfig.remove();
}
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 7d13889..cff2fad 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -206,6 +206,10 @@
mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
mFrom.top + mFrozenTaskHeight);
+ // Boost the thread priority of the animation thread while the bounds animation is
+ // running
+ updateBooster();
+
// Ensure that we have prepared the target for animation before
// we trigger any size changes, so it can swap surfaces
// in to appropriate modes, or do as it wishes otherwise.
@@ -316,6 +320,9 @@
removeListener(this);
removeUpdateListener(this);
mRunningAnimations.remove(mTarget);
+
+ // Reset the thread priority of the animation thread after the bounds animation is done
+ updateBooster();
}
@Override
@@ -446,4 +453,9 @@
b.resume();
}
}
+
+ private void updateBooster() {
+ WindowManagerService.sThreadPriorityBooster.setBoundsAnimationRunning(
+ !mRunningAnimations.isEmpty());
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index ccc8f63..fbe6f94 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -210,6 +210,7 @@
final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
/** @see #computeCompatSmallestWidth(boolean, int, int, int, int) */
private final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
+
/**
* Compat metrics computed based on {@link #mDisplayMetrics}.
* @see #updateDisplayAndOrientation(int)
@@ -226,6 +227,7 @@
* @see #updateRotationUnchecked(boolean)
*/
private int mRotation = 0;
+
/**
* Last applied orientation of the display.
* Constants as per {@link android.content.pm.ActivityInfo.ScreenOrientation}.
@@ -233,6 +235,7 @@
* @see WindowManagerService#updateOrientationFromAppTokensLocked(boolean, int)
*/
private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
/**
* Flag indicating that the application is receiving an orientation that has different metrics
* than it expected. E.g. Portrait instead of Landscape.
@@ -240,6 +243,7 @@
* @see #updateRotationUnchecked(boolean)
*/
private boolean mAltOrientation = false;
+
/**
* Orientation forced by some window. If there is no visible window that specifies orientation
* it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
@@ -247,6 +251,7 @@
* @see NonAppWindowContainers#getOrientation()
*/
private int mLastWindowForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
/**
* Last orientation forced by the keyguard. It is applied when keyguard is shown and is not
* occluded.
@@ -255,6 +260,11 @@
*/
private int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ /**
+ * Keep track of wallpaper visibility to notify changes.
+ */
+ private boolean mLastWallpaperVisible = false;
+
private Rect mBaseDisplayRect = new Rect();
private Rect mContentRect = new Rect();
@@ -314,6 +324,9 @@
// the display's direct children should be allowed.
private boolean mRemovingDisplay = false;
+ // {@code false} if this display is in the processing of being created.
+ private boolean mDisplayReady = false;
+
private final WindowLayersController mLayersController;
WallpaperController mWallpaperController;
int mInputMethodAnimLayerAdjustment;
@@ -720,7 +733,6 @@
*/
DisplayContent(Display display, WindowManagerService service,
WindowLayersController layersController, WallpaperController wallpaperController) {
-
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -748,6 +760,15 @@
// Add itself as a child to the root container.
mService.mRoot.addChild(this, null);
+
+ // TODO(b/62541591): evaluate whether this is the best spot to declare the
+ // {@link DisplayContent} ready for use.
+ mDisplayReady = true;
+ }
+
+ boolean isReady() {
+ // The display is ready when the system and the individual display are both ready.
+ return mService.mDisplayReady && mDisplayReady;
}
int getDisplayId() {
@@ -2754,6 +2775,12 @@
stopDimmingIfNeeded();
+ final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
+ if (wallpaperVisible != mLastWallpaperVisible) {
+ mLastWallpaperVisible = wallpaperVisible;
+ mService.mWallpaperVisibilityListeners.notifyWallpaperVisibilityChanged(this);
+ }
+
while (!mTmpUpdateAllDrawn.isEmpty()) {
final AppWindowToken atoken = mTmpUpdateAllDrawn.removeLast();
// See if any windows have been drawn, so they (and others associated with them)
diff --git a/services/core/java/com/android/server/wm/WallpaperVisibilityListeners.java b/services/core/java/com/android/server/wm/WallpaperVisibilityListeners.java
new file mode 100644
index 0000000..2c06851
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WallpaperVisibilityListeners.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.IWallpaperVisibilityListener;
+
+/**
+ * Manages and trigger wallpaper visibility listeners.
+ */
+class WallpaperVisibilityListeners {
+
+ /**
+ * A map of displayIds and its listeners.
+ */
+ private final SparseArray<RemoteCallbackList<IWallpaperVisibilityListener>> mDisplayListeners =
+ new SparseArray<>();
+
+ void registerWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
+ int displayId) {
+ RemoteCallbackList<IWallpaperVisibilityListener> listeners =
+ mDisplayListeners.get(displayId);
+ if (listeners == null) {
+ listeners = new RemoteCallbackList<>();
+ mDisplayListeners.append(displayId, listeners);
+ }
+ listeners.register(listener);
+ }
+
+ void unregisterWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
+ int displayId) {
+ RemoteCallbackList<IWallpaperVisibilityListener> listeners =
+ mDisplayListeners.get(displayId);
+ if (listeners == null) {
+ return;
+ }
+ listeners.unregister(listener);
+ }
+
+ void notifyWallpaperVisibilityChanged(DisplayContent displayContent) {
+ final int displayId = displayContent.getDisplayId();
+ final boolean visible = displayContent.mWallpaperController.isWallpaperVisible();
+ RemoteCallbackList<IWallpaperVisibilityListener> displayListeners =
+ mDisplayListeners.get(displayId);
+
+ // No listeners for this display.
+ if (displayListeners == null) {
+ return;
+ }
+
+ int i = displayListeners.beginBroadcast();
+ while (i > 0) {
+ i--;
+ IWallpaperVisibilityListener listener = displayListeners.getBroadcastItem(i);
+ try {
+ listener.onWallpaperVisibilityChanged(visible, displayId);
+ } catch (RemoteException e) {
+ // Nothing to do in here, RemoteCallbackListener will clean it up.
+ }
+ }
+ displayListeners.finishBroadcast();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 03b5b827..aabf2be 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -108,7 +108,8 @@
}
void addDisplayLocked(final int displayId) {
- // Create the DisplayContentsAnimator object by retrieving it.
+ // Create the DisplayContentsAnimator object by retrieving it if the associated
+ // {@link DisplayContent} exists.
getDisplayContentsAnimatorLocked(displayId);
if (displayId == DEFAULT_DISPLAY) {
mInitialized = true;
@@ -356,8 +357,16 @@
}
private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
+ if (displayId < 0) {
+ return null;
+ }
+
DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
- if (displayAnimator == null) {
+
+ // It is possible that this underlying {@link DisplayContent} has been removed. In this
+ // case, we do not want to create an animator associated with it as {link #animate} will
+ // fail.
+ if (displayAnimator == null && mService.mRoot.getDisplayContent(displayId) != null) {
displayAnimator = new DisplayContentsAnimator();
mDisplayContentsAnimators.put(displayId, displayAnimator);
}
@@ -365,8 +374,10 @@
}
void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
- if (displayId >= 0) {
- getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+ final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
+
+ if (animator != null) {
+ animator.mScreenRotationAnimation = animation;
}
}
@@ -374,7 +385,9 @@
if (displayId < 0) {
return null;
}
- return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
+
+ DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
+ return animator != null? animator.mScreenRotationAnimation : null;
}
void requestRemovalOfReplacedWindows(WindowState win) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3b7ec34..93116a3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -181,6 +181,7 @@
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedStackListener;
import android.view.IRotationWatcher;
+import android.view.IWallpaperVisibilityListener;
import android.view.IWindow;
import android.view.IWindowId;
import android.view.IWindowManager;
@@ -549,9 +550,9 @@
}
class RotationWatcher {
- IRotationWatcher mWatcher;
- IBinder.DeathRecipient mDeathRecipient;
- int mDisplayId;
+ final IRotationWatcher mWatcher;
+ final IBinder.DeathRecipient mDeathRecipient;
+ final int mDisplayId;
RotationWatcher(IRotationWatcher watcher, IBinder.DeathRecipient deathRecipient,
int displayId) {
mWatcher = watcher;
@@ -562,6 +563,8 @@
ArrayList<RotationWatcher> mRotationWatchers = new ArrayList<>();
int mDeferredRotationPauseCount;
+ final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
+ new WallpaperVisibilityListeners();
int mSystemDecorLayer = 0;
final Rect mScreenRect = new Rect();
@@ -3937,6 +3940,29 @@
}
}
+ @Override
+ public boolean registerWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
+ int displayId) {
+ synchronized (mWindowMap) {
+ final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+ if (displayContent == null) {
+ throw new IllegalArgumentException("Trying to register visibility event "
+ + "for invalid display: " + displayId);
+ }
+ mWallpaperVisibilityListeners.registerWallpaperVisibilityListener(listener, displayId);
+ return displayContent.mWallpaperController.isWallpaperVisible();
+ }
+ }
+
+ @Override
+ public void unregisterWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
+ int displayId) {
+ synchronized (mWindowMap) {
+ mWallpaperVisibilityListeners
+ .unregisterWallpaperVisibilityListener(listener, displayId);
+ }
+ }
+
/**
* Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
* theme attribute) on devices that feature a physical options menu key attempt to position
@@ -5890,8 +5916,8 @@
return;
}
- if (!mDisplayReady || !mPolicy.isScreenOn()) {
- // No need to freeze the screen before the system is ready or if
+ if (!displayContent.isReady() || !mPolicy.isScreenOn()) {
+ // No need to freeze the screen before the display is ready, system is ready, or if
// the screen is off.
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
index 6a244a2..1b2eb46 100644
--- a/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
+++ b/services/core/java/com/android/server/wm/WindowManagerThreadPriorityBooster.java
@@ -23,6 +23,7 @@
import static com.android.server.LockGuard.INDEX_WINDOW;
import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.AnimationThread;
import com.android.server.ThreadPriorityBooster;
@@ -32,12 +33,18 @@
*/
class WindowManagerThreadPriorityBooster extends ThreadPriorityBooster {
- private final AnimationThread mAnimationThread;
+ private final Object mLock = new Object();
+
+ private final int mAnimationThreadId;
+
+ @GuardedBy("mLock")
private boolean mAppTransitionRunning;
+ @GuardedBy("mLock")
+ private boolean mBoundsAnimationRunning;
WindowManagerThreadPriorityBooster() {
super(THREAD_PRIORITY_DISPLAY, INDEX_WINDOW);
- mAnimationThread = AnimationThread.get();
+ mAnimationThreadId = AnimationThread.get().getThreadId();
}
@Override
@@ -45,7 +52,7 @@
// Do not boost the animation thread. As the animation thread is changing priorities,
// boosting it might mess up the priority because we reset it the the previous priority.
- if (myTid() == mAnimationThread.getThreadId()) {
+ if (myTid() == mAnimationThreadId) {
return;
}
super.boost();
@@ -55,24 +62,35 @@
public void reset() {
// See comment in boost().
- if (myTid() == mAnimationThread.getThreadId()) {
+ if (myTid() == mAnimationThreadId) {
return;
}
super.reset();
}
void setAppTransitionRunning(boolean running) {
- if (mAppTransitionRunning == running) {
- return;
+ synchronized (mLock) {
+ if (mAppTransitionRunning != running) {
+ mAppTransitionRunning = running;
+ updatePriorityLocked();
+ }
}
-
- final int priority = calculatePriority(running);
- setBoostToPriority(priority);
- setThreadPriority(mAnimationThread.getThreadId(), priority);
- mAppTransitionRunning = running;
}
- private int calculatePriority(boolean appTransitionRunning) {
- return appTransitionRunning ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY;
+ void setBoundsAnimationRunning(boolean running) {
+ synchronized (mLock) {
+ if (mBoundsAnimationRunning != running) {
+ mBoundsAnimationRunning = running;
+ updatePriorityLocked();
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void updatePriorityLocked() {
+ int priority = (mAppTransitionRunning || mBoundsAnimationRunning)
+ ? TOP_APP_PRIORITY_BOOST : THREAD_PRIORITY_DISPLAY;
+ setBoostToPriority(priority);
+ setThreadPriority(mAnimationThreadId, priority);
}
}
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 96c2d7e..470cc57 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -39,7 +39,7 @@
}
-static void android_server_SystemServer_startHidlServices(JNIEnv* /* env */, jobject /* clazz */) {
+static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
using ::android::frameworks::sensorservice::V1_0::ISensorManager;
@@ -50,7 +50,10 @@
configureRpcThreadpool(5, false /* callerWillJoin */);
- sp<ISensorManager> sensorService = new SensorManager();
+ JavaVM *vm;
+ LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
+
+ sp<ISensorManager> sensorService = new SensorManager(vm);
err = sensorService->registerAsService();
ALOGE_IF(err != OK, "Cannot register %s: %d", ISensorManager::descriptor, err);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 1d5fb55..f53eb15 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -558,6 +558,13 @@
}
}
+ boolean isRecognitionRequested(UUID modelId) {
+ synchronized (mLock) {
+ ModelData modelData = mModelDataMap.get(modelId);
+ return modelData != null && modelData.isRequested();
+ }
+ }
+
//---- SoundTrigger.StatusListener methods
@Override
public void onRecognition(RecognitionEvent event) {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 9bca012..51c805d 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -16,18 +16,25 @@
package com.android.server.soundtrigger;
import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
+import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.Manifest;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
+import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.ParcelUuid;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.util.Slog;
@@ -36,6 +43,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.TreeMap;
import java.util.UUID;
/**
@@ -52,16 +60,23 @@
private static final boolean DEBUG = true;
final Context mContext;
+ private Object mLock;
private final SoundTriggerServiceStub mServiceStub;
private final LocalSoundTriggerService mLocalSoundTriggerService;
private SoundTriggerDbHelper mDbHelper;
private SoundTriggerHelper mSoundTriggerHelper;
+ private final TreeMap<UUID, SoundModel> mLoadedModels;
+ private final TreeMap<UUID, LocalSoundTriggerRecognitionStatusCallback> mIntentCallbacks;
+ private PowerManager.WakeLock mWakelock;
public SoundTriggerService(Context context) {
super(context);
mContext = context;
mServiceStub = new SoundTriggerServiceStub();
mLocalSoundTriggerService = new LocalSoundTriggerService(context);
+ mLoadedModels = new TreeMap<UUID, SoundModel>();
+ mIntentCallbacks = new TreeMap<UUID, LocalSoundTriggerRecognitionStatusCallback>();
+ mLock = new Object();
}
@Override
@@ -177,8 +192,357 @@
mSoundTriggerHelper.unloadGenericSoundModel(soundModelId.getUuid());
mDbHelper.deleteGenericSoundModel(soundModelId.getUuid());
}
+
+ @Override
+ public int loadGenericSoundModel(GenericSoundModel soundModel) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_ERROR;
+ if (soundModel == null || soundModel.uuid == null) {
+ Slog.e(TAG, "Invalid sound model");
+ return STATUS_ERROR;
+ }
+ if (DEBUG) {
+ Slog.i(TAG, "loadGenericSoundModel(): id = " + soundModel.uuid);
+ }
+ synchronized (mLock) {
+ SoundModel oldModel = mLoadedModels.get(soundModel.uuid);
+ // If the model we're loading is actually different than what we had loaded, we
+ // should unload that other model now. We don't care about return codes since we
+ // don't know if the other model is loaded.
+ if (oldModel != null && !oldModel.equals(soundModel)) {
+ mSoundTriggerHelper.unloadGenericSoundModel(soundModel.uuid);
+ mIntentCallbacks.remove(soundModel.uuid);
+ }
+ mLoadedModels.put(soundModel.uuid, soundModel);
+ }
+ return STATUS_OK;
+ }
+
+ @Override
+ public int loadKeyphraseSoundModel(KeyphraseSoundModel soundModel) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_ERROR;
+ if (soundModel == null || soundModel.uuid == null) {
+ Slog.e(TAG, "Invalid sound model");
+ return STATUS_ERROR;
+ }
+ if (soundModel.keyphrases == null || soundModel.keyphrases.length != 1) {
+ Slog.e(TAG, "Only one keyphrase per model is currently supported.");
+ return STATUS_ERROR;
+ }
+ if (DEBUG) {
+ Slog.i(TAG, "loadKeyphraseSoundModel(): id = " + soundModel.uuid);
+ }
+ synchronized (mLock) {
+ SoundModel oldModel = mLoadedModels.get(soundModel.uuid);
+ // If the model we're loading is actually different than what we had loaded, we
+ // should unload that other model now. We don't care about return codes since we
+ // don't know if the other model is loaded.
+ if (oldModel != null && !oldModel.equals(soundModel)) {
+ mSoundTriggerHelper.unloadKeyphraseSoundModel(soundModel.keyphrases[0].id);
+ mIntentCallbacks.remove(soundModel.uuid);
+ }
+ mLoadedModels.put(soundModel.uuid, soundModel);
+ }
+ return STATUS_OK;
+ }
+
+ @Override
+ public int startRecognitionForIntent(ParcelUuid soundModelId, PendingIntent callbackIntent,
+ SoundTrigger.RecognitionConfig config) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_ERROR;
+ if (DEBUG) {
+ Slog.i(TAG, "startRecognition(): id = " + soundModelId);
+ }
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded");
+ return STATUS_ERROR;
+ }
+ LocalSoundTriggerRecognitionStatusCallback callback = mIntentCallbacks.get(
+ soundModelId.getUuid());
+ if (callback != null) {
+ Slog.e(TAG, soundModelId + " is already running");
+ return STATUS_ERROR;
+ }
+ callback = new LocalSoundTriggerRecognitionStatusCallback(soundModelId.getUuid(),
+ callbackIntent, config);
+ int ret;
+ switch (soundModel.type) {
+ case SoundModel.TYPE_KEYPHRASE: {
+ KeyphraseSoundModel keyphraseSoundModel = (KeyphraseSoundModel) soundModel;
+ ret = mSoundTriggerHelper.startKeyphraseRecognition(
+ keyphraseSoundModel.keyphrases[0].id, keyphraseSoundModel, callback,
+ config);
+ } break;
+ case SoundModel.TYPE_GENERIC_SOUND:
+ ret = mSoundTriggerHelper.startGenericRecognition(soundModel.uuid,
+ (GenericSoundModel) soundModel, callback, config);
+ break;
+ default:
+ Slog.e(TAG, "Unknown model type");
+ return STATUS_ERROR;
+ }
+
+ if (ret != STATUS_OK) {
+ Slog.e(TAG, "Failed to start model: " + ret);
+ return ret;
+ }
+ mIntentCallbacks.put(soundModelId.getUuid(), callback);
+ }
+ return STATUS_OK;
+ }
+
+ @Override
+ public int stopRecognitionForIntent(ParcelUuid soundModelId) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_ERROR;
+ if (DEBUG) {
+ Slog.i(TAG, "stopRecognition(): id = " + soundModelId);
+ }
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded");
+ return STATUS_ERROR;
+ }
+ LocalSoundTriggerRecognitionStatusCallback callback = mIntentCallbacks.get(
+ soundModelId.getUuid());
+ if (callback == null) {
+ Slog.e(TAG, soundModelId + " is not running");
+ return STATUS_ERROR;
+ }
+ int ret;
+ switch (soundModel.type) {
+ case SoundModel.TYPE_KEYPHRASE:
+ ret = mSoundTriggerHelper.stopKeyphraseRecognition(
+ ((KeyphraseSoundModel)soundModel).keyphrases[0].id, callback);
+ break;
+ case SoundModel.TYPE_GENERIC_SOUND:
+ ret = mSoundTriggerHelper.stopGenericRecognition(soundModel.uuid, callback);
+ break;
+ default:
+ Slog.e(TAG, "Unknown model type");
+ return STATUS_ERROR;
+ }
+
+ if (ret != STATUS_OK) {
+ Slog.e(TAG, "Failed to stop model: " + ret);
+ return ret;
+ }
+ mIntentCallbacks.remove(soundModelId.getUuid());
+ }
+ return STATUS_OK;
+ }
+
+ @Override
+ public int unloadSoundModel(ParcelUuid soundModelId) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return STATUS_ERROR;
+ if (DEBUG) {
+ Slog.i(TAG, "unloadSoundModel(): id = " + soundModelId);
+ }
+
+ synchronized (mLock) {
+ SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid());
+ if (soundModel == null) {
+ Slog.e(TAG, soundModelId + " is not loaded");
+ return STATUS_ERROR;
+ }
+ int ret;
+ switch (soundModel.type) {
+ case SoundModel.TYPE_KEYPHRASE:
+ ret = mSoundTriggerHelper.unloadKeyphraseSoundModel(
+ ((KeyphraseSoundModel)soundModel).keyphrases[0].id);
+ break;
+ case SoundModel.TYPE_GENERIC_SOUND:
+ ret = mSoundTriggerHelper.unloadGenericSoundModel(soundModel.uuid);
+ break;
+ default:
+ Slog.e(TAG, "Unknown model type");
+ return STATUS_ERROR;
+ }
+ if (ret != STATUS_OK) {
+ Slog.e(TAG, "Failed to unload model");
+ return ret;
+ }
+ mLoadedModels.remove(soundModelId.getUuid());
+ return STATUS_OK;
+ }
+ }
+
+ @Override
+ public boolean isRecognitionActive(ParcelUuid parcelUuid) {
+ enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (!isInitialized()) return false;
+ synchronized (mLock) {
+ LocalSoundTriggerRecognitionStatusCallback callback =
+ mIntentCallbacks.get(parcelUuid.getUuid());
+ if (callback == null) {
+ return false;
+ }
+ return mSoundTriggerHelper.isRecognitionRequested(parcelUuid.getUuid());
+ }
+ }
}
+ private final class LocalSoundTriggerRecognitionStatusCallback
+ extends IRecognitionStatusCallback.Stub {
+ private UUID mUuid;
+ private PendingIntent mCallbackIntent;
+ private RecognitionConfig mRecognitionConfig;
+
+ public LocalSoundTriggerRecognitionStatusCallback(UUID modelUuid,
+ PendingIntent callbackIntent,
+ RecognitionConfig config) {
+ mUuid = modelUuid;
+ mCallbackIntent = callbackIntent;
+ mRecognitionConfig = config;
+ }
+
+ @Override
+ public boolean pingBinder() {
+ return mCallbackIntent != null;
+ }
+
+ @Override
+ public void onKeyphraseDetected(SoundTrigger.KeyphraseRecognitionEvent event) {
+ if (mCallbackIntent == null) {
+ return;
+ }
+ grabWakeLock();
+
+ Slog.w(TAG, "Keyphrase sound trigger event: " + event);
+ Intent extras = new Intent();
+ extras.putExtra(SoundTriggerManager.EXTRA_MESSAGE_TYPE,
+ SoundTriggerManager.FLAG_MESSAGE_TYPE_RECOGNITION_EVENT);
+ extras.putExtra(SoundTriggerManager.EXTRA_RECOGNITION_EVENT, event);
+ try {
+ mCallbackIntent.send(mContext, 0, extras, mCallbackCompletedHandler, null);
+ if (!mRecognitionConfig.allowMultipleTriggers) {
+ removeCallback(/*releaseWakeLock=*/false);
+ }
+ } catch (PendingIntent.CanceledException e) {
+ removeCallback(/*releaseWakeLock=*/true);
+ }
+ }
+
+ @Override
+ public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
+ if (mCallbackIntent == null) {
+ return;
+ }
+ grabWakeLock();
+
+ Slog.w(TAG, "Generic sound trigger event: " + event);
+ Intent extras = new Intent();
+ extras.putExtra(SoundTriggerManager.EXTRA_MESSAGE_TYPE,
+ SoundTriggerManager.FLAG_MESSAGE_TYPE_RECOGNITION_EVENT);
+ extras.putExtra(SoundTriggerManager.EXTRA_RECOGNITION_EVENT, event);
+ try {
+ mCallbackIntent.send(mContext, 0, extras, mCallbackCompletedHandler, null);
+ if (!mRecognitionConfig.allowMultipleTriggers) {
+ removeCallback(/*releaseWakeLock=*/false);
+ }
+ } catch (PendingIntent.CanceledException e) {
+ removeCallback(/*releaseWakeLock=*/true);
+ }
+ }
+
+ @Override
+ public void onError(int status) {
+ if (mCallbackIntent == null) {
+ return;
+ }
+ grabWakeLock();
+
+ Slog.i(TAG, "onError: " + status);
+ Intent extras = new Intent();
+ extras.putExtra(SoundTriggerManager.EXTRA_MESSAGE_TYPE,
+ SoundTriggerManager.FLAG_MESSAGE_TYPE_RECOGNITION_ERROR);
+ extras.putExtra(SoundTriggerManager.EXTRA_STATUS, status);
+ try {
+ mCallbackIntent.send(mContext, 0, extras, mCallbackCompletedHandler, null);
+ // Remove the callback, but wait for the intent to finish before we let go of the
+ // wake lock
+ removeCallback(/*releaseWakeLock=*/false);
+ } catch (PendingIntent.CanceledException e) {
+ removeCallback(/*releaseWakeLock=*/true);
+ }
+ }
+
+ @Override
+ public void onRecognitionPaused() {
+ if (mCallbackIntent == null) {
+ return;
+ }
+ grabWakeLock();
+
+ Slog.i(TAG, "onRecognitionPaused");
+ Intent extras = new Intent();
+ extras.putExtra(SoundTriggerManager.EXTRA_MESSAGE_TYPE,
+ SoundTriggerManager.FLAG_MESSAGE_TYPE_RECOGNITION_PAUSED);
+ try {
+ mCallbackIntent.send(mContext, 0, extras, mCallbackCompletedHandler, null);
+ } catch (PendingIntent.CanceledException e) {
+ removeCallback(/*releaseWakeLock=*/true);
+ }
+ }
+
+ @Override
+ public void onRecognitionResumed() {
+ if (mCallbackIntent == null) {
+ return;
+ }
+ grabWakeLock();
+
+ Slog.i(TAG, "onRecognitionResumed");
+ Intent extras = new Intent();
+ extras.putExtra(SoundTriggerManager.EXTRA_MESSAGE_TYPE,
+ SoundTriggerManager.FLAG_MESSAGE_TYPE_RECOGNITION_RESUMED);
+ try {
+ mCallbackIntent.send(mContext, 0, extras, mCallbackCompletedHandler, null);
+ } catch (PendingIntent.CanceledException e) {
+ removeCallback(/*releaseWakeLock=*/true);
+ }
+ }
+
+ private void removeCallback(boolean releaseWakeLock) {
+ mCallbackIntent = null;
+ synchronized (mLock) {
+ mIntentCallbacks.remove(mUuid);
+ if (releaseWakeLock) {
+ mWakelock.release();
+ }
+ }
+ }
+ }
+
+ private void grabWakeLock() {
+ synchronized (mLock) {
+ if (mWakelock == null) {
+ PowerManager pm = ((PowerManager) mContext.getSystemService(Context.POWER_SERVICE));
+ mWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ }
+ mWakelock.acquire();
+ }
+ }
+
+ private PendingIntent.OnFinished mCallbackCompletedHandler = new PendingIntent.OnFinished() {
+ @Override
+ public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
+ String resultData, Bundle resultExtras) {
+ // We're only ever invoked when the callback is done, so release the lock.
+ synchronized (mLock) {
+ mWakelock.release();
+ }
+ }
+ };
+
public final class LocalSoundTriggerService extends SoundTriggerInternal {
private final Context mContext;
private SoundTriggerHelper mSoundTriggerHelper;
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 640c9e1..de205380 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -325,7 +325,8 @@
return sEventManager;
}
- private static SessionManager getSessionManager() {
+ @VisibleForTesting
+ public static SessionManager getSessionManager() {
// Checking for null again outside of synchronization because we only need to synchronize
// during the lazy loading of the session logger. We don't need to synchronize elsewhere.
if (sSessionManager == null) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 331328d..b1eedf5 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -369,6 +369,15 @@
public static final String EXTRA_IS_HANDOVER = "android.telecom.extra.IS_HANDOVER";
/**
+ * Parcelable extra used with {@link #EXTRA_IS_HANDOVER} to indicate the source
+ * {@link PhoneAccountHandle} when initiating a handover which {@link ConnectionService}
+ * the handover is from.
+ * @hide
+ */
+ public static final String EXTRA_HANDOVER_FROM_PHONE_ACCOUNT =
+ "android.telecom.extra.HANDOVER_FROM_PHONE_ACCOUNT";
+
+ /**
* Extra key specified in the {@link ConnectionRequest#getExtras()} when Telecom calls
* {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
* to inform the {@link ConnectionService} what the initial {@link CallAudioState} of the
diff --git a/tests/JobSchedulerTestApp/res/layout/activity_main.xml b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
index 96e1641..41f9777 100644
--- a/tests/JobSchedulerTestApp/res/layout/activity_main.xml
+++ b/tests/JobSchedulerTestApp/res/layout/activity_main.xml
@@ -73,10 +73,18 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
+ <RadioButton android:id="@+id/checkbox_none"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/none"/>
<RadioButton android:id="@+id/checkbox_any"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/any"/>
+ <RadioButton android:id="@+id/checkbox_metered"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/metered"/>
<RadioButton android:id="@+id/checkbox_unmetered"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/tests/JobSchedulerTestApp/res/values/strings.xml b/tests/JobSchedulerTestApp/res/values/strings.xml
index 90dd2b6..866b61e 100644
--- a/tests/JobSchedulerTestApp/res/values/strings.xml
+++ b/tests/JobSchedulerTestApp/res/values/strings.xml
@@ -30,7 +30,9 @@
<string name="persisted_caption">Persisted:</string>
<string name="constraints">Constraints</string>
<string name="connectivity">Connectivity:</string>
+ <string name="none">None</string>
<string name="any">Any</string>
+ <string name="metered">Metered</string>
<string name="unmetered">WiFi</string>
<string name="timing">Timing:</string>
<string name="delay">Delay:</string>
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
index 51cdbb5..3dfdba7 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java
@@ -63,6 +63,7 @@
mDeadlineEditText = findViewById(R.id.deadline_time);
mWiFiConnectivityRadioButton = findViewById(R.id.checkbox_unmetered);
mAnyConnectivityRadioButton = findViewById(R.id.checkbox_any);
+ mCellConnectivityRadioButton = findViewById(R.id.checkbox_metered);
mRequiresChargingCheckBox = findViewById(R.id.checkbox_charging);
mRequiresIdleCheckbox = findViewById(R.id.checkbox_idle);
mIsPersistedCheckbox = findViewById(R.id.checkbox_persisted);
@@ -85,6 +86,7 @@
EditText mDeadlineEditText;
RadioButton mWiFiConnectivityRadioButton;
RadioButton mAnyConnectivityRadioButton;
+ RadioButton mCellConnectivityRadioButton;
CheckBox mRequiresChargingCheckBox;
CheckBox mRequiresIdleCheckbox;
CheckBox mIsPersistedCheckbox;
@@ -141,9 +143,12 @@
builder.setOverrideDeadline(Long.parseLong(deadline) * 1000);
}
boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked();
+ boolean requiresMetered = mCellConnectivityRadioButton.isChecked();
boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked();
if (requiresUnmetered) {
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
+ } else if (requiresMetered) {
+ builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED);
} else if (requiresAnyConnectivity) {
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
}
diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
index 9df11fe..b698a3a 100644
--- a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
+++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java
@@ -81,7 +81,8 @@
@Override
public boolean onStartJob(JobParameters params) {
- Log.i(TAG, "on start job: " + params.getJobId());
+ Log.i(TAG, "on start job: " + params.getJobId()
+ + " deadline?=" + params.isOverrideDeadlineExpired());
currentId++;
jobParamsMap.put(currentId, params);
final int currId = this.currentId;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 088cbc6..7972d06 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -19,6 +19,7 @@
import android.content.pm.ParceledListSlice;
+import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.WifiConfiguration;
@@ -61,6 +62,8 @@
WifiConfiguration getMatchingWifiConfig(in ScanResult scanResult);
+ List<OsuProvider> getMatchingOsuProviders(in ScanResult scanResult);
+
int addOrUpdateNetwork(in WifiConfiguration config);
boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c89a9a4..ec8d91b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -30,6 +30,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.os.Binder;
import android.os.Build;
@@ -1000,11 +1001,9 @@
/**
* Returns a WifiConfiguration matching this ScanResult
*
- * An {@link UnsupportedOperationException} will be thrown if Passpoint is not enabled
- * on the device.
- *
* @param scanResult scanResult that represents the BSSID
* @return {@link WifiConfiguration} that matches this BSSID or null
+ * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
* @hide
*/
public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
@@ -1016,6 +1015,24 @@
}
/**
+ * Returns a list of Hotspot 2.0 OSU (Online Sign-Up) providers associated with the given AP.
+ *
+ * An empty list will be returned if no match is found.
+ *
+ * @param scanResult scanResult that represents the BSSID
+ * @return list of {@link OsuProvider}
+ * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+ * @hide
+ */
+ public List<OsuProvider> getMatchingOsuProviders(ScanResult scanResult) {
+ try {
+ return mService.getMatchingOsuProviders(scanResult);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Add a new network description to the set of configured networks.
* The {@code networkId} field of the supplied configuration object
* is ignored.