Merge "Adds silence toggle to notification settings."
diff --git a/api/system-current.txt b/api/system-current.txt
index da1adac..237d4c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1052,6 +1052,7 @@
field public static final java.lang.String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE";
field public static final java.lang.String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
field public static final java.lang.String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
+ field public static final java.lang.String ACTION_MANAGE_APP_PERMISSION = "android.intent.action.MANAGE_APP_PERMISSION";
field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
@@ -2719,6 +2720,7 @@
public class LocationManager {
method public deprecated boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
method public deprecated boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+ method public android.app.PendingIntent createManageLocationPermissionIntent(java.lang.String, java.lang.String);
method public void flushGnssBatch();
method public int getGnssBatchSize();
method public java.lang.String getNetworkProviderPackage();
@@ -3645,9 +3647,9 @@
method public boolean isPortableHotspotSupported();
method public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
- method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
method public boolean isWpa3SaeSupported();
method public boolean isWpa3SuiteBSupported();
+ method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method public boolean startScan(android.os.WorkSource);
method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 0d9a393..f11b49d 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1361,15 +1361,11 @@
Landroid/security/IKeystoreService;->generateKey(Ljava/lang/String;Landroid/security/keymaster/KeymasterArguments;[BIILandroid/security/keymaster/KeyCharacteristics;)I
Landroid/security/IKeystoreService;->get(Ljava/lang/String;I)[B
Landroid/security/IKeystoreService;->getState(I)I
-Landroid/security/IKeystoreService;->get_pubkey(Ljava/lang/String;)[B
-Landroid/security/IKeystoreService;->import_key(Ljava/lang/String;[BII)I
Landroid/security/IKeystoreService;->insert(Ljava/lang/String;[BII)I
Landroid/security/IKeystoreService;->is_hardware_backed(Ljava/lang/String;)I
Landroid/security/IKeystoreService;->list(Ljava/lang/String;I)[Ljava/lang/String;
Landroid/security/IKeystoreService;->reset()I
-Landroid/security/IKeystoreService;->sign(Ljava/lang/String;[B)[B
Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I
-Landroid/security/IKeystoreService;->verify(Ljava/lang/String;[B[B)I
Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V
Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V
Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B
diff --git a/config/preloaded-classes b/config/preloaded-classes
index b6bff9c..22fc5e8 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -3240,7 +3240,7 @@
android.view.FocusFinder$FocusSorter
android.view.FocusFinder$UserSpecifiedFocusComparator
android.view.FocusFinder$UserSpecifiedFocusComparator$NextFocusGetter
-android.view.FrameInfo
+android.graphics.FrameInfo
android.view.FrameMetrics
android.view.FrameMetricsObserver
android.view.FrameStats
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9079f1a..805fb68 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -72,6 +72,7 @@
import android.database.sqlite.SQLiteDebug.DbStats;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.HardwareRenderer;
import android.graphics.ImageDecoder;
import android.hardware.display.DisplayManagerGlobal;
import android.net.ConnectivityManager;
@@ -5652,7 +5653,7 @@
int uid = Process.myUid();
String[] packages = getPackageManager().getPackagesForUid(uid);
if (packages != null) {
- ThreadedRenderer.setupDiskCache(codeCacheDir);
+ HardwareRenderer.setupDiskCache(codeCacheDir);
RenderScriptCacheDir.setupDiskCache(codeCacheDir);
}
} catch (RemoteException e) {
@@ -5887,7 +5888,8 @@
// Allow renderer debugging features if we're debuggable.
boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- ThreadedRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE);
+ HardwareRenderer.setDebuggingEnabled(isAppDebuggable || Build.IS_DEBUGGABLE);
+ HardwareRenderer.setPackageName(data.appInfo.packageName);
/**
* Initialize the default http proxy in this process for the reasons we set the time zone.
@@ -5954,7 +5956,7 @@
StrictMode.setThreadPolicyMask(oldMask);
}
} else {
- ThreadedRenderer.setIsolatedProcess(true);
+ HardwareRenderer.setIsolatedProcess(true);
}
// If we use profiles, setup the dex reporter to notify package manager
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 1e2244e..a9819fc 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -28,7 +28,9 @@
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.pm.ParceledListSlice;
+import android.database.ContentObserver;
import android.media.AudioAttributes.AttributeUsage;
+import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@@ -36,6 +38,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.ArrayMap;
import com.android.internal.app.IAppOpsActiveCallback;
@@ -50,6 +53,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* API for interacting with "application operation" tracking.
@@ -1608,9 +1612,56 @@
* @hide
*/
public static int opToDefaultMode(int op) {
+ // STOPSHIP b/118520006: Hardcode the default values once the feature is stable.
+ switch (op) {
+ // SMS permissions
+ case AppOpsManager.OP_SEND_SMS:
+ case AppOpsManager.OP_RECEIVE_SMS:
+ case AppOpsManager.OP_READ_SMS:
+ case AppOpsManager.OP_RECEIVE_WAP_PUSH:
+ case AppOpsManager.OP_RECEIVE_MMS:
+ case AppOpsManager.OP_READ_CELL_BROADCASTS:
+ // CallLog permissions
+ case AppOpsManager.OP_READ_CALL_LOG:
+ case AppOpsManager.OP_WRITE_CALL_LOG:
+ case AppOpsManager.OP_PROCESS_OUTGOING_CALLS: {
+ if (sSmsAndCallLogRestrictionEnabled.get() < 0) {
+ startWatchingSmsRestrictionEnabled();
+ }
+ if (sSmsAndCallLogRestrictionEnabled.get() == 1) {
+ return AppOpsManager.MODE_DEFAULT;
+ }
+ }
+ }
return sOpDefaultMode[op];
}
+ // STOPSHIP b/118520006: Hardcode the default values once the feature is stable.
+ private static final AtomicInteger sSmsAndCallLogRestrictionEnabled = new AtomicInteger(-1);
+
+ // STOPSHIP b/118520006: Hardcode the default values once the feature is stable.
+ private static void startWatchingSmsRestrictionEnabled() {
+ final Context context = ActivityThread.currentApplication();
+ if (context == null) {
+ // Should never happen
+ return;
+ }
+
+ sSmsAndCallLogRestrictionEnabled.set(ActivityThread.currentActivityThread()
+ .getIntCoreSetting(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0));
+
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED);
+ context.getContentResolver().registerContentObserver(uri, false, new ContentObserver(
+ context.getMainThreadHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ sSmsAndCallLogRestrictionEnabled.set(Settings.Global.getInt(
+ context.getContentResolver(),
+ Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0));
+ }
+ });
+ }
+
/**
* Retrieve the default mode for the app op.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6c0fa4c..aa34da8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1753,6 +1753,30 @@
"android.intent.action.MANAGE_APP_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage a specific permissions of an app.
+ * <p>
+ * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose permission
+ * will be managed by the launched UI.
+ * </p>
+ * <p>
+ * Input: {@link #EXTRA_PERMISSION_NAME} specifies the (individual) permission
+ * that should be managed by the launched UI.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @see #EXTRA_PACKAGE_NAME
+ * @see #EXTRA_PERMISSION_NAME
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_APP_PERMISSION =
+ "android.intent.action.MANAGE_APP_PERMISSION";
+
+ /**
* Activity action: Launch UI to manage permissions.
* <p>
* Input: Nothing.
@@ -1882,8 +1906,8 @@
/**
* Activity action: Launch UI to manage which apps have a given permission.
* <p>
- * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
- * to which will be managed by the launched UI.
+ * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission group
+ * which will be managed by the launched UI.
* </p>
* <p>
* Output: Nothing.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8e4de9f..7a444e0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9174,6 +9174,13 @@
public static final String DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT
= "enable_freeform_support";
+ /**
+ * Whether to enable experimental desktop mode on secondary displays.
+ * @hide
+ */
+ public static final String DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS =
+ "force_desktop_mode_on_external_displays";
+
/**
* Whether user has enabled development settings.
*/
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b047ef7..67505e5 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -45,7 +45,7 @@
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put("settings_dynamic_homepage", "false");
- DEFAULT_FLAGS.put("settings_mobile_network_v2", "false");
+ DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index a872776..96ef8ba 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -21,6 +21,7 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.graphics.FrameInfo;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Build;
import android.os.Handler;
diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java
index 597089b..0f38e84 100644
--- a/core/java/android/view/FrameMetricsObserver.java
+++ b/core/java/android/view/FrameMetricsObserver.java
@@ -40,8 +40,9 @@
@UnsupportedAppUsage
private FrameMetrics mFrameMetrics;
- /* package */ Window.OnFrameMetricsAvailableListener mListener;
- /* package */ VirtualRefBasePtr mNative;
+ /* pacage */ Window.OnFrameMetricsAvailableListener mListener;
+ /** @hide */
+ public VirtualRefBasePtr mNative;
/**
* Creates a FrameMetricsObserver
diff --git a/core/java/android/view/TextureLayer.java b/core/java/android/view/TextureLayer.java
index d89d634..46dd436 100644
--- a/core/java/android/view/TextureLayer.java
+++ b/core/java/android/view/TextureLayer.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.graphics.Bitmap;
+import android.graphics.HardwareRenderer;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.SurfaceTexture;
@@ -32,10 +33,10 @@
* @hide
*/
public final class TextureLayer {
- private ThreadedRenderer mRenderer;
+ private HardwareRenderer mRenderer;
private VirtualRefBasePtr mFinalizer;
- private TextureLayer(ThreadedRenderer renderer, long deferredUpdater) {
+ private TextureLayer(HardwareRenderer renderer, long deferredUpdater) {
if (renderer == null || deferredUpdater == 0) {
throw new IllegalArgumentException("Either hardware renderer: " + renderer
+ " or deferredUpdater: " + deferredUpdater + " is invalid");
@@ -139,7 +140,8 @@
mRenderer.pushLayerUpdate(this);
}
- static TextureLayer adoptTextureLayer(ThreadedRenderer renderer, long layer) {
+ /** @hide */
+ public static TextureLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
return new TextureLayer(renderer, layer);
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f0f4c1c..bac0154 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,36 +16,24 @@
package android.view;
-import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
-import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
+import android.graphics.HardwareRenderer;
import android.graphics.Point;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Trace;
-import android.util.Log;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
import android.view.animation.AnimationUtils;
import com.android.internal.R;
-import com.android.internal.util.VirtualRefBasePtr;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
/**
* Threaded renderer that proxies the rendering to a render thread. Most calls
@@ -66,15 +54,7 @@
*
* @hide
*/
-public final class ThreadedRenderer {
- private static final String LOG_TAG = "ThreadedRenderer";
-
- /**
- * Name of the file that holds the shaders cache.
- */
- private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
- private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
-
+public final class ThreadedRenderer extends HardwareRenderer {
/**
* System property used to enable or disable threaded rendering profiling.
* The default value of this property is assumed to be false.
@@ -271,21 +251,6 @@
}
/**
- * Sets the directory to use as a persistent storage for threaded rendering
- * resources.
- *
- * @param cacheDir A directory the current process can write to
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static void setupDiskCache(File cacheDir) {
- ThreadedRenderer.setupShadersDiskCache(
- new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
- new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
- }
-
- /**
* Creates a threaded renderer using OpenGL.
*
* @param translucent True if the surface is translucent, false otherwise
@@ -300,55 +265,10 @@
return renderer;
}
- /**
- * Invoke this method when the system is running out of memory. This
- * method will attempt to recover as much memory as possible, based on
- * the specified hint.
- *
- * @param level Hint about the amount of memory that should be trimmed,
- * see {@link android.content.ComponentCallbacks}
- */
- public static void trimMemory(int level) {
- nTrimMemory(level);
- }
-
- public static void overrideProperty(@NonNull String name, @NonNull String value) {
- if (name == null || value == null) {
- throw new IllegalArgumentException("name and value must be non-null");
- }
- nOverrideProperty(name, value);
- }
-
- // Keep in sync with DrawFrameTask.h SYNC_* flags
- // Nothing interesting to report
- private static final int SYNC_OK = 0;
- // Needs a ViewRoot invalidate
- private static final int SYNC_INVALIDATE_REQUIRED = 1 << 0;
- // Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
- private static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1;
- // setStopped is true, drawing is false
- // TODO: Remove this and SYNC_LOST_SURFACE_REWARD_IF_FOUND?
- // This flag isn't really used as there's nothing that we care to do
- // in response, so it really just exists to differentiate from LOST_SURFACE
- // but possibly both can just be deleted.
- private static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2;
- private static final int SYNC_FRAME_DROPPED = 1 << 3;
-
private static final String[] VISUALIZERS = {
PROFILE_PROPERTY_VISUALIZE_BARS,
};
- private static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
- private static final int FLAG_DUMP_RESET = 1 << 1;
- private static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS;
-
- @IntDef(flag = true, prefix = { "FLAG_DUMP_" }, value = {
- FLAG_DUMP_FRAMESTATS,
- FLAG_DUMP_RESET
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface DumpFlags {}
-
// Size of the rendered content.
private int mWidth, mHeight;
@@ -362,51 +282,37 @@
// Whether the surface has insets. Used to protect opacity.
private boolean mHasInsets;
- // Light and shadow properties specified by the theme.
+ // Light properties specified by the theme.
private final float mLightY;
private final float mLightZ;
private final float mLightRadius;
- private final int mAmbientShadowAlpha;
- private final int mSpotShadowAlpha;
- private long mNativeProxy;
private boolean mInitialized = false;
- private RenderNode mRootNode;
private boolean mRootNodeNeedsUpdate;
private boolean mEnabled;
private boolean mRequested = true;
- private boolean mIsOpaque = false;
ThreadedRenderer(Context context, boolean translucent, String name) {
+ super();
+ setName(name);
+ setOpaque(!translucent);
+
final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
- mAmbientShadowAlpha =
- (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
- mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
+ float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
+ float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
a.recycle();
-
- long rootNodePtr = nCreateRootRenderNode();
- mRootNode = RenderNode.adopt(rootNodePtr);
- mRootNode.setClipToBounds(false);
- mIsOpaque = !translucent;
- mNativeProxy = nCreateProxy(translucent, rootNodePtr);
- nSetName(mNativeProxy, name);
-
- ProcessInitializer.sInstance.init(context, mNativeProxy);
-
- loadSystemProperties();
+ setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha);
}
- /**
- * Destroys the threaded rendering context.
- */
- void destroy() {
+ @Override
+ public void destroy() {
mInitialized = false;
updateEnabledState(null);
- nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
+ super.destroy();
}
/**
@@ -464,7 +370,7 @@
boolean status = !mInitialized;
mInitialized = true;
updateEnabledState(surface);
- nInitialize(mNativeProxy, surface);
+ setSurface(surface);
return status;
}
@@ -505,26 +411,18 @@
*/
void updateSurface(Surface surface) throws OutOfResourcesException {
updateEnabledState(surface);
- nUpdateSurface(mNativeProxy, surface);
+ setSurface(surface);
}
- /**
- * Halts any current rendering into the surface. Use this if it is unclear whether
- * or not the surface used by the ThreadedRenderer will be changing. It
- * Suspends any rendering into the surface, but will not do any destruction.
- *
- * Any subsequent draws will override the pause, resuming normal operation.
- */
- boolean pauseSurface(Surface surface) {
- return nPauseSurface(mNativeProxy, surface);
- }
-
- /**
- * Hard stops or resumes rendering into the surface. This flag is used to
- * determine whether or not it is safe to use the given surface *at all*
- */
- void setStopped(boolean stopped) {
- nSetStopped(mNativeProxy, stopped);
+ @Override
+ public void setSurface(Surface surface) {
+ // TODO: Do we ever pass a non-null but isValid() = false surface?
+ // This is here to be super conservative for ViewRootImpl
+ if (surface != null && surface.isValid()) {
+ super.setSurface(surface);
+ } else {
+ super.setSurface(null);
+ }
}
/**
@@ -535,7 +433,7 @@
*/
void destroyHardwareResources(View view) {
destroyResources(view);
- nDestroyHardwareResources(mNativeProxy);
+ destroyHardwareResources();
}
private static void destroyResources(View view) {
@@ -543,14 +441,6 @@
}
/**
- * Detaches the layer's surface texture from the GL context and releases
- * the texture id
- */
- void detachSurfaceTexture(long hardwareLayer) {
- nDetachSurfaceTexture(mNativeProxy, hardwareLayer);
- }
-
- /**
* Sets up the renderer for drawing.
*
* @param width The width of the drawing surface.
@@ -581,8 +471,6 @@
}
mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
- nSetup(mNativeProxy, mLightRadius,
- mAmbientShadowAlpha, mSpotShadowAlpha);
setLightCenter(attachInfo);
}
@@ -598,27 +486,7 @@
attachInfo.mDisplay.getRealSize(displaySize);
final float lightX = displaySize.x / 2f - attachInfo.mWindowLeft;
final float lightY = mLightY - attachInfo.mWindowTop;
-
- nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ);
- }
-
- /**
- * Change the ThreadedRenderer's opacity
- */
- void setOpaque(boolean opaque) {
- mIsOpaque = opaque && !mHasInsets;
- nSetOpaque(mNativeProxy, mIsOpaque);
- }
-
- boolean isOpaque() {
- return mIsOpaque;
- }
-
- /**
- * Enable/disable wide gamut rendering on this renderer.
- */
- void setWideGamut(boolean wideGamut) {
- nSetWideGamut(mNativeProxy, wideGamut);
+ setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius);
}
/**
@@ -663,18 +531,12 @@
break;
}
}
- nDumpProfileInfo(mNativeProxy, fd, flags);
+ dumpProfileInfo(fd, flags);
}
- /**
- * Loads system properties used by the renderer. This method is invoked
- * whenever system properties are modified. Implementations can use this
- * to trigger live updates of the renderer based on properties.
- *
- * @return True if a property has changed.
- */
- boolean loadSystemProperties() {
- boolean changed = nLoadSystemProperties(mNativeProxy);
+ @Override
+ public boolean loadSystemProperties() {
+ boolean changed = super.loadSystemProperties();
if (changed) {
invalidateRoot();
}
@@ -695,72 +557,27 @@
updateViewTreeDisplayList(view);
if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
- RecordingCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
+ RecordingCanvas canvas = mRootNode.startRecording(mSurfaceWidth, mSurfaceHeight);
try {
final int saveCount = canvas.save();
canvas.translate(mInsetLeft, mInsetTop);
callbacks.onPreDraw(canvas);
- canvas.insertReorderBarrier();
+ canvas.enableZ();
canvas.drawRenderNode(view.updateDisplayListIfDirty());
- canvas.insertInorderBarrier();
+ canvas.disableZ();
callbacks.onPostDraw(canvas);
canvas.restoreToCount(saveCount);
mRootNodeNeedsUpdate = false;
} finally {
- mRootNode.end(canvas);
+ mRootNode.endRecording();
}
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
/**
- * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the
- * rendernode of the UI thread.
- * @param node The node to add.
- * @param placeFront If true, the render node will be placed in front of the content node,
- * otherwise behind the content node.
- */
- @UnsupportedAppUsage
- public void addRenderNode(RenderNode node, boolean placeFront) {
- nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront);
- }
-
- /**
- * Only especially added render nodes can be removed.
- * @param node The node which was added via addRenderNode which should get removed again.
- */
- @UnsupportedAppUsage
- public void removeRenderNode(RenderNode node) {
- nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode);
- }
-
- /**
- * Draws a particular render node. If the node is not the content node, only the additional
- * nodes will get drawn and the content remains untouched.
- * @param node The node to be drawn.
- */
- @UnsupportedAppUsage
- public void drawRenderNode(RenderNode node) {
- nDrawRenderNode(mNativeProxy, node.mNativeRenderNode);
- }
-
- /**
- * To avoid unnecessary overdrawing of the main content all additionally passed render nodes
- * will be prevented to overdraw this area. It will be synchronized with the draw call.
- * This should be updated in the content view's draw call.
- * @param left The left side of the protected bounds.
- * @param top The top side of the protected bounds.
- * @param right The right side of the protected bounds.
- * @param bottom The bottom side of the protected bounds.
- */
- @UnsupportedAppUsage
- public void setContentDrawBounds(int left, int top, int right, int bottom) {
- nSetContentDrawBounds(mNativeProxy, left, top, right, bottom);
- }
-
- /**
* Interface used to receive callbacks whenever a view is drawn by
* a threaded renderer instance.
*/
@@ -819,11 +636,10 @@
attachInfo.mPendingAnimatingRenderNodes = null;
}
- final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
if (frameDrawingCallback != null) {
- nSetFrameCallback(mNativeProxy, frameDrawingCallback);
+ setFrameCallback(frameDrawingCallback);
}
- int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
+ int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
setEnabled(false);
attachInfo.mViewRootImpl.mSurface.release();
@@ -831,207 +647,40 @@
// if it is still needed or do nothing if we are no longer drawing
attachInfo.mViewRootImpl.invalidate();
}
- if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
+ if ((syncResult & SYNC_REDRAW_REQUESTED) != 0) {
attachInfo.mViewRootImpl.invalidate();
}
}
- void setFrameCompleteCallback(FrameCompleteCallback callback) {
- nSetFrameCompleteCallback(mNativeProxy, callback);
- }
-
- static void invokeFunctor(long functor, boolean waitForCompletion) {
- nInvokeFunctor(functor, waitForCompletion);
- }
-
- /**
- * Creates a new hardware layer. A hardware layer built by calling this
- * method will be treated as a texture layer, instead of as a render target.
- *
- * @return A hardware layer
- */
- TextureLayer createTextureLayer() {
- long layer = nCreateTextureLayer(mNativeProxy);
- return TextureLayer.adoptTextureLayer(this, layer);
- }
-
-
- void buildLayer(RenderNode node) {
- if (node.hasDisplayList()) {
- nBuildLayer(mNativeProxy, node.mNativeRenderNode);
- }
- }
-
-
- boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) {
- return nCopyLayerInto(mNativeProxy,
- layer.getDeferredLayerUpdater(), bitmap);
- }
-
- /**
- * Indicates that the specified hardware layer needs to be updated
- * as soon as possible.
- *
- * @param layer The hardware layer that needs an update
- */
- void pushLayerUpdate(TextureLayer layer) {
- nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
- }
-
- /**
- * Tells the HardwareRenderer that the layer is destroyed. The renderer
- * should remove the layer from any update queues.
- */
- void onLayerDestroyed(TextureLayer layer) {
- nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
- }
-
- /**
- * Blocks until all previously queued work has completed.
- */
- void fence() {
- nFence(mNativeProxy);
- }
-
- /**
- * Prevents any further drawing until draw() is called. This is a signal
- * that the contents of the RenderNode tree are no longer safe to play back.
- * In practice this usually means that there are Functor pointers in the
- * display list that are no longer valid.
- */
- void stopDrawing() {
- nStopDrawing(mNativeProxy);
- }
-
- /**
- * Called by {@link ViewRootImpl} when a new performTraverals is scheduled.
- */
- public void notifyFramePending() {
- nNotifyFramePending(mNativeProxy);
- }
-
-
- void registerAnimatingRenderNode(RenderNode animator) {
- nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
- }
-
- void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
- nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
- animator.getAnimatorNativePtr());
- }
-
- public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) {
- if (srcRect == null) {
- // Empty rect means entire surface
- return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap);
- } else {
- return nCopySurfaceInto(surface, srcRect.left, srcRect.top,
- srcRect.right, srcRect.bottom, bitmap);
- }
- }
-
- /**
- * Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given
- * RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and
- * not the RenderNode from a View.
- **/
- @UnsupportedAppUsage
- public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) {
- return nCreateHardwareBitmap(node.mNativeRenderNode, width, height);
- }
-
- /**
- * Sets whether or not high contrast text rendering is enabled. The setting is global
- * but only affects content rendered after the change is made.
- */
- public static void setHighContrastText(boolean highContrastText) {
- nSetHighContrastText(highContrastText);
- }
-
- /**
- * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source
- */
- public static void setIsolatedProcess(boolean isIsolated) {
- nSetIsolatedProcess(isIsolated);
- }
-
- /**
- * If set extra graphics debugging abilities will be enabled such as dumping skp
- */
- public static void setDebuggingEnabled(boolean enable) {
- nSetDebuggingEnabled(enable);
- }
-
- void allocateBuffers(Surface surface) {
- nAllocateBuffers(mNativeProxy, surface);
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- nDeleteProxy(mNativeProxy);
- mNativeProxy = 0;
- } finally {
- super.finalize();
- }
- }
-
/** The root of everything */
public @NonNull RenderNode getRootNode() {
return mRootNode;
}
- private boolean mForceDark = false;
-
- /**
- * Whether or not the force-dark feature should be used for this renderer.
- */
- public boolean setForceDark(boolean enable) {
- if (mForceDark != enable) {
- mForceDark = enable;
- nSetForceDark(mNativeProxy, enable);
- return true;
- }
- return false;
- }
-
/**
* Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
* TODO: deduplicate against ThreadedRenderer.
*
* @hide
*/
- public static class SimpleRenderer {
- private final RenderNode mRootNode;
- private long mNativeProxy;
- private final float mLightY, mLightZ;
- private Surface mSurface;
- private final FrameInfo mFrameInfo = new FrameInfo();
+ public static class SimpleRenderer extends HardwareRenderer {
+ private final float mLightY, mLightZ, mLightRadius;
public SimpleRenderer(final Context context, final String name, final Surface surface) {
+ super();
+ setName(name);
+ setOpaque(false);
+ setSurface(surface);
final TypedArray a = context.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
mLightY = a.getDimension(R.styleable.Lighting_lightY, 0);
mLightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
- final float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
+ mLightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
final int ambientShadowAlpha =
(int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
final int spotShadowAlpha =
(int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
a.recycle();
-
- final long rootNodePtr = nCreateRootRenderNode();
- mRootNode = RenderNode.adopt(rootNodePtr);
- mRootNode.setClipToBounds(false);
- mNativeProxy = nCreateProxy(true /* translucent */, rootNodePtr);
- nSetName(mNativeProxy, name);
-
- ProcessInitializer.sInstance.init(context, mNativeProxy);
- nLoadSystemProperties(mNativeProxy);
-
- nSetup(mNativeProxy, lightRadius, ambientShadowAlpha, spotShadowAlpha);
-
- mSurface = surface;
- nUpdateSurface(mNativeProxy, surface);
+ setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha);
}
/**
@@ -1045,7 +694,7 @@
final float lightX = displaySize.x / 2f - windowLeft;
final float lightY = mLightY - windowTop;
- nSetLightCenter(mNativeProxy, lightX, lightY, mLightZ);
+ setLightSourceGeometry(lightX, lightY, mLightZ, mLightRadius);
}
public RenderNode getRootNode() {
@@ -1057,222 +706,10 @@
*/
public void draw(final FrameDrawingCallback callback) {
final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L;
- mFrameInfo.setVsync(vsync, vsync);
- mFrameInfo.addFlags(1 << 2 /* VSYNC */);
if (callback != null) {
- nSetFrameCallback(mNativeProxy, callback);
+ setFrameCallback(callback);
}
- nSyncAndDrawFrame(mNativeProxy, mFrameInfo.mFrameInfo, mFrameInfo.mFrameInfo.length);
- }
-
- /**
- * Destroy the renderer.
- */
- public void destroy() {
- mSurface = null;
- nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- nDeleteProxy(mNativeProxy);
- mNativeProxy = 0;
- } finally {
- super.finalize();
- }
+ syncAndDrawFrame(vsync);
}
}
-
- /**
- * Interface used to receive callbacks when a frame is being drawn.
- */
- public interface FrameDrawingCallback {
- /**
- * Invoked during a frame drawing.
- *
- * @param frame The id of the frame being drawn.
- */
- void onFrameDraw(long frame);
- }
-
- /**
- * Interface used to be notified when a frame has finished rendering
- */
- public interface FrameCompleteCallback {
- /**
- * Invoked after a frame draw
- *
- * @param frameNr The id of the frame that was drawn.
- */
- void onFrameComplete(long frameNr);
- }
-
- private static class ProcessInitializer {
- static ProcessInitializer sInstance = new ProcessInitializer();
-
- private boolean mInitialized = false;
-
- private Context mAppContext;
- private IGraphicsStats mGraphicsStatsService;
- private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() {
- @Override
- public void onRotateGraphicsStatsBuffer() throws RemoteException {
- rotateBuffer();
- }
- };
-
- private ProcessInitializer() {}
-
- synchronized void init(Context context, long renderProxy) {
- if (mInitialized) return;
- mInitialized = true;
- mAppContext = context.getApplicationContext();
-
- initSched(renderProxy);
-
- if (mAppContext != null) {
- initGraphicsStats();
- }
- }
-
- private void initSched(long renderProxy) {
- try {
- int tid = nGetRenderThreadTid(renderProxy);
- ActivityManager.getService().setRenderThread(tid);
- } catch (Throwable t) {
- Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t);
- }
- }
-
- private void initGraphicsStats() {
- try {
- IBinder binder = ServiceManager.getService("graphicsstats");
- if (binder == null) return;
- mGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder);
- requestBuffer();
- } catch (Throwable t) {
- Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
- }
- }
-
- private void rotateBuffer() {
- nRotateProcessStatsBuffer();
- requestBuffer();
- }
-
- private void requestBuffer() {
- try {
- final String pkg = mAppContext.getApplicationInfo().packageName;
- ParcelFileDescriptor pfd = mGraphicsStatsService
- .requestBufferForProcess(pkg, mGraphicsStatsCallback);
- nSetProcessStatsBuffer(pfd.getFd());
- pfd.close();
- } catch (Throwable t) {
- Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
- }
- }
- }
-
- void addFrameMetricsObserver(FrameMetricsObserver observer) {
- long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
- observer.mNative = new VirtualRefBasePtr(nativeObserver);
- }
-
- void removeFrameMetricsObserver(FrameMetricsObserver observer) {
- nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
- observer.mNative = null;
- }
-
- /** b/68769804: For low FPS experiments. */
- public static void setFPSDivisor(int divisor) {
- nHackySetRTAnimationsEnabled(divisor <= 1);
- }
-
- /**
- * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be
- * called before any OpenGL context is created.
- *
- * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values.
- */
- public static void setContextPriority(int priority) {
- nSetContextPriority(priority);
- }
-
- /** Not actually public - internal use only. This doc to make lint happy */
- public static native void disableVsync();
-
- static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
-
- private static native void nRotateProcessStatsBuffer();
- private static native void nSetProcessStatsBuffer(int fd);
- private static native int nGetRenderThreadTid(long nativeProxy);
-
- private static native long nCreateRootRenderNode();
- private static native long nCreateProxy(boolean translucent, long rootRenderNode);
- private static native void nDeleteProxy(long nativeProxy);
-
- private static native boolean nLoadSystemProperties(long nativeProxy);
- private static native void nSetName(long nativeProxy, String name);
-
- private static native void nInitialize(long nativeProxy, Surface window);
- private static native void nUpdateSurface(long nativeProxy, Surface window);
- private static native boolean nPauseSurface(long nativeProxy, Surface window);
- private static native void nSetStopped(long nativeProxy, boolean stopped);
- private static native void nSetup(long nativeProxy,
- float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
- private static native void nSetLightCenter(long nativeProxy,
- float lightX, float lightY, float lightZ);
- private static native void nSetOpaque(long nativeProxy, boolean opaque);
- private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
- private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
- private static native void nDestroy(long nativeProxy, long rootRenderNode);
- private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
- private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator);
-
- private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
-
- private static native long nCreateTextureLayer(long nativeProxy);
- private static native void nBuildLayer(long nativeProxy, long node);
- private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
- private static native void nPushLayerUpdate(long nativeProxy, long layer);
- private static native void nCancelLayerUpdate(long nativeProxy, long layer);
- private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
-
- private static native void nDestroyHardwareResources(long nativeProxy);
- private static native void nTrimMemory(int level);
- private static native void nOverrideProperty(String name, String value);
-
- private static native void nFence(long nativeProxy);
- private static native void nStopDrawing(long nativeProxy);
- private static native void nNotifyFramePending(long nativeProxy);
-
- private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
- @DumpFlags int dumpFlags);
-
- private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
- boolean placeFront);
- private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
- private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
- private static native void nSetContentDrawBounds(long nativeProxy, int left,
- int top, int right, int bottom);
- private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
- private static native void nSetFrameCompleteCallback(long nativeProxy,
- FrameCompleteCallback callback);
-
- private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
- private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
-
- private static native int nCopySurfaceInto(Surface surface,
- int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap);
-
- private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
- private static native void nSetHighContrastText(boolean enabled);
- // For temporary experimentation b/66945974
- private static native void nHackySetRTAnimationsEnabled(boolean enabled);
- private static native void nSetDebuggingEnabled(boolean enabled);
- private static native void nSetIsolatedProcess(boolean enabled);
- private static native void nSetContextPriority(int priority);
- private static native void nAllocateBuffers(long nativeProxy, Surface window);
- private static native void nSetForceDark(long nativeProxy, boolean enabled);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index dd1f640..a23d68b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -46,6 +46,8 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.FrameInfo;
+import android.graphics.HardwareRenderer.FrameDrawingCallback;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
@@ -84,7 +86,6 @@
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl.Transaction;
-import android.view.ThreadedRenderer.FrameDrawingCallback;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
@@ -2148,7 +2149,7 @@
// relayoutWindow may decide to destroy mSurface. As that decision
// happens in WindowManager service, we need to be defensive here
// and stop using the surface in case it gets destroyed.
- if (mAttachInfo.mThreadedRenderer.pauseSurface(mSurface)) {
+ if (mAttachInfo.mThreadedRenderer.pause()) {
// Animations were running so we need to push a frame
// to resume them
mDirty.set(0, 0, mWidth, mHeight);
@@ -2266,7 +2267,7 @@
& View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
// Don't pre-allocate if transparent regions
// are requested as they may not be needed
- mAttachInfo.mThreadedRenderer.allocateBuffers(mSurface);
+ mAttachInfo.mThreadedRenderer.allocateBuffers();
}
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index f512ce4..b8139a7 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -556,18 +556,18 @@
proxy->setWideGamut(true);
}
proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
- proxy->initialize(surface);
+ proxy->setSurface(surface);
// Shadows can't be used via this interface, so just set the light source
// to all 0s.
- proxy->setup(0, 0, 0);
- proxy->setLightCenter((Vector3){0, 0, 0});
+ proxy->setLightAlpha(0, 0);
+ proxy->setLightGeometry((Vector3){0, 0, 0}, 0);
return (jlong) proxy;
}
static void setSurface(JNIEnv* env, jclass clazz, jlong rendererPtr, jlong surfacePtr) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr));
- proxy->updateSurface(surface);
+ proxy->setSurface(surface);
}
static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 7a5b604..702741e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -686,31 +686,20 @@
env->ReleaseStringUTFChars(jname, name);
}
-static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jobject jsurface) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
- proxy->initialize(surface);
-}
-
-static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
+static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
sp<Surface> surface;
if (jsurface) {
surface = android_view_Surface_getSurface(env, jsurface);
}
- proxy->updateSurface(surface);
+ proxy->setSurface(surface);
}
-static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jobject jsurface) {
+static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- sp<Surface> surface;
- if (jsurface) {
- surface = android_view_Surface_getSurface(env, jsurface);
- }
- return proxy->pauseSurface(surface);
+ return proxy->pause();
}
static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz,
@@ -719,16 +708,16 @@
proxy->setStopped(stopped);
}
-static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
- jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
+static void android_view_ThreadedRenderer_setLightAlpha(JNIEnv* env, jobject clazz, jlong proxyPtr,
+ jfloat ambientShadowAlpha, jfloat spotShadowAlpha) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha);
+ proxy->setLightAlpha((uint8_t) (255 * ambientShadowAlpha), (uint8_t) (255 * spotShadowAlpha));
}
-static void android_view_ThreadedRenderer_setLightCenter(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ) {
+static void android_view_ThreadedRenderer_setLightGeometry(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setLightCenter((Vector3){lightX, lightY, lightZ});
+ proxy->setLightGeometry((Vector3){lightX, lightY, lightZ}, lightRadius);
}
static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
@@ -990,13 +979,12 @@
{
ContextFactory factory;
RenderProxy proxy{true, renderNode, &factory};
- proxy.loadSystemProperties();
proxy.setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
- proxy.initialize(surface);
+ proxy.setSurface(surface);
// Shadows can't be used via this interface, so just set the light source
// to all 0s.
- proxy.setup(0, 0, 0);
- proxy.setLightCenter((Vector3){0, 0, 0});
+ proxy.setLightAlpha(0, 0);
+ proxy.setLightGeometry((Vector3){0, 0, 0}, 0);
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy.frameInfo())
.setVsync(vsync, vsync)
@@ -1058,10 +1046,9 @@
}
static void android_view_ThreadedRenderer_allocateBuffers(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jobject jsurface) {
+ jlong proxyPtr) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
- proxy->allocateBuffers(surface);
+ proxy->allocateBuffers();
}
static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz,
@@ -1118,7 +1105,7 @@
// JNI Glue
// ----------------------------------------------------------------------------
-const char* const kClassPathName = "android/view/ThreadedRenderer";
+const char* const kClassPathName = "android/graphics/HardwareRenderer";
static const JNINativeMethod gMethods[] = {
{ "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer },
@@ -1129,12 +1116,11 @@
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
{ "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
{ "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
- { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
- { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
- { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
+ { "nSetSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_setSurface },
+ { "nPause", "(J)Z", (void*) android_view_ThreadedRenderer_pause },
{ "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
- { "nSetup", "(JFII)V", (void*) android_view_ThreadedRenderer_setup },
- { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
+ { "nSetLightAlpha", "(JFF)V", (void*) android_view_ThreadedRenderer_setLightAlpha },
+ { "nSetLightGeometry", "(JFFFF)V", (void*) android_view_ThreadedRenderer_setLightGeometry },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
{ "nSetWideGamut", "(JZ)V", (void*) android_view_ThreadedRenderer_setWideGamut },
{ "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
@@ -1161,9 +1147,9 @@
{ "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
{ "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
{ "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
- { "nSetFrameCallback", "(JLandroid/view/ThreadedRenderer$FrameDrawingCallback;)V",
+ { "nSetFrameCallback", "(JLandroid/graphics/HardwareRenderer$FrameDrawingCallback;)V",
(void*)android_view_ThreadedRenderer_setFrameCallback},
- { "nSetFrameCompleteCallback", "(JLandroid/view/ThreadedRenderer$FrameCompleteCallback;)V",
+ { "nSetFrameCompleteCallback", "(JLandroid/graphics/HardwareRenderer$FrameCompleteCallback;)V",
(void*)android_view_ThreadedRenderer_setFrameCompleteCallback },
{ "nAddFrameMetricsObserver",
"(JLandroid/view/FrameMetricsObserver;)J",
@@ -1182,7 +1168,7 @@
{ "nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled },
{ "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
{ "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
- { "nAllocateBuffers", "(JLandroid/view/Surface;)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
+ { "nAllocateBuffers", "(J)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
{ "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },
};
@@ -1215,12 +1201,12 @@
env, metricsClass, "mTimingData", "[J");
jclass frameCallbackClass = FindClassOrDie(env,
- "android/view/ThreadedRenderer$FrameDrawingCallback");
+ "android/graphics/HardwareRenderer$FrameDrawingCallback");
gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
"onFrameDraw", "(J)V");
jclass frameCompleteClass = FindClassOrDie(env,
- "android/view/ThreadedRenderer$FrameCompleteCallback");
+ "android/graphics/HardwareRenderer$FrameCompleteCallback");
gFrameCompleteCallback.onFrameComplete = GetMethodIDOrDie(env, frameCompleteClass,
"onFrameComplete", "(J)V");
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 69ebb59..e0e7b6f 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -270,6 +270,7 @@
optional SettingProto enable_freeform_windows_support = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto force_rtl = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto emulate_display_cutout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto force_desktop_mode_on_external_displays = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Development development = 39;
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index 36efd0a..c26bebe 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -33,7 +33,7 @@
<item>LPP_PROFILE=3</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc221/config.xml b/core/res/res/values-mcc302-mnc221/config.xml
index a11dd95..96338b58 100644
--- a/core/res/res/values-mcc302-mnc221/config.xml
+++ b/core/res/res/values-mcc302-mnc221/config.xml
@@ -30,7 +30,7 @@
<item>LPP_PROFILE=3</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
index 8d29ec1..79f4bb6 100644
--- a/core/res/res/values-mcc302-mnc370/config.xml
+++ b/core/res/res/values-mcc302-mnc370/config.xml
@@ -34,7 +34,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
index 650aa62..10b007e 100644
--- a/core/res/res/values-mcc302-mnc610/config.xml
+++ b/core/res/res/values-mcc302-mnc610/config.xml
@@ -32,7 +32,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
index 4bb68dc..657d1e7 100644
--- a/core/res/res/values-mcc302-mnc640/config.xml
+++ b/core/res/res/values-mcc302-mnc640/config.xml
@@ -28,7 +28,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
index 735a8c8..ba8c75a 100644
--- a/core/res/res/values-mcc302-mnc720/config.xml
+++ b/core/res/res/values-mcc302-mnc720/config.xml
@@ -34,7 +34,7 @@
<item>LPP_PROFILE=2</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a8c78a6..bca72f4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2793,7 +2793,7 @@
<item>LPP_PROFILE=0</item>
<item>USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=1</item>
<item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>GPS_LOCK=0</item>
+ <item>GPS_LOCK=3</item>
</string-array>
<!-- Sprint need a 70 ms delay for 3way call -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8d3992d..200c35d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -248,6 +248,10 @@
<item>@string/wfcSpnFormat_spn_wifi</item>
<item>@string/wfcSpnFormat_wifi_calling_bar_spn</item>
<item>@string/wfcSpnFormat_spn_vowifi</item>
+ <item>@string/wfcSpnFormat_wifi_calling</item>
+ <item>@string/wfcSpnFormat_wifi</item>
+ <item>@string/wfcSpnFormat_wifi_calling_wo_hyphen</item>
+ <item>@string/wfcSpnFormat_vowifi</item>
</string-array>
<!-- Spn during Wi-Fi Calling: "<operator>" -->
@@ -264,6 +268,14 @@
<string name="wfcSpnFormat_wifi_calling_bar_spn">WiFi Calling | <xliff:g id="spn" example="Operator">%s</xliff:g></string>
<!-- Spn during Wi-Fi Calling: "<operator> VoWifi" -->
<string name="wfcSpnFormat_spn_vowifi"><xliff:g id="spn" example="Operator">%s</xliff:g> VoWifi</string>
+ <!-- Spn during Wi-Fi Calling: "Wi-Fi Calling" -->
+ <string name="wfcSpnFormat_wifi_calling">Wi-Fi Calling</string>
+ <!-- Spn during Wi-Fi Calling: "Wi-Fi" -->
+ <string name="wfcSpnFormat_wifi">Wi-Fi</string>
+ <!-- Spn during Wi-Fi Calling: "WiFi Calling" (without hyphen) -->
+ <string name="wfcSpnFormat_wifi_calling_wo_hyphen">WiFi Calling</string>
+ <!-- Spn during Wi-Fi Calling: "VoWifi" -->
+ <string name="wfcSpnFormat_vowifi">VoWifi</string>
<!-- WFC, summary for Disabled -->
<string name="wifi_calling_off_summary">Off</string>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 3342266..63dd59a 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -197,6 +197,7 @@
Settings.Global.DESK_DOCK_SOUND,
Settings.Global.DESK_UNDOCK_SOUND,
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
+ Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
Settings.Global.DEVELOPMENT_FORCE_RTL,
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED,
diff --git a/core/java/android/view/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java
similarity index 70%
rename from core/java/android/view/FrameInfo.java
rename to graphics/java/android/graphics/FrameInfo.java
index 6c5e048..42a5cc4 100644
--- a/core/java/android/view/FrameInfo.java
+++ b/graphics/java/android/graphics/FrameInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view;
+package android.graphics;
import android.annotation.LongDef;
@@ -33,14 +33,14 @@
* long layout & measure took it's displayListRecordStart - performTraversalsStart.
*
* These constants must be kept in sync with FrameInfo.h in libhwui and are
- * used for indexing into AttachInfo's mFrameInfo long[], which is intended
+ * used for indexing into AttachInfo's frameInfo long[], which is intended
* to be quick to pass down to native via JNI, hence a pre-packed format
*
* @hide
*/
-final class FrameInfo {
+public final class FrameInfo {
- long[] mFrameInfo = new long[9];
+ public long[] frameInfo = new long[9];
// Various flags set to provide extra metadata about the current frame
private static final int FLAGS = 0;
@@ -48,8 +48,11 @@
// Is this the first-draw following a window layout?
public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;
+ // A renderer associated with just a Surface, not with a ViewRootImpl instance.
+ public static final long FLAG_SURFACE_CANVAS = 1 << 2;
+
@LongDef(flag = true, value = {
- FLAG_WINDOW_LAYOUT_CHANGED })
+ FLAG_WINDOW_LAYOUT_CHANGED, FLAG_SURFACE_CANVAS })
@Retention(RetentionPolicy.SOURCE)
public @interface FrameInfoFlags {}
@@ -78,41 +81,48 @@
// When View:draw() started
private static final int DRAW_START = 8;
+ /** checkstyle */
public void setVsync(long intendedVsync, long usedVsync) {
- mFrameInfo[INTENDED_VSYNC] = intendedVsync;
- mFrameInfo[VSYNC] = usedVsync;
- mFrameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
- mFrameInfo[NEWEST_INPUT_EVENT] = 0;
- mFrameInfo[FLAGS] = 0;
+ frameInfo[INTENDED_VSYNC] = intendedVsync;
+ frameInfo[VSYNC] = usedVsync;
+ frameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
+ frameInfo[NEWEST_INPUT_EVENT] = 0;
+ frameInfo[FLAGS] = 0;
}
+ /** checkstyle */
public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) {
- if (inputEventOldestTime < mFrameInfo[OLDEST_INPUT_EVENT]) {
- mFrameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
+ if (inputEventOldestTime < frameInfo[OLDEST_INPUT_EVENT]) {
+ frameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
}
- if (inputEventTime > mFrameInfo[NEWEST_INPUT_EVENT]) {
- mFrameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
+ if (inputEventTime > frameInfo[NEWEST_INPUT_EVENT]) {
+ frameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
}
}
+ /** checkstyle */
public void markInputHandlingStart() {
- mFrameInfo[HANDLE_INPUT_START] = System.nanoTime();
+ frameInfo[HANDLE_INPUT_START] = System.nanoTime();
}
+ /** checkstyle */
public void markAnimationsStart() {
- mFrameInfo[ANIMATION_START] = System.nanoTime();
+ frameInfo[ANIMATION_START] = System.nanoTime();
}
+ /** checkstyle */
public void markPerformTraversalsStart() {
- mFrameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime();
+ frameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime();
}
+ /** checkstyle */
public void markDrawStart() {
- mFrameInfo[DRAW_START] = System.nanoTime();
+ frameInfo[DRAW_START] = System.nanoTime();
}
+ /** checkstyle */
public void addFlags(@FrameInfoFlags long flags) {
- mFrameInfo[FLAGS] |= flags;
+ frameInfo[FLAGS] |= flags;
}
}
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
new file mode 100644
index 0000000..e402055
--- /dev/null
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -0,0 +1,1030 @@
+/*
+ * Copyright (C) 2018 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.graphics;
+
+import android.annotation.FloatRange;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.FrameMetricsObserver;
+import android.view.IGraphicsStats;
+import android.view.IGraphicsStatsCallback;
+import android.view.NativeVectorDrawableAnimator;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.TextureLayer;
+
+import com.android.internal.util.VirtualRefBasePtr;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import sun.misc.Cleaner;
+
+/**
+ * <p>Creates an instance of a hardware-accelerated renderer. This is used to render a scene built
+ * from {@link RenderNode}'s to an output {@link android.view.Surface}. There can be as many
+ * HardwareRenderer instances as desired.</p>
+ *
+ * <h3>Threading</h3>
+ * <p>HardwareRenderer is not thread safe. An instance of a HardwareRenderer must only be
+ * created & used from a single thread. It does not matter what thread is used, however
+ * it must have a {@link android.os.Looper}. Multiple instances do not have to share the same
+ * thread, although they can.</p>
+ *
+ * <h3>Resources & lifecycle</h3>
+ * <p>All HardwareRenderer instances share a common render thread. The render thread contains
+ * the GPU context & resources necessary to do GPU-accelerated rendering. As such, the first
+ * HardwareRenderer created comes with the cost of also creating the associated GPU contexts,
+ * however each incremental HardwareRenderer thereafter is fairly cheap. The expected usage
+ * is to have a HardwareRenderer instance for every active {@link Surface}. For example
+ * when an Activity shows a Dialog the system internally will use 2 hardware renderers, both
+ * of which may be drawing at the same time.</p>
+ * <p>NOTE: Due to the shared, cooperative nature of the render thread it is critical that
+ * any {@link Surface} used must have a prompt, reliable consuming side. System-provided
+ * consumers such as {@link android.view.SurfaceView},
+ * {@link android.view.Window#takeSurface(SurfaceHolder.Callback2)},
+ * or {@link android.view.TextureView} all fit this requirement. However if custom consumers
+ * are used such as when using {@link SurfaceTexture} or {@link android.media.ImageReader}
+ * it is the app's responsibility to ensure that they consume updates promptly and rapidly.
+ * Failure to do so will cause the render thread to stall on that surface, blocking all
+ * HardwareRenderer instances.</p>
+ *
+ * @hide
+ */
+public class HardwareRenderer {
+ private static final String LOG_TAG = "HardwareRenderer";
+
+ // Keep in sync with DrawFrameTask.h SYNC_* flags
+ /**
+ * Nothing interesting to report. Sync & draw kicked off
+ */
+ public static final int SYNC_OK = 0;
+
+ /**
+ * The renderer is requesting a redraw. This can occur if there's an animation that's running
+ * in the RenderNode tree and the hardware renderer is unable to self-animate.
+ *
+ * If this is returned from syncAndDrawFrame the expectation is that syncAndDrawFrame
+ * will be called again on the next vsync signal.
+ */
+ public static final int SYNC_REDRAW_REQUESTED = 1 << 0;
+
+ /**
+ * The hardware renderer no longer has a valid {@link android.view.Surface} to render to.
+ * This can happen if {@link Surface#destroy()} was called. The user should no longer
+ * attempt to call syncAndDrawFrame until a new surface has been provided by calling
+ * setSurface.
+ *
+ * Spoiler: the reward is GPU-accelerated drawing, better find that Surface!
+ */
+ public static final int SYNC_LOST_SURFACE_REWARD_IF_FOUND = 1 << 1;
+
+ /**
+ * The hardware renderer has been set to a "stopped" state. If this is returned then the
+ * rendering content has been synced, however a frame was not produced.
+ */
+ public static final int SYNC_CONTEXT_IS_STOPPED = 1 << 2;
+
+ /**
+ * The content was synced but the renderer has declined to produce a frame in this vsync
+ * interval. This can happen if a frame was already drawn in this vsync or if the renderer
+ * is outrunning the frame consumer. The renderer will internally re-schedule itself
+ * to render a frame in the next vsync signal, so the caller does not need to do anything
+ * in response to this signal.
+ */
+ public static final int SYNC_FRAME_DROPPED = 1 << 3;
+
+ @IntDef(value = {
+ SYNC_OK, SYNC_REDRAW_REQUESTED, SYNC_LOST_SURFACE_REWARD_IF_FOUND,
+ SYNC_CONTEXT_IS_STOPPED, SYNC_FRAME_DROPPED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SyncAndDrawResult {
+ }
+
+ /** @hide */
+ public static final int FLAG_DUMP_FRAMESTATS = 1 << 0;
+ /** @hide */
+ public static final int FLAG_DUMP_RESET = 1 << 1;
+ /** @hide */
+ public static final int FLAG_DUMP_ALL = FLAG_DUMP_FRAMESTATS;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"FLAG_DUMP_"}, value = {
+ FLAG_DUMP_FRAMESTATS,
+ FLAG_DUMP_RESET
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DumpFlags {
+ }
+
+ /**
+ * Name of the file that holds the shaders cache.
+ */
+ private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
+ private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
+
+ private final long mNativeProxy;
+ /** @hide */
+ protected RenderNode mRootNode;
+ private boolean mOpaque = true;
+ private boolean mForceDark = false;
+ private FrameInfo mScratchInfo;
+
+ /**
+ * Creates a new instance of a HardwareRenderer. The HardwareRenderer will default
+ * to opaque with no light source configured.
+ */
+ public HardwareRenderer() {
+ mRootNode = RenderNode.adopt(nCreateRootRenderNode());
+ mRootNode.setClipToBounds(false);
+ mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);
+ if (mNativeProxy == 0) {
+ throw new OutOfMemoryError("Unable to create hardware renderer");
+ }
+ Cleaner.create(this, new DestroyContextRunnable(mNativeProxy));
+ ProcessInitializer.sInstance.init(mNativeProxy);
+ }
+
+ /**
+ * Destroys the rendering context of this HardwareRenderer. This destroys the resources
+ * associated with this renderer and releases the currently set {@link Surface}.
+ *
+ * The renderer may be restored from this state by setting a new {@link Surface}, setting
+ * new rendering content with {@link #setContentRoot(RenderNode)}, and resuming
+ * rendering with {@link #syncAndDrawFrame(long)}.
+ *
+ * It is suggested to call this in response to callbacks such as
+ * {@link android.view.SurfaceHolder.Callback#surfaceDestroyed(SurfaceHolder)}.
+ *
+ * Note that if there are any outstanding frame commit callbacks they may end up never being
+ * invoked if the frame was deferred to a later vsync.
+ */
+ public void destroy() {
+ nDestroy(mNativeProxy, mRootNode.mNativeRenderNode);
+ }
+
+ /**
+ * Sets a name for this renderer. This is used to identify this renderer instance
+ * when reporting debug information such as the per-window frame time metrics
+ * reported by 'adb shell dumpsys gfxinfo [package] framestats'
+ *
+ * @param name The debug name to use for this HardwareRenderer instance
+ */
+ public void setName(String name) {
+ nSetName(mNativeProxy, name);
+ }
+
+ /**
+ * Sets the center of the light source. The light source point controls the directionality
+ * and shape of shadows rendered by RenderNode Z & elevation.
+ *
+ * The platform's recommendation is to set lightX to 'displayWidth / 2f - windowLeft', set
+ * lightY to 0 - windowTop, lightZ set to 600dp, and lightRadius to 800dp.
+ *
+ * The light source should be setup both as part of initial configuration, and whenever
+ * the window moves to ensure the light source stays anchored in display space instead
+ * of in window space.
+ *
+ * This must be set at least once along with {@link #setLightSourceAlpha(float, float)}
+ * before shadows will work.
+ *
+ * @param lightX The X position of the light source
+ * @param lightY The Y position of the light source
+ * @param lightZ The Z position of the light source. Must be >= 0.
+ * @param lightRadius The radius of the light source. Smaller radius will have sharper edges,
+ * larger radius will have softer shadows.
+ */
+ public void setLightSourceGeometry(float lightX, float lightY, float lightZ,
+ float lightRadius) {
+ validateFinite(lightX, "lightX");
+ validateFinite(lightY, "lightY");
+ validatePositive(lightZ, "lightZ");
+ validatePositive(lightRadius, "lightRadius");
+ nSetLightGeometry(mNativeProxy, lightX, lightY, lightZ, lightRadius);
+ }
+
+ /**
+ * Configures the ambient & spot shadow alphas. This is the alpha used when the shadow
+ * has max alpha, and ramps down from the values provided to zero.
+ *
+ * These values are typically provided by the current theme, see
+ * {@link android.R.attr#spotShadowAlpha} and {@link android.R.attr#ambientShadowAlpha}.
+ *
+ * This must be set at least once along with
+ * {@link #setLightSourceGeometry(float, float, float, float)} before shadows will work.
+ *
+ * @param ambientShadowAlpha The alpha for the ambient shadow. If unsure, a reasonable default
+ * is 0.039f.
+ * @param spotShadowAlpha The alpha for the spot shadow. If unsure, a reasonable default is
+ * 0.19f.
+ */
+ public void setLightSourceAlpha(@FloatRange(from = 0.0f, to = 1.0f) float ambientShadowAlpha,
+ @FloatRange(from = 0.0f, to = 1.0f) float spotShadowAlpha) {
+ validateAlpha(ambientShadowAlpha, "ambientShadowAlpha");
+ validateAlpha(spotShadowAlpha, "spotShadowAlpha");
+ nSetLightAlpha(mNativeProxy, ambientShadowAlpha, spotShadowAlpha);
+ }
+
+ /**
+ * Sets the content root to render. It is not necessary to call this whenever the content
+ * recording changes. Any mutations to the RenderNode content, or any of the RenderNode's
+ * contained within the content node, will be applied whenever {@link #syncAndDrawFrame(long)}
+ * is called.
+ *
+ * @param content The content to set as the root RenderNode. If null the content root is removed
+ * and the renderer will draw nothing.
+ */
+ public void setContentRoot(@Nullable RenderNode content) {
+ RecordingCanvas canvas = mRootNode.startRecording();
+ if (content != null) {
+ canvas.drawRenderNode(content);
+ }
+ mRootNode.endRecording();
+ }
+
+ /**
+ * <p>The surface to render into. The surface is assumed to be associated with the display and
+ * as such is still driven by vsync signals such as those from
+ * {@link android.view.Choreographer} and that it has a native refresh rate matching that of
+ * the display's (typically 60hz).</p>
+ *
+ * <p>NOTE: Due to the shared, cooperative nature of the render thread it is critical that
+ * any {@link Surface} used must have a prompt, reliable consuming side. System-provided
+ * consumers such as {@link android.view.SurfaceView},
+ * {@link android.view.Window#takeSurface(SurfaceHolder.Callback2)},
+ * or {@link android.view.TextureView} all fit this requirement. However if custom consumers
+ * are used such as when using {@link SurfaceTexture} or {@link android.media.ImageReader}
+ * it is the app's responsibility to ensure that they consume updates promptly and rapidly.
+ * Failure to do so will cause the render thread to stall on that surface, blocking all
+ * HardwareRenderer instances.</p>
+ *
+ * @param surface The surface to render into. If null then rendering will be stopped. If
+ * non-null then {@link Surface#isValid()} must be true.
+ */
+ public void setSurface(@Nullable Surface surface) {
+ if (surface != null && !surface.isValid()) {
+ throw new IllegalArgumentException("Surface is invalid. surface.isValid() == false.");
+ }
+ nSetSurface(mNativeProxy, surface);
+ }
+
+ /**
+ * Syncs the RenderNode tree to the render thread and requests a frame to be drawn.
+ *
+ * @hide
+ */
+ @SyncAndDrawResult
+ public int syncAndDrawFrame(@NonNull FrameInfo frameInfo) {
+ return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo, frameInfo.frameInfo.length);
+ }
+
+ /**
+ * Syncs the RenderNode tree to the render thread and requests a frame to be drawn.
+ *
+ * @param vsyncTime The vsync timestamp for this frame. Typically this comes from
+ * {@link android.view.Choreographer.FrameCallback}. Must be set and be valid
+ * as the renderer uses this time internally to drive animations.
+ * @return The result of the sync operation. See {@link SyncAndDrawResult}.
+ */
+ @SyncAndDrawResult
+ public int syncAndDrawFrame(long vsyncTime) {
+ if (mScratchInfo == null) {
+ mScratchInfo = new FrameInfo();
+ }
+ mScratchInfo.setVsync(vsyncTime, vsyncTime);
+ mScratchInfo.addFlags(FrameInfo.FLAG_SURFACE_CANVAS);
+ return syncAndDrawFrame(mScratchInfo);
+ }
+
+ /**
+ * Syncs the RenderNode tree to the render thread and requests a frame to be drawn.
+ * frameCommitCallback callback will be invoked when the current rendering content has been
+ * rendered into a frame and submitted to the swap chain.
+ *
+ * @param vsyncTime The vsync timestamp for this frame. Typically this comes from
+ * {@link android.view.Choreographer.FrameCallback}. Must be set and
+ * be valid as the renderer uses this time internally to drive
+ * animations.
+ * @param frameCommitCallback The callback to invoke when the frame content has been drawn.
+ * Will be invoked on the current {@link android.os.Looper} thread.
+ * @return The result of the sync operation. See {@link SyncAndDrawResult}.
+ */
+ @SyncAndDrawResult
+ public int syncAndDrawFrame(long vsyncTime,
+ @Nullable Runnable frameCommitCallback) {
+ if (frameCommitCallback != null) {
+ setFrameCompleteCallback(frameNr -> frameCommitCallback.run());
+ }
+ return syncAndDrawFrame(vsyncTime);
+ }
+
+ /**
+ * Suspends any current rendering into the surface but do not do any destruction. This
+ * is useful to temporarily suspend using the active Surface in order to do any Surface
+ * mutations necessary.
+ *
+ * Any subsequent draws will override the pause, resuming normal operation.
+ *
+ * @return true if there was an outstanding render request, false otherwise. If this is true
+ * the caller should ensure that {@link #syncAndDrawFrame(long)} is called at the soonest
+ * possible time to resume normal operation.
+ *
+ * TODO Should this be exposed? ViewRootImpl needs it because it destroys the old
+ * Surface before getting a new one. However things like SurfaceView will ensure that
+ * the old surface remains un-destroyed until after a new frame has been produced with
+ * the new surface.
+ * @hide
+ */
+ public boolean pause() {
+ return nPause(mNativeProxy);
+ }
+
+ /**
+ * Hard stops rendering into the surface. If the renderer is stopped it will
+ * block any attempt to render. Calls to {@link #syncAndDrawFrame(long)} will still
+ * sync over the latest rendering content, however they will not render and instead
+ * {@link #SYNC_CONTEXT_IS_STOPPED} will be returned.
+ *
+ * If false is passed then rendering will resume as normal. Any pending rendering requests
+ * will produce a new frame at the next vsync signal.
+ *
+ * This is useful in combination with lifecycle events such as {@link Activity#onStop()}
+ * and {@link Activity#onStart()}.
+ *
+ * @param stopped true to stop all rendering, false to resume
+ */
+ public void setStopped(boolean stopped) {
+ nSetStopped(mNativeProxy, stopped);
+ }
+
+ /**
+ * Destroys all hardware rendering resources associated with the current rendering content.
+ * This includes releasing a reference to the current content root RenderNode. It will
+ * therefore be necessary to call {@link #setContentRoot(RenderNode)} in order to resume
+ * rendering after calling this.
+ *
+ * It is recommended, but not necessary, to use this in combination with lifecycle events
+ * such as {@link Activity#onStop()} and {@link Activity#onStart()} or in response to
+ * {@link android.content.ComponentCallbacks2#onTrimMemory(int)} signals such as
+ * {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
+ *
+ * See also {@link #setStopped(boolean)}
+ */
+ public void destroyHardwareResources() {
+ nDestroyHardwareResources(mNativeProxy);
+ }
+
+ /**
+ * Whether or not the force-dark feature should be used for this renderer.
+ */
+ public boolean setForceDark(boolean enable) {
+ if (mForceDark != enable) {
+ mForceDark = enable;
+ nSetForceDark(mNativeProxy, enable);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Allocate buffers ahead of time to avoid allocation delays during rendering.
+ *
+ * Typically a Surface will allocate buffers lazily. This is usually fine and reduces the
+ * memory usage of Surfaces that render rarely or never hit triple buffering. However
+ * for UI it can result in a slight bit of jank on first launch. This hint will
+ * tell the HardwareRenderer that now is a good time to allocate the 3 buffers
+ * necessary for typical rendering.
+ *
+ * Must be called after a {@link Surface} has been set.
+ */
+ public void allocateBuffers() {
+ nAllocateBuffers(mNativeProxy);
+ }
+
+ /**
+ * Notifies the hardware renderer that a call to {@link #syncAndDrawFrame(long)} will
+ * be coming soon. This is used to help schedule when RenderThread-driven animations will
+ * happen as the renderer wants to avoid producing more than one frame per vsync signal.
+ */
+ public void notifyFramePending() {
+ nNotifyFramePending(mNativeProxy);
+ }
+
+ /**
+ * Change the HardwareRenderer's opacity. Will take effect on the next frame produced.
+ *
+ * If the renderer is set to opaque it is the app's responsibility to ensure that the
+ * content renders to every pixel of the Surface, otherwise corruption may result. Note that
+ * this includes ensuring that the first draw of any given pixel does not attempt to blend
+ * against the destination. If this is false then the hardware renderer will clear to
+ * transparent at the start of every frame.
+ *
+ * @param opaque true if the content rendered is opaque, false if the renderer should clear
+ * to transparent before rendering
+ */
+ public void setOpaque(boolean opaque) {
+ if (mOpaque != opaque) {
+ mOpaque = opaque;
+ nSetOpaque(mNativeProxy, mOpaque);
+ }
+ }
+
+ /**
+ * Whether or not the renderer is set to be opaque. See {@link #setOpaque(boolean)}
+ *
+ * @return true if the renderer is opaque, false otherwise
+ */
+ public boolean isOpaque() {
+ return mOpaque;
+ }
+
+ /** @hide */
+ public void setFrameCompleteCallback(FrameCompleteCallback callback) {
+ nSetFrameCompleteCallback(mNativeProxy, callback);
+ }
+
+ /**
+ * TODO: Public API this?
+ *
+ * @hide
+ */
+ public void addFrameMetricsObserver(FrameMetricsObserver observer) {
+ long nativeObserver = nAddFrameMetricsObserver(mNativeProxy, observer);
+ observer.mNative = new VirtualRefBasePtr(nativeObserver);
+ }
+
+ /**
+ * TODO: Public API this?
+ *
+ * @hide
+ */
+ public void removeFrameMetricsObserver(FrameMetricsObserver observer) {
+ nRemoveFrameMetricsObserver(mNativeProxy, observer.mNative.get());
+ observer.mNative = null;
+ }
+
+ /**
+ * Enable/disable wide gamut rendering on this renderer. Whether or not the actual rendering
+ * will be wide gamut depends on the hardware support for such rendering.
+ *
+ * @param wideGamut true if this renderer should render in wide gamut, false if it should
+ * render in sRGB
+ * TODO: Figure out color...
+ * @hide
+ */
+ public void setWideGamut(boolean wideGamut) {
+ nSetWideGamut(mNativeProxy, wideGamut);
+ }
+
+ /**
+ * Blocks until all previously queued work has completed.
+ *
+ * TODO: Only used for draw finished listeners, but the FrameCompleteCallback does that
+ * better
+ *
+ * @hide
+ */
+ public void fence() {
+ nFence(mNativeProxy);
+ }
+
+ /** @hide */
+ public void registerAnimatingRenderNode(RenderNode animator) {
+ nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
+ }
+
+ /** @hide */
+ public void registerVectorDrawableAnimator(NativeVectorDrawableAnimator animator) {
+ nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
+ animator.getAnimatorNativePtr());
+ }
+
+ /**
+ * Prevents any further drawing until {@link #syncAndDrawFrame(long)} is called.
+ * This is a signal that the contents of the RenderNode tree are no longer safe to play back.
+ * In practice this usually means that there are Functor pointers in the
+ * display list that are no longer valid.
+ *
+ * TODO: Can we get webview off of this?
+ *
+ * @hide
+ */
+ public void stopDrawing() {
+ nStopDrawing(mNativeProxy);
+ }
+
+ /**
+ * Creates a new hardware layer. A hardware layer built by calling this
+ * method will be treated as a texture layer, instead of as a render target.
+ *
+ * @return A hardware layer
+ * @hide
+ */
+ public TextureLayer createTextureLayer() {
+ long layer = nCreateTextureLayer(mNativeProxy);
+ return TextureLayer.adoptTextureLayer(this, layer);
+ }
+
+ /**
+ * Detaches the layer's surface texture from the GL context and releases
+ * the texture id
+ *
+ * @hide
+ */
+ public void detachSurfaceTexture(long hardwareLayer) {
+ nDetachSurfaceTexture(mNativeProxy, hardwareLayer);
+ }
+
+
+ /** @hide */
+ public void buildLayer(RenderNode node) {
+ if (node.hasDisplayList()) {
+ nBuildLayer(mNativeProxy, node.mNativeRenderNode);
+ }
+ }
+
+ /** @hide */
+ public boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) {
+ return nCopyLayerInto(mNativeProxy,
+ layer.getDeferredLayerUpdater(), bitmap);
+ }
+
+ /**
+ * Indicates that the specified hardware layer needs to be updated
+ * as soon as possible.
+ *
+ * @param layer The hardware layer that needs an update
+ * @hide
+ */
+ public void pushLayerUpdate(TextureLayer layer) {
+ nPushLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
+ }
+
+ /**
+ * Tells the HardwareRenderer that the layer is destroyed. The renderer
+ * should remove the layer from any update queues.
+ *
+ * @hide
+ */
+ public void onLayerDestroyed(TextureLayer layer) {
+ nCancelLayerUpdate(mNativeProxy, layer.getDeferredLayerUpdater());
+ }
+
+ /** @hide */
+ public void setFrameCallback(FrameDrawingCallback callback) {
+ nSetFrameCallback(mNativeProxy, callback);
+ }
+
+ /**
+ * Adds a rendernode to the renderer which can be drawn and changed asynchronously to the
+ * rendernode of the UI thread.
+ *
+ * @param node The node to add.
+ * @param placeFront If true, the render node will be placed in front of the content node,
+ * otherwise behind the content node.
+ * @hide
+ */
+ public void addRenderNode(RenderNode node, boolean placeFront) {
+ nAddRenderNode(mNativeProxy, node.mNativeRenderNode, placeFront);
+ }
+
+ /**
+ * Only especially added render nodes can be removed.
+ *
+ * @param node The node which was added via addRenderNode which should get removed again.
+ * @hide
+ */
+ public void removeRenderNode(RenderNode node) {
+ nRemoveRenderNode(mNativeProxy, node.mNativeRenderNode);
+ }
+
+ /**
+ * Draws a particular render node. If the node is not the content node, only the additional
+ * nodes will get drawn and the content remains untouched.
+ *
+ * @param node The node to be drawn.
+ * @hide
+ */
+ public void drawRenderNode(RenderNode node) {
+ nDrawRenderNode(mNativeProxy, node.mNativeRenderNode);
+ }
+
+ /**
+ * Loads system properties used by the renderer. This method is invoked
+ * whenever system properties are modified. Implementations can use this
+ * to trigger live updates of the renderer based on properties.
+ *
+ * @return True if a property has changed.
+ * @hide
+ */
+ public boolean loadSystemProperties() {
+ return nLoadSystemProperties(mNativeProxy);
+ }
+
+ /**
+ * @hide
+ */
+ public void dumpProfileInfo(FileDescriptor fd, @DumpFlags int dumpFlags) {
+ nDumpProfileInfo(mNativeProxy, fd, dumpFlags);
+ }
+
+ /**
+ * To avoid unnecessary overdrawing of the main content all additionally passed render nodes
+ * will be prevented to overdraw this area. It will be synchronized with the draw call.
+ * This should be updated in the content view's draw call.
+ *
+ * @param left The left side of the protected bounds.
+ * @param top The top side of the protected bounds.
+ * @param right The right side of the protected bounds.
+ * @param bottom The bottom side of the protected bounds.
+ * @hide
+ */
+ public void setContentDrawBounds(int left, int top, int right, int bottom) {
+ nSetContentDrawBounds(mNativeProxy, left, top, right, bottom);
+ }
+
+ /**
+ * Interface used to receive callbacks when a frame is being drawn.
+ *
+ * @hide
+ */
+ public interface FrameDrawingCallback {
+ /**
+ * Invoked during a frame drawing.
+ *
+ * @param frame The id of the frame being drawn.
+ */
+ void onFrameDraw(long frame);
+ }
+
+ /**
+ * Interface used to be notified when a frame has finished rendering
+ *
+ * @hide
+ */
+ public interface FrameCompleteCallback {
+ /**
+ * Invoked after a frame draw
+ *
+ * @param frameNr The id of the frame that was drawn.
+ */
+ void onFrameComplete(long frameNr);
+ }
+
+ private static void validateAlpha(float alpha, String argumentName) {
+ if (!(alpha >= 0.0f && alpha <= 1.0f)) {
+ throw new IllegalArgumentException(argumentName + " must be a valid alpha, "
+ + alpha + " is not in the range of 0.0f to 1.0f");
+ }
+ }
+
+ private static void validatePositive(float f, String argumentName) {
+ if (!(Float.isFinite(f) && f >= 0.0f)) {
+ throw new IllegalArgumentException(argumentName
+ + " must be a finite positive, given=" + f);
+ }
+ }
+
+ private static void validateFinite(float f, String argumentName) {
+ if (!Float.isFinite(f)) {
+ throw new IllegalArgumentException(argumentName + " must be finite, given=" + f);
+ }
+ }
+
+ /** @hide */
+ public static void invokeFunctor(long functor, boolean waitForCompletion) {
+ nInvokeFunctor(functor, waitForCompletion);
+ }
+
+ /**
+ * b/68769804: For low FPS experiments.
+ *
+ * @hide
+ */
+ public static void setFPSDivisor(int divisor) {
+ nHackySetRTAnimationsEnabled(divisor <= 1);
+ }
+
+ /**
+ * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be
+ * called before any OpenGL context is created.
+ *
+ * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values.
+ * @hide
+ */
+ public static void setContextPriority(int priority) {
+ nSetContextPriority(priority);
+ }
+
+ /**
+ * Sets whether or not high contrast text rendering is enabled. The setting is global
+ * but only affects content rendered after the change is made.
+ *
+ * @hide
+ */
+ public static void setHighContrastText(boolean highContrastText) {
+ nSetHighContrastText(highContrastText);
+ }
+
+ /**
+ * If set RenderThread will avoid doing any IPC using instead a fake vsync & DisplayInfo source
+ *
+ * @hide
+ */
+ public static void setIsolatedProcess(boolean isIsolated) {
+ nSetIsolatedProcess(isIsolated);
+ }
+
+ /**
+ * If set extra graphics debugging abilities will be enabled such as dumping skp
+ *
+ * @hide
+ */
+ public static void setDebuggingEnabled(boolean enable) {
+ nSetDebuggingEnabled(enable);
+ }
+
+ /** @hide */
+ public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) {
+ if (srcRect == null) {
+ // Empty rect means entire surface
+ return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap);
+ } else {
+ return nCopySurfaceInto(surface, srcRect.left, srcRect.top,
+ srcRect.right, srcRect.bottom, bitmap);
+ }
+ }
+
+ /**
+ * Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given
+ * RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and
+ * not the RenderNode from a View.
+ *
+ * @hide
+ **/
+ public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) {
+ return nCreateHardwareBitmap(node.mNativeRenderNode, width, height);
+ }
+
+ /**
+ * Invoke this method when the system is running out of memory. This
+ * method will attempt to recover as much memory as possible, based on
+ * the specified hint.
+ *
+ * @param level Hint about the amount of memory that should be trimmed,
+ * see {@link android.content.ComponentCallbacks}
+ * @hide
+ */
+ public static void trimMemory(int level) {
+ nTrimMemory(level);
+ }
+
+ /** @hide */
+ public static void overrideProperty(@NonNull String name, @NonNull String value) {
+ if (name == null || value == null) {
+ throw new IllegalArgumentException("name and value must be non-null");
+ }
+ nOverrideProperty(name, value);
+ }
+
+ /**
+ * Sets the directory to use as a persistent storage for threaded rendering
+ * resources.
+ *
+ * @param cacheDir A directory the current process can write to
+ * @hide
+ */
+ public static void setupDiskCache(File cacheDir) {
+ setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
+ new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
+ }
+
+ /** @hide */
+ public static void setPackageName(String packageName) {
+ ProcessInitializer.sInstance.setPackageName(packageName);
+ }
+
+ private static final class DestroyContextRunnable implements Runnable {
+ private final long mNativeInstance;
+
+ DestroyContextRunnable(long nativeInstance) {
+ mNativeInstance = nativeInstance;
+ }
+
+ @Override
+ public void run() {
+ nDeleteProxy(mNativeInstance);
+ }
+ }
+
+ private static class ProcessInitializer {
+ static ProcessInitializer sInstance = new ProcessInitializer();
+
+ private boolean mInitialized = false;
+
+ private String mPackageName;
+ private IGraphicsStats mGraphicsStatsService;
+ private IGraphicsStatsCallback mGraphicsStatsCallback = new IGraphicsStatsCallback.Stub() {
+ @Override
+ public void onRotateGraphicsStatsBuffer() throws RemoteException {
+ rotateBuffer();
+ }
+ };
+
+ private ProcessInitializer() {
+ }
+
+ synchronized void setPackageName(String name) {
+ if (mInitialized) return;
+ mPackageName = name;
+ }
+
+ synchronized void init(long renderProxy) {
+ if (mInitialized) return;
+ mInitialized = true;
+
+ initSched(renderProxy);
+ initGraphicsStats();
+ }
+
+ private void initSched(long renderProxy) {
+ try {
+ int tid = nGetRenderThreadTid(renderProxy);
+ ActivityManager.getService().setRenderThread(tid);
+ } catch (Throwable t) {
+ Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t);
+ }
+ }
+
+ private void initGraphicsStats() {
+ if (mPackageName == null) return;
+
+ try {
+ IBinder binder = ServiceManager.getService("graphicsstats");
+ if (binder == null) return;
+ mGraphicsStatsService = IGraphicsStats.Stub.asInterface(binder);
+ requestBuffer();
+ } catch (Throwable t) {
+ Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
+ }
+ }
+
+ private void rotateBuffer() {
+ nRotateProcessStatsBuffer();
+ requestBuffer();
+ }
+
+ private void requestBuffer() {
+ try {
+ ParcelFileDescriptor pfd = mGraphicsStatsService
+ .requestBufferForProcess(mPackageName, mGraphicsStatsCallback);
+ nSetProcessStatsBuffer(pfd.getFd());
+ pfd.close();
+ } catch (Throwable t) {
+ Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static native void disableVsync();
+
+ /** @hide */
+ protected static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
+
+ private static native void nRotateProcessStatsBuffer();
+
+ private static native void nSetProcessStatsBuffer(int fd);
+
+ private static native int nGetRenderThreadTid(long nativeProxy);
+
+ private static native long nCreateRootRenderNode();
+
+ private static native long nCreateProxy(boolean translucent, long rootRenderNode);
+
+ private static native void nDeleteProxy(long nativeProxy);
+
+ private static native boolean nLoadSystemProperties(long nativeProxy);
+
+ private static native void nSetName(long nativeProxy, String name);
+
+ private static native void nSetSurface(long nativeProxy, Surface window);
+
+ private static native boolean nPause(long nativeProxy);
+
+ private static native void nSetStopped(long nativeProxy, boolean stopped);
+
+ private static native void nSetLightGeometry(long nativeProxy,
+ float lightX, float lightY, float lightZ, float lightRadius);
+
+ private static native void nSetLightAlpha(long nativeProxy, float ambientShadowAlpha,
+ float spotShadowAlpha);
+
+ private static native void nSetOpaque(long nativeProxy, boolean opaque);
+
+ private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
+
+ private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
+
+ private static native void nDestroy(long nativeProxy, long rootRenderNode);
+
+ private static native void nRegisterAnimatingRenderNode(long rootRenderNode,
+ long animatingNode);
+
+ private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator);
+
+ private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
+
+ private static native long nCreateTextureLayer(long nativeProxy);
+
+ private static native void nBuildLayer(long nativeProxy, long node);
+
+ private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
+
+ private static native void nPushLayerUpdate(long nativeProxy, long layer);
+
+ private static native void nCancelLayerUpdate(long nativeProxy, long layer);
+
+ private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
+
+ private static native void nDestroyHardwareResources(long nativeProxy);
+
+ private static native void nTrimMemory(int level);
+
+ private static native void nOverrideProperty(String name, String value);
+
+ private static native void nFence(long nativeProxy);
+
+ private static native void nStopDrawing(long nativeProxy);
+
+ private static native void nNotifyFramePending(long nativeProxy);
+
+ private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
+ @DumpFlags int dumpFlags);
+
+ private static native void nAddRenderNode(long nativeProxy, long rootRenderNode,
+ boolean placeFront);
+
+ private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
+
+ private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
+
+ private static native void nSetContentDrawBounds(long nativeProxy, int left,
+ int top, int right, int bottom);
+
+ private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
+
+ private static native void nSetFrameCompleteCallback(long nativeProxy,
+ FrameCompleteCallback callback);
+
+ private static native long nAddFrameMetricsObserver(long nativeProxy,
+ FrameMetricsObserver observer);
+
+ private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
+
+ private static native int nCopySurfaceInto(Surface surface,
+ int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap);
+
+ private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
+
+ private static native void nSetHighContrastText(boolean enabled);
+
+ // For temporary experimentation b/66945974
+ private static native void nHackySetRTAnimationsEnabled(boolean enabled);
+
+ private static native void nSetDebuggingEnabled(boolean enabled);
+
+ private static native void nSetIsolatedProcess(boolean enabled);
+
+ private static native void nSetContextPriority(int priority);
+
+ private static native void nAllocateBuffers(long nativeProxy);
+
+ private static native void nSetForceDark(long nativeProxy, boolean enabled);
+}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 0a4ac8c..c10e482 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -30,6 +30,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.security.KeyStoreException;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -40,14 +41,21 @@
import android.security.keystore.KeyExpiredException;
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
import android.security.keystore.StrongBoxUnavailableException;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
-
+import com.android.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import java.math.BigInteger;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.security.InvalidKeyException;
import java.util.List;
import java.util.Locale;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.AlgorithmId;
/**
* @hide This should not be made public in its present form because it
@@ -69,6 +77,7 @@
public static final int VALUE_CORRUPTED = 8;
public static final int UNDEFINED_ACTION = 9;
public static final int WRONG_PASSWORD = 10;
+ public static final int KEY_ALREADY_EXISTS = 16;
public static final int CANNOT_ATTEST_IDS = -66;
public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
@@ -239,7 +248,12 @@
if (value == null) {
value = new byte[0];
}
- return mBinder.insert(key, value, uid, flags);
+ int error = mBinder.insert(key, value, uid, flags);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(key, uid);
+ error = mBinder.insert(key, value, uid, flags);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -366,53 +380,6 @@
return isEmpty(UserHandle.myUserId());
}
- public boolean generate(String key, int uid, int keyType, int keySize, int flags,
- byte[][] args) {
- try {
- return mBinder.generate(key, uid, keyType, keySize, flags,
- new KeystoreArguments(args)) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean importKey(String keyName, byte[] key, int uid, int flags) {
- try {
- return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public byte[] sign(String key, byte[] data) {
- try {
- return mBinder.sign(key, data);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return null;
- }
-
- }
-
- public boolean verify(String key, byte[] data, byte[] signature) {
- try {
- signature = signature != null ? signature : new byte[0];
- return mBinder.verify(key, data, signature) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return false;
- }
-
- }
-
public String grant(String key, int uid) {
try {
String grantAlias = mBinder.grant(key, uid);
@@ -496,7 +463,12 @@
try {
entropy = entropy != null ? entropy : new byte[0];
args = args != null ? args : new KeymasterArguments();
- return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
+ int error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(alias, uid);
+ error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -528,8 +500,14 @@
public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
int uid, int flags, KeyCharacteristics outCharacteristics) {
try {
- return mBinder.importKey(alias, args, format, keyData, uid, flags,
+ int error = mBinder.importKey(alias, args, format, keyData, uid, flags,
outCharacteristics);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(alias, uid);
+ error = mBinder.importKey(alias, args, format, keyData, uid, flags,
+ outCharacteristics);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -541,13 +519,78 @@
return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
}
+ private String getAlgorithmFromPKCS8(byte[] keyData) {
+ try {
+ final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
+ final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
+ final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
+ return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
+ } catch (IOException e) {
+ Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
+ Log.e(TAG, Log.getStackTraceString(e));
+ return null;
+ }
+ }
+
+ private KeymasterArguments makeLegacyArguments(String algorithm) {
+ KeymasterArguments args = new KeymasterArguments();
+ args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
+ KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+ args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+ if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
+ args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
+ }
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
+ args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
+ args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
+ args.addUnsignedLong(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+ KeymasterArguments.UINT64_MAX_VALUE);
+ args.addUnsignedLong(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+ KeymasterArguments.UINT64_MAX_VALUE);
+ args.addUnsignedLong(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, BigInteger.ZERO);
+ return args;
+ }
+
+ public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
+ String algorithm = getAlgorithmFromPKCS8(keyData);
+ if (algorithm == null) return false;
+ KeymasterArguments args = makeLegacyArguments(algorithm);
+ KeyCharacteristics out = new KeyCharacteristics();
+ int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
+ flags, out);
+ if (result != NO_ERROR) {
+ Log.e(TAG, Log.getStackTraceString(
+ new KeyStoreException(result, "legacy key import failed")));
+ return false;
+ }
+ return true;
+ }
+
public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
String wrappingKeyAlias,
byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
KeyCharacteristics outCharacteristics) {
try {
- return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
+ int error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
+ if (error == KEY_ALREADY_EXISTS) {
+ mBinder.del(wrappedKeyAlias, -1);
+ error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
+ maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
+ }
+ return error;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return SYSTEM_ERROR;
@@ -627,21 +670,6 @@
}
/**
- * Check if the operation referenced by {@code token} is currently authorized.
- *
- * @param token An operation token returned by a call to
- * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
- */
- public boolean isOperationAuthorized(IBinder token) {
- try {
- return mBinder.isOperationAuthorized(token);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- /**
* Add an authentication record to the keystore authorization table.
*
* @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index 236a6b6..b04c774 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -66,6 +66,7 @@
FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) {
setDensity(1);
+ consumeProperties();
}
FrameInfoVisualizer::~FrameInfoVisualizer() {
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 05dc340..c58bcb3 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -139,7 +139,7 @@
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
uint32_t flags = paint->getFlags();
- SkFontHinting hinting = (SkFontHinting)paint->getHinting();
+ unsigned hinting = static_cast<unsigned>(paint->getHinting());
// select only flags that might affect text layout
flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
SkPaint::kSubpixelText_Flag | SkPaint::kEmbeddedBitmapText_Flag |
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 92a749f..f1a522e 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -180,14 +180,20 @@
}
}
-void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
- mLightGeometry.radius = lightRadius;
+void CanvasContext::allocateBuffers() {
+ if (mNativeSurface) {
+ mNativeSurface->allocateBuffers();
+ }
+}
+
+void CanvasContext::setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
mLightInfo.spotShadowAlpha = spotShadowAlpha;
}
-void CanvasContext::setLightCenter(const Vector3& lightCenter) {
+void CanvasContext::setLightGeometry(const Vector3& lightCenter, float lightRadius) {
mLightGeometry.center = lightCenter;
+ mLightGeometry.radius = lightRadius;
}
void CanvasContext::setOpaque(bool opaque) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2307ee4..70be4a6 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -113,9 +113,10 @@
bool pauseSurface();
void setStopped(bool stopped);
bool hasSurface() { return mNativeSurface.get(); }
+ void allocateBuffers();
- void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
- void setLightCenter(const Vector3& lightCenter);
+ void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+ void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
void setWideGamut(bool wideGamut);
bool makeCurrent();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 54219b5..085812a 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -80,22 +80,16 @@
mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); });
}
-void RenderProxy::initialize(const sp<Surface>& surface) {
+void RenderProxy::setSurface(const sp<Surface>& surface) {
mRenderThread.queue().post(
[ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
}
-void RenderProxy::allocateBuffers(const sp<Surface>& surface) {
- mRenderThread.queue().post(
- [ surf = surface ]() mutable { surf->allocateBuffers(); });
+void RenderProxy::allocateBuffers() {
+ mRenderThread.queue().post([=]() { mContext->allocateBuffers(); });
}
-void RenderProxy::updateSurface(const sp<Surface>& surface) {
- mRenderThread.queue().post(
- [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
-}
-
-bool RenderProxy::pauseSurface(const sp<Surface>& surface) {
+bool RenderProxy::pause() {
return mRenderThread.queue().runSync([this]() -> bool { return mContext->pauseSurface(); });
}
@@ -103,13 +97,13 @@
mRenderThread.queue().runSync([this, stopped]() { mContext->setStopped(stopped); });
}
-void RenderProxy::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+void RenderProxy::setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
mRenderThread.queue().post(
- [=]() { mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha); });
+ [=]() { mContext->setLightAlpha(ambientShadowAlpha, spotShadowAlpha); });
}
-void RenderProxy::setLightCenter(const Vector3& lightCenter) {
- mRenderThread.queue().post([=]() { mContext->setLightCenter(lightCenter); });
+void RenderProxy::setLightGeometry(const Vector3& lightCenter, float lightRadius) {
+ mRenderThread.queue().post([=]() { mContext->setLightGeometry(lightCenter, lightRadius); });
}
void RenderProxy::setOpaque(bool opaque) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d29fcc4..6668c58 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -69,13 +69,12 @@
ANDROID_API bool loadSystemProperties();
ANDROID_API void setName(const char* name);
- ANDROID_API void initialize(const sp<Surface>& surface);
- ANDROID_API void allocateBuffers(const sp<Surface>& surface);
- ANDROID_API void updateSurface(const sp<Surface>& surface);
- ANDROID_API bool pauseSurface(const sp<Surface>& surface);
+ ANDROID_API void setSurface(const sp<Surface>& surface);
+ ANDROID_API void allocateBuffers();
+ ANDROID_API bool pause();
ANDROID_API void setStopped(bool stopped);
- ANDROID_API void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
- ANDROID_API void setLightCenter(const Vector3& lightCenter);
+ ANDROID_API void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+ ANDROID_API void setLightGeometry(const Vector3& lightCenter, float lightRadius);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API void setWideGamut(bool wideGamut);
ANDROID_API int64_t* frameInfo();
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 62f704b..2384f95 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -74,7 +74,7 @@
PREVENT_COPY_AND_ASSIGN(RenderThread);
public:
- // Sets a callback that fires before any RenderThread setup has occured.
+ // Sets a callback that fires before any RenderThread setup has occurred.
ANDROID_API static void setOnStartHook(void (*onStartHook)());
WorkQueue& queue() { return ThreadBase::queue(); }
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 5f5a92e..5fa008b 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -132,10 +132,10 @@
ContextFactory factory;
std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode.get(), &factory));
proxy->loadSystemProperties();
- proxy->initialize(surface);
+ proxy->setSurface(surface);
float lightX = width / 2.0;
- proxy->setup(dp(800.0f), 255 * 0.075, 255 * 0.15);
- proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
+ proxy->setLightAlpha(255 * 0.075, 255 * 0.15);
+ proxy->setLightGeometry((Vector3){lightX, dp(-200.0f), dp(800.0f)}, dp(800.0f));
// Do a few cold runs then reset the stats so that the caches are all hot
int warmupFrameCount = 5;
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 1276881..b5d835a 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -120,4 +120,18 @@
// used by gts tests to verify throttling whitelist
String[] getBackgroundThrottlingWhitelist();
+
+ /**
+ * Allow the {@link android.location.LocationManager#getNetworkProviderPackage location
+ * provider} to start the UI to modify the location permission for a package.
+ *
+ * <p>Can only be called by the location provider.
+ *
+ * @param packageName The package the permission belongs to
+ * @param permission The (individual) permission to switch
+ *
+ * @return A pending intent that starts the permission management UI or {@code null} if the
+ * intent cannot be created
+ */
+ PendingIntent createManageLocationPermissionIntent(in String packageName, in String permission);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index b1968ba..02680ab 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -22,6 +22,7 @@
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -43,7 +44,9 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
+
import com.android.internal.location.ProviderProperties;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -2393,4 +2396,29 @@
return null;
}
}
+
+ /**
+ * Allow the {@link android.location.LocationManager#getNetworkProviderPackage location
+ * provider} to start the UI to modify the location permission for a package.
+ *
+ * <p>Can only be called by the location provider.
+ *
+ * @param packageName The package the permission belongs to
+ * @param permission The (individual) location permission to switch
+ *
+ * @return A one-shot pending intent that starts the permission management UI or {@code null} if
+ * the intent cannot be created
+ *
+ * @hide
+ */
+ @SystemApi
+ public @Nullable PendingIntent createManageLocationPermissionIntent(@NonNull String packageName,
+ @NonNull String permission) {
+ try {
+ return mService.createManageLocationPermissionIntent(packageName, permission);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index e1f9111..69c267e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -65,6 +65,15 @@
}
}
+ /**
+ * Logs a generic Settings event.
+ */
+ public void action(int attribution, int action, int pageId, String key, int value) {
+ for (LogWriter writer : mLoggerWriters) {
+ writer.action(attribution, action, pageId, key, value);
+ }
+ }
+
public void action(Context context, int category, int value) {
for (LogWriter writer : mLoggerWriters) {
writer.action(context, category, value);
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
index a28e45c..71f3789 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java
@@ -116,8 +116,6 @@
mPreferenceKeySet.add(prefKey);
return;
}
- // TODO: Remove count logging to save some resource.
- mMetricsFeature.count(mContext, buildCountName(prefKey, value), 1);
final Pair<Integer, Object> valueData;
if (value instanceof Long) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ca0267c..f1295e03 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -481,6 +481,9 @@
dumpSetting(s, p,
Settings.Global.EMULATE_DISPLAY_CUTOUT,
GlobalSettingsProto.Development.EMULATE_DISPLAY_CUTOUT);
+ dumpSetting(s, p,
+ Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
+ GlobalSettingsProto.Development.FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS);
p.end(developmentToken);
final long deviceToken = p.start(GlobalSettingsProto.DEVICE);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index b4fc820..887ea59 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -13,11 +13,11 @@
*/
package com.android.systemui.plugins;
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
import android.graphics.Paint.Style;
import android.view.View;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
/**
* This plugin is used to replace main clock in keyguard.
*/
@@ -44,4 +44,9 @@
* @param color A color value.
*/
void setTextColor(int color);
+
+ /**
+ * Notifies that time tick alarm from doze service fired.
+ */
+ default void dozeTimeTick() { }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 013745a..8881f8a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -143,6 +143,15 @@
}
/**
+ * Notifies that time tick alarm from doze service fired.
+ */
+ public void dozeTimeTick() {
+ if (mClockPlugin != null) {
+ mClockPlugin.dozeTimeTick();
+ }
+ }
+
+ /**
* When plugin changes, set all kept parameters into newer plugin.
*/
private void initPluginParams() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a403b75..f701e22 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -47,7 +47,6 @@
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import com.google.android.collect.Sets;
@@ -276,6 +275,7 @@
public void dozeTimeTick() {
refreshTime();
mKeyguardSlice.refresh();
+ mClockView.dozeTimeTick();
}
private void refreshTime() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index c3bf16e..a315bf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1124,7 +1124,7 @@
*/
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
private float getExpandTranslationStart() {
- return -mTopPadding + getMinExpansionHeight();
+ return -mTopPadding + getMinExpansionHeight() - mShelf.getIntrinsicHeight();
}
/**
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 90ad09e..046442a 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -83,6 +84,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
@@ -111,6 +113,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
/**
@@ -3420,6 +3423,48 @@
}
}
+ @Override
+ public PendingIntent createManageLocationPermissionIntent(String packageName,
+ String permission) {
+ Preconditions.checkNotNull(packageName);
+ Preconditions.checkArgument(permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)
+ || permission.equals(Manifest.permission.ACCESS_COARSE_LOCATION)
+ || permission.equals(Manifest.permission.ACCESS_BACKGROUND_LOCATION));
+
+ int callingUid = Binder.getCallingUid();
+ long token = Binder.clearCallingIdentity();
+ try {
+ String locProvider = getNetworkProviderPackage();
+ if (locProvider == null) {
+ return null;
+ }
+
+ PackageInfo locProviderInfo;
+ try {
+ locProviderInfo = mContext.getPackageManager().getPackageInfo(
+ locProvider, PackageManager.MATCH_DIRECT_BOOT_AUTO);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not resolve " + locProvider, e);
+ return null;
+ }
+
+ if (locProviderInfo.applicationInfo.uid != callingUid) {
+ throw new SecurityException("Only " + locProvider + " can call this API");
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(Intent.EXTRA_PERMISSION_NAME, permission);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ return PendingIntent.getActivity(mContext,
+ Objects.hash(packageName, permission), intent,
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void log(String log) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.d(TAG, log);
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 968c17f..8ac19d5 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -61,6 +61,7 @@
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS_GLES, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, int.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 0ee55ed..527539d 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -21,6 +21,7 @@
import android.content.IntentFilter;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceProxy;
+import android.media.AudioManager;
import android.metrics.LogMaker;
import android.nfc.INfcAdapter;
import android.os.Binder;
@@ -393,6 +394,19 @@
boolean wasEmpty = mActiveCameraUsage.isEmpty();
switch (newCameraState) {
case ICameraServiceProxy.CAMERA_STATE_OPEN:
+ // Notify the audio subsystem about the facing of the most-recently opened
+ // camera This can be used to select the best audio tuning in case video
+ // recording with that camera will happen. Since only open events are used, if
+ // multiple cameras are opened at once, the one opened last will be used to
+ // select audio tuning.
+ AudioManager audioManager = getContext().getSystemService(AudioManager.class);
+ if (audioManager != null) {
+ // Map external to front for audio tuning purposes
+ String facingStr = (facing == ICameraServiceProxy.CAMERA_FACING_BACK) ?
+ "back" : "front";
+ String facingParameter = "cameraFacing=" + facingStr;
+ audioManager.setParameters(facingParameter);
+ }
break;
case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 4c93441..13bb817 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2777,13 +2777,13 @@
// dataPath - path to package's data path
// seinfo - seinfo label for the app (assigned at install time)
// gids - supplementary gids this app launches with
+ // profileableFromShellFlag - 0 or 1 if the package is profileable from shell.
//
// NOTE: We prefer not to expose all ApplicationInfo flags for now.
//
// DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
// FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
- // frameworks/base/libs/packagelistparser
- // system/core/run-as/run-as.c
+ // system/core/libpackagelistparser
//
sb.setLength(0);
sb.append(ai.packageName);
@@ -2803,6 +2803,8 @@
} else {
sb.append("none");
}
+ sb.append(" ");
+ sb.append(ai.isProfileableByShell() ? "1" : "0");
sb.append("\n");
writer.append(sb);
}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 478a11a..751ae0d 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -1103,13 +1103,12 @@
}
/**
+ * Checks if system decorations should be shown on this display.
+ *
* @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
*/
boolean supportsSystemDecorations() {
- return mDisplay.supportsSystemDecorations()
- // TODO (b/111363427): Remove this and set the new FLAG_SHOULD_SHOW_LAUNCHER flag
- // (b/114338689) whenever vr 2d display id is set.
- || mDisplayId == mSupervisor.mService.mVr2dDisplayId;
+ return mWindowContainerController.supportsSystemDecorations();
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 9b01dfd..61e1414 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -72,12 +72,12 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
import android.app.WindowConfiguration.WindowingMode;
@@ -495,7 +495,9 @@
foundInfo = info;
}
if (allWindowsDrawn()) {
- reset(false /* abort */, foundInfo, "notifyTransitionStarting - all windows drawn");
+ // abort metrics collection if we cannot find a matching transition.
+ final boolean abortMetrics = foundInfo == null;
+ reset(abortMetrics, foundInfo, "notifyTransitionStarting - all windows drawn");
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 433c05a..f55bcce 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -56,7 +56,6 @@
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
@@ -658,8 +657,6 @@
ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
final boolean supportsMultiDisplay = mContext.getPackageManager()
.hasSystemFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
- final boolean alwaysFinishActivities =
- Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
final boolean forceResizable = Settings.Global.getInt(
resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fece980..e20793e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4666,4 +4666,16 @@
pendingLayoutChanges |= changes;
}
+
+ /**
+ * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
+ */
+ boolean supportsSystemDecorations() {
+ // TODO(b/114338689): Read the setting from DisplaySettings.
+ return mDisplay.supportsSystemDecorations()
+ // TODO (b/111363427): Remove this and set the new FLAG_SHOULD_SHOW_LAUNCHER flag
+ // (b/114338689) whenever vr 2d display id is set.
+ || mDisplayId == mService.mVr2dDisplayId
+ || mService.mForceDesktopModeOnExternalDisplays;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java
index 44956ab..624fbc7 100644
--- a/services/core/java/com/android/server/wm/DisplaySettings.java
+++ b/services/core/java/com/android/server/wm/DisplaySettings.java
@@ -185,15 +185,12 @@
}
// No record is present so use default windowing mode policy.
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- if (displayId == Display.DEFAULT_DISPLAY) {
- windowingMode = (mService.mIsPc && mService.mSupportsFreeformWindowManagement)
- ? WindowConfiguration.WINDOWING_MODE_FREEFORM
- : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
- } else {
- windowingMode = mService.mSupportsFreeformWindowManagement
- ? WindowConfiguration.WINDOWING_MODE_FREEFORM
- : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
- }
+ final boolean forceDesktopMode = mService.mForceDesktopModeOnExternalDisplays
+ && displayId != Display.DEFAULT_DISPLAY;
+ windowingMode = mService.mSupportsFreeformWindowManagement
+ && (mService.mIsPc || forceDesktopMode)
+ ? WindowConfiguration.WINDOWING_MODE_FREEFORM
+ : WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
}
return windowingMode;
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index 632494b..864f7e1 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -339,6 +339,17 @@
|| transit == TRANSIT_TASK_TO_FRONT;
}
+ /**
+ * Checks if system decorations should be shown on this display.
+ *
+ * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
+ */
+ public boolean supportsSystemDecorations() {
+ synchronized (mGlobalLock) {
+ return mContainer.supportsSystemDecorations();
+ }
+ }
+
@Override
public String toString() {
return "{DisplayWindowController displayId=" + mDisplayId + "}";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ec68f76..e4444e2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -29,6 +29,7 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.DOCKED_INVALID;
@@ -538,12 +539,21 @@
int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
Rect mDockedStackCreateBounds;
- boolean mForceResizableTasks = false;
- boolean mSupportsPictureInPicture = false;
- boolean mSupportsFreeformWindowManagement = false;
- boolean mIsPc = false;
+ boolean mForceResizableTasks;
+ boolean mSupportsPictureInPicture;
+ boolean mSupportsFreeformWindowManagement;
+ boolean mIsPc;
+ /**
+ * Flag that indicates that desktop mode is forced for public secondary screens.
+ *
+ * This includes several settings:
+ * - Set freeform windowing mode on external screen if it's supported and enabled.
+ * - Enable system decorations and IME on external screen.
+ * - TODO: Show mouse pointer on external screen.
+ */
+ boolean mForceDesktopModeOnExternalDisplays;
- boolean mDisableTransitionAnimation = false;
+ boolean mDisableTransitionAnimation;
int getDragLayerLocked() {
return mPolicy.getWindowLayerFromTypeLw(TYPE_DRAG) * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
@@ -980,17 +990,21 @@
}
}, UserHandle.ALL, suspendPackagesFilter, null, null);
+ final ContentResolver resolver = context.getContentResolver();
// Get persisted window scale setting
- mWindowAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
+ mWindowAnimationScaleSetting = Settings.Global.getFloat(resolver,
Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
- mTransitionAnimationScaleSetting = Settings.Global.getFloat(context.getContentResolver(),
+ mTransitionAnimationScaleSetting = Settings.Global.getFloat(resolver,
Settings.Global.TRANSITION_ANIMATION_SCALE,
context.getResources().getFloat(
R.dimen.config_appTransitionAnimationDurationScaleDefault));
- setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
+ setAnimatorDurationScale(Settings.Global.getFloat(resolver,
Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting));
+ mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,
+ DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
+
IntentFilter filter = new IntentFilter();
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -6398,6 +6412,12 @@
}
}
+ void setForceDesktopModeOnExternalDisplays(boolean forceDesktopModeOnExternalDisplays) {
+ synchronized (mWindowMap) {
+ mForceDesktopModeOnExternalDisplays = forceDesktopModeOnExternalDisplays;
+ }
+ }
+
public void setIsPc(boolean isPc) {
synchronized (mGlobalLock) {
mIsPc = isPc;
@@ -6576,10 +6596,10 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final DisplayContent dc = getDisplayContentOrCreate(displayId, null);
+ final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
if (dc == null) {
throw new IllegalArgumentException(
- "Trying to register a non existent display.");
+ "Trying to configure a non existent display.");
}
// We usually set the override info in DisplayManager so that we get consistent
// values when displays are changing. However, we don't do this for displays that
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
index f0c49c8..5808bc9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
@@ -64,6 +64,7 @@
mWm.setSupportsFreeformWindowManagement(false);
mWm.setIsPc(false);
+ mWm.setForceDesktopModeOnExternalDisplays(false);
mTarget = new DisplaySettings(mWm, TEST_FOLDER);
@@ -78,7 +79,7 @@
}
@Test
- public void testPrimaryDisplayDefaultToFullscreenWithoutFreeformSupport() {
+ public void testPrimaryDisplayDefaultToFullscreen_NoFreeformSupport() {
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
@@ -86,7 +87,7 @@
}
@Test
- public void testPrimaryDisplayDefaultToFullscreenWithFreeformSupportNonPc() {
+ public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.setSupportsFreeformWindowManagement(true);
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -96,7 +97,18 @@
}
@Test
- public void testPrimaryDisplayDefaultToFreeformWithFreeformIsPc() {
+ public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_HasDesktopMode() {
+ mWm.setSupportsFreeformWindowManagement(true);
+ mWm.setForceDesktopModeOnExternalDisplays(true);
+
+ mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+
+ assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+ mPrimaryDisplay.getWindowingMode());
+ }
+
+ @Test
+ public void testPrimaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
mWm.setSupportsFreeformWindowManagement(true);
mWm.setIsPc(true);
@@ -107,7 +119,7 @@
}
@Test
- public void testSecondaryDisplayDefaultToFullscreenWithoutFreeformSupport() {
+ public void testSecondaryDisplayDefaultToFullscreen_NoFreeformSupport() {
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
@@ -115,17 +127,28 @@
}
@Test
- public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportNonPc() {
+ public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.setSupportsFreeformWindowManagement(true);
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+ mSecondaryDisplay.getWindowingMode());
+ }
+
+ @Test
+ public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_HasDesktopMode() {
+ mWm.setSupportsFreeformWindowManagement(true);
+ mWm.setForceDesktopModeOnExternalDisplays(true);
+
+ mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+
assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
mSecondaryDisplay.getWindowingMode());
}
@Test
- public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportIsPc() {
+ public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_IsPc() {
mWm.setSupportsFreeformWindowManagement(true);
mWm.setIsPc(true);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 27b8cdf..60cb08f 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -153,6 +153,7 @@
private static final int MSG_SET_FUNCTIONS_TIMEOUT = 15;
private static final int MSG_GET_CURRENT_USB_FUNCTIONS = 16;
private static final int MSG_FUNCTION_SWITCH_TIMEOUT = 17;
+ private static final int MSG_GADGET_HAL_REGISTERED = 18;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -1708,10 +1709,16 @@
protected static final String CTL_STOP = "ctl.stop";
/**
- * Adb natvie daemon
+ * Adb native daemon.
*/
protected static final String ADBD = "adbd";
+ /**
+ * Gadget HAL fully qualified instance name for registering for ServiceNotification.
+ */
+ protected static final String GADGET_HAL_FQ_NAME =
+ "android.hardware.usb.gadget@1.0::IUsbGadget";
+
protected boolean mCurrentUsbFunctionsRequested;
UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager,
@@ -1721,8 +1728,7 @@
ServiceNotification serviceNotification = new ServiceNotification();
boolean ret = IServiceManager.getService()
- .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget",
- "", serviceNotification);
+ .registerForNotifications(GADGET_HAL_FQ_NAME, "", serviceNotification);
if (!ret) {
Slog.e(TAG, "Failed to register usb gadget service start notification");
return;
@@ -1764,20 +1770,12 @@
@Override
public void onRegistration(String fqName, String name, boolean preexisting) {
Slog.i(TAG, "Usb gadget hal service started " + fqName + " " + name);
- synchronized (mGadgetProxyLock) {
- try {
- mGadgetProxy = IUsbGadget.getService();
- mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
- USB_GADGET_HAL_DEATH_COOKIE);
- if (!mCurrentFunctionsApplied && !mCurrentUsbFunctionsRequested) {
- setEnabledFunctions(mCurrentFunctions, false);
- }
- } catch (NoSuchElementException e) {
- Slog.e(TAG, "Usb gadget hal not found", e);
- } catch (RemoteException e) {
- Slog.e(TAG, "Usb Gadget hal not responding", e);
- }
+ if (!fqName.equals(GADGET_HAL_FQ_NAME)) {
+ Slog.e(TAG, "fqName does not match");
+ return;
}
+
+ sendMessage(MSG_GADGET_HAL_REGISTERED, preexisting);
}
}
@@ -1815,6 +1813,23 @@
setEnabledFunctions(UsbManager.FUNCTION_NONE, !isAdbEnabled());
}
break;
+ case MSG_GADGET_HAL_REGISTERED:
+ boolean preexisting = msg.arg1 == 1;
+ synchronized (mGadgetProxyLock) {
+ try {
+ mGadgetProxy = IUsbGadget.getService();
+ mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
+ USB_GADGET_HAL_DEATH_COOKIE);
+ if (!mCurrentFunctionsApplied && !preexisting) {
+ setEnabledFunctions(mCurrentFunctions, false);
+ }
+ } catch (NoSuchElementException e) {
+ Slog.e(TAG, "Usb gadget hal not found", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Usb Gadget hal not responding", e);
+ }
+ }
+ break;
default:
super.handleMessage(msg);
}
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index c39688c..0c40a6b 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -62,3 +62,22 @@
],
test_suites: ["general-tests"],
}
+
+cc_binary_host {
+ name: "dex_testcase_generator",
+ defaults: ["viewcompiler_defaults"],
+ srcs: ["dex_testcase_generator.cc"],
+ static_libs: [
+ "libviewcompiler",
+ ],
+}
+
+genrule {
+ name: "generate_dex_testcases",
+ tools: [":dex_testcase_generator"],
+ cmd: "$(location :dex_testcase_generator) $(genDir)",
+ out: [
+ "simple.dex",
+ "trivial.dex",
+ ],
+}
diff --git a/startop/view_compiler/README.md b/startop/view_compiler/README.md
index 5659501..f8da02b 100644
--- a/startop/view_compiler/README.md
+++ b/startop/view_compiler/README.md
@@ -23,3 +23,31 @@
application.
* This only works for apps that do not use a custom layout inflater.
* Other limitations yet to be discovered.
+
+## DexBuilder Tests
+
+The DexBuilder has several low-level end to end tests to verify generated DEX
+code validates, runs, and has the correct behavior. There are, unfortunately, a
+number of pieces that must be added to generate new tests. Here are the
+components:
+
+* `dex_testcase_generator` - Written in C++ using `DexBuilder`. This runs as a
+ build step produce the DEX files that will be tested on device. See the
+ `genrule` named `generate_dex_testcases` in `Android.bp`. These files are then
+ copied over to the device by TradeFed when running tests.
+* `DexBuilderTest` - This is a Java Language test harness that loads the
+ generated DEX files and exercises methods in the file.
+
+To add a new DEX file test, follow these steps:
+1. Modify `dex_testcase_generator` to produce the DEX file.
+2. Add the filename to the `out` list of the `generate_dex_testcases` rule in
+ `Android.bp`.
+3. Add a new `push` option to `AndroidTest.xml` to copy the DEX file to the
+ device.
+4. Modify `DexBuilderTest.java` to load and exercise the new test.
+
+In each case, you should be able to cargo-cult the existing test cases.
+
+In general, you can probably get by without adding a new generated DEX file, and
+instead add more methods to the files that are already generated. In this case,
+you can skip all of steps 2 and 3 above, and simplify steps 1 and 4.
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
new file mode 100644
index 0000000..5d675b7
--- /dev/null
+++ b/startop/view_compiler/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "dex-builder-test"
+ }
+ ]
+}
diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp
new file mode 100644
index 0000000..4449ea0
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2018 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.
+//
+
+android_test {
+ name: "dex-builder-test",
+ srcs: ["src/android/startop/test/DexBuilderTest.java"],
+ sdk_version: "current",
+ data: [":generate_dex_testcases"],
+ static_libs: [
+ "android-support-test",
+ "guava",
+ ],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTest.xml",
+ test_suites: ["general-tests"],
+}
diff --git a/startop/view_compiler/dex_builder_test/AndroidManifest.xml b/startop/view_compiler/dex_builder_test/AndroidManifest.xml
new file mode 100644
index 0000000..6ac5fc5
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.startop.test" >
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.startop.test"
+ android:label="DexBuilder Tests"/>
+
+</manifest>
diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml
new file mode 100644
index 0000000..6f90cf3
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<configuration description="Runs DexBuilder Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="dex-builder-test.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="trivial.dex->/data/local/tmp/dex-builder-test/trivial.dex" />
+ <option name="push" value="simple.dex->/data/local/tmp/dex-builder-test/simple.dex" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.startop.test" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
new file mode 100644
index 0000000..87b2578
--- /dev/null
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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.startop.test;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import com.google.common.io.ByteStreams;
+import dalvik.system.InMemoryDexClassLoader;
+import dalvik.system.PathClassLoader;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import org.junit.Assert;
+import org.junit.Test;
+
+// Adding tests here requires changes in several other places. See README.md in
+// the view_compiler directory for more information.
+public class DexBuilderTest {
+ static ClassLoader loadDexFile(String filename) throws Exception {
+ return new PathClassLoader("/data/local/tmp/dex-builder-test/" + filename,
+ ClassLoader.getSystemClassLoader());
+ }
+
+ public void hello() {}
+
+ @Test
+ public void loadTrivialDex() throws Exception {
+ ClassLoader loader = loadDexFile("trivial.dex");
+ loader.loadClass("android.startop.test.testcases.Trivial");
+ }
+
+ @Test
+ public void return5() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("return5");
+ Assert.assertEquals(5, method.invoke(null));
+ }
+
+ @Test
+ public void returnParam() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("returnParam", int.class);
+ Assert.assertEquals(5, method.invoke(null, 5));
+ Assert.assertEquals(42, method.invoke(null, 42));
+ }
+
+ @Test
+ public void returnStringLength() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("returnStringLength", String.class);
+ Assert.assertEquals(13, method.invoke(null, "Hello, World!"));
+ }
+}
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
new file mode 100644
index 0000000..898817b
--- /dev/null
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/logging.h"
+#include "dex_builder.h"
+
+#include <fstream>
+#include <string>
+
+// Adding tests here requires changes in several other places. See README.md in
+// the view_compiler directory for more information.
+
+using namespace startop::dex;
+using namespace std;
+
+void GenerateTrivialDexFile(const string& outdir) {
+ DexBuilder dex_file;
+
+ ClassBuilder cbuilder{dex_file.MakeClass("android.startop.test.testcases.Trivial")};
+ cbuilder.set_source_file("dex_testcase_generator.cc#GenerateTrivialDexFile");
+
+ slicer::MemView image{dex_file.CreateImage()};
+ std::ofstream out_file(outdir + "/trivial.dex");
+ out_file.write(image.ptr<const char>(), image.size());
+}
+
+// Generates test cases that test around 1 instruction.
+void GenerateSimpleTestCases(const string& outdir) {
+ DexBuilder dex_file;
+
+ ClassBuilder cbuilder{dex_file.MakeClass("android.startop.test.testcases.SimpleTests")};
+ cbuilder.set_source_file("dex_testcase_generator.cc#GenerateSimpleTestCases");
+
+ // int return5() { return 5; }
+ auto return5{cbuilder.CreateMethod("return5", Prototype{TypeDescriptor::Int()})};
+ Value r{return5.MakeRegister()};
+ return5.BuildConst4(r, 5);
+ return5.BuildReturn(r);
+ return5.Encode();
+
+ // // int returnParam(int x) { return x; }
+ auto returnParam{cbuilder.CreateMethod("returnParam",
+ Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
+ returnParam.BuildReturn(Value::Parameter(0));
+ returnParam.Encode();
+
+ // int returnStringLength(String x) { return x.length(); }
+ auto string_type{TypeDescriptor::FromClassname("java.lang.String")};
+ MethodDeclData string_length{
+ dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()})};
+
+ auto returnStringLength{
+ cbuilder.CreateMethod("returnStringLength", Prototype{TypeDescriptor::Int(), string_type})};
+ Value result = returnStringLength.MakeRegister();
+ returnStringLength.AddInstruction(
+ Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
+ returnStringLength.BuildReturn(result);
+ returnStringLength.Encode();
+
+ slicer::MemView image{dex_file.CreateImage()};
+ std::ofstream out_file(outdir + "/simple.dex");
+ out_file.write(image.ptr<const char>(), image.size());
+}
+
+int main(int argc, char** argv) {
+ CHECK_EQ(argc, 2);
+
+ string outdir = argv[1];
+
+ GenerateTrivialDexFile(outdir);
+ GenerateSimpleTestCases(outdir);
+}
diff --git a/telecomm/java/android/telecom/Logging/EventManager.java b/telecomm/java/android/telecom/Logging/EventManager.java
index 2bda648..1342038 100644
--- a/telecomm/java/android/telecom/Logging/EventManager.java
+++ b/telecomm/java/android/telecom/Logging/EventManager.java
@@ -180,7 +180,7 @@
}
}
- private final List<Event> mEvents = new LinkedList<>();
+ private final List<Event> mEvents = Collections.synchronizedList(new LinkedList<>());
private final Loggable mRecordEntry;
public EventRecord(Loggable recordEntry) {
@@ -197,7 +197,7 @@
}
public List<Event> getEvents() {
- return mEvents;
+ return new LinkedList<>(mEvents);
}
public List<EventTiming> extractEventTimings() {
@@ -207,21 +207,24 @@
LinkedList<EventTiming> result = new LinkedList<>();
Map<String, PendingResponse> pendingResponses = new HashMap<>();
- for (Event event : mEvents) {
- if (requestResponsePairs.containsKey(event.eventId)) {
- // This event expects a response, so add that expected response to the maps
- // of pending events.
- for (EventManager.TimedEventPair p : requestResponsePairs.get(event.eventId)) {
- pendingResponses.put(p.mResponse, new PendingResponse(event.eventId,
- event.time, p.mTimeoutMillis, p.mName));
+ synchronized (mEvents) {
+ for (Event event : mEvents) {
+ if (requestResponsePairs.containsKey(event.eventId)) {
+ // This event expects a response, so add that expected response to the maps
+ // of pending events.
+ for (EventManager.TimedEventPair p : requestResponsePairs.get(
+ event.eventId)) {
+ pendingResponses.put(p.mResponse, new PendingResponse(event.eventId,
+ event.time, p.mTimeoutMillis, p.mName));
+ }
}
- }
- PendingResponse pendingResponse = pendingResponses.remove(event.eventId);
- if (pendingResponse != null) {
- long elapsedTime = event.time - pendingResponse.requestEventTimeMillis;
- if (elapsedTime < pendingResponse.timeoutMillis) {
- result.add(new EventTiming(pendingResponse.name, elapsedTime));
+ PendingResponse pendingResponse = pendingResponses.remove(event.eventId);
+ if (pendingResponse != null) {
+ long elapsedTime = event.time - pendingResponse.requestEventTimeMillis;
+ if (elapsedTime < pendingResponse.timeoutMillis) {
+ result.add(new EventTiming(pendingResponse.name, elapsedTime));
+ }
}
}
}
@@ -233,7 +236,8 @@
pw.print(mRecordEntry.getDescription());
pw.increaseIndent();
- for (Event event : mEvents) {
+ // Iterate over copy of events so that this doesn't hold the lock for too long.
+ for (Event event : getEvents()) {
pw.print(event.timestampString);
pw.print(" - ");
pw.print(event.eventId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3f9a533..fbc54ae6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1079,24 +1079,44 @@
"wfc_operator_error_codes_string_array";
/**
- * Indexes of SPN format strings in wfcSpnFormats and wfcDataSpnFormats.
+ * Indexes of SPN format strings in wfcSpnFormats.
*
* <p>Available options are:
* <ul>
- * <li> 0: %s</li>
- * <li> 1: %s Wi-Fi Calling</li>
- * <li> 2: WLAN Call</li>
- * <li> 3: %s WLAN Call</li>
- * <li> 4: %s Wi-Fi</li>
- * <li> 5: WiFi Calling | %s</li>
- * <li> 6: %s VoWifi</li>
+ * <li> 0: %s</li>
+ * <li> 1: %s Wi-Fi Calling</li>
+ * <li> 2: WLAN Call</li>
+ * <li> 3: %s WLAN Call</li>
+ * <li> 4: %s Wi-Fi</li>
+ * <li> 5: WiFi Calling | %s</li>
+ * <li> 6: %s VoWifi</li>
+ * <li> 7: Wi-Fi Calling</li>
+ * <li> 8: Wi-Fi</li>
+ * <li> 9: WiFi Calling</li>
+ * <li> 10: VoWifi</li>
* @hide
*/
public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int";
- /** @hide */
+
+ /**
+ * Indexes of data SPN format strings in wfcSpnFormats.
+ *
+ * @see KEY_WFC_SPN_FORMAT_IDX_INT for available options.
+ * @hide
+ */
public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int";
/**
+ * Indexes of SPN format strings in wfcSpnFormats used during flight mode.
+ *
+ * Set to -1 to use the value from KEY_WFC_SPN_FORMAT_IDX_INT also in this case.
+ * @see KEY_WFC_SPN_FORMAT_IDX_INT for other available options.
+ * @hide
+ */
+ public static final String KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT =
+ "wfc_flight_mode_spn_format_idx_int";
+
+ /**
* Use root locale when reading wfcSpnFormats.
*
* If true, then the root locale will always be used when reading wfcSpnFormats. This means the
@@ -2456,6 +2476,7 @@
sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0);
+ sDefaults.putInt(KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT, -1);
sDefaults.putBoolean(KEY_WFC_SPN_USE_ROOT_LOCALE, false);
sDefaults.putString(KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING, "");
sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false);