Loading apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +14 −0 Original line number Diff line number Diff line Loading @@ -280,6 +280,20 @@ public interface AppStandbyInternal { */ boolean shouldNoteResponseEventForAllBroadcastSessions(); /** * Returns the list of roles whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. */ @NonNull List<String> getBroadcastResponseExemptedRoles(); /** * Returns the list of permissions whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. */ @NonNull List<String> getBroadcastResponseExemptedPermissions(); /** * Return the last known value corresponding to the {@code key} from * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController. Loading apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +73 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings.Global; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; Loading Loading @@ -420,6 +421,26 @@ public class AppStandbyController volatile boolean mNoteResponseEventForAllBroadcastSessions = ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS; /** * List of roles whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. * * The list of roles will be separated by '|' in the string. */ volatile String mBroadcastResponseExemptedRoles = ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES; volatile List<String> mBroadcastResponseExemptedRolesList = Collections.EMPTY_LIST; /** * List of permissions whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. * * The list of permissions will be separated by '|' in the string. */ volatile String mBroadcastResponseExemptedPermissions = ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS; volatile List<String> mBroadcastResponseExemptedPermissionsList = Collections.EMPTY_LIST; /** * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}. * Loading Loading @@ -1959,6 +1980,18 @@ public class AppStandbyController return mNoteResponseEventForAllBroadcastSessions; } @Override @NonNull public List<String> getBroadcastResponseExemptedRoles() { return mBroadcastResponseExemptedRolesList; } @Override @NonNull public List<String> getBroadcastResponseExemptedPermissions() { return mBroadcastResponseExemptedPermissionsList; } @Override @Nullable public String getAppStandbyConstant(@NonNull String key) { Loading Loading @@ -2311,6 +2344,14 @@ public class AppStandbyController pw.print(mNoteResponseEventForAllBroadcastSessions); pw.println(); pw.print(" mBroadcastResponseExemptedRoles"); pw.print(mBroadcastResponseExemptedRoles); pw.println(); pw.print(" mBroadcastResponseExemptedPermissions"); pw.print(mBroadcastResponseExemptedPermissions); pw.println(); pw.println(); pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); pw.print(" mAllowRestrictedBucket="); Loading Loading @@ -2795,6 +2836,10 @@ public class AppStandbyController "broadcast_sessions_with_response_duration_ms"; private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = "note_response_event_for_all_broadcast_sessions"; private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES = "brodacast_response_exempted_roles"; private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = "brodacast_response_exempted_permissions"; public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS = COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; Loading Loading @@ -2837,6 +2882,11 @@ public class AppStandbyController 2 * ONE_MINUTE; public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = true; private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES = ""; private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = ""; private final TextUtils.SimpleStringSplitter mStringPipeSplitter = new TextUtils.SimpleStringSplitter('|'); ConstantsObserver(Handler handler) { super(handler); Loading Loading @@ -2989,6 +3039,20 @@ public class AppStandbyController KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS, DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS); break; case KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES: mBroadcastResponseExemptedRoles = properties.getString( KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES, DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES); mBroadcastResponseExemptedRolesList = splitPipeSeparatedString( mBroadcastResponseExemptedRoles); break; case KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS: mBroadcastResponseExemptedPermissions = properties.getString( KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS, DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS); mBroadcastResponseExemptedPermissionsList = splitPipeSeparatedString( mBroadcastResponseExemptedPermissions); break; default: if (!timeThresholdsUpdated && (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD) Loading @@ -3003,6 +3067,15 @@ public class AppStandbyController } } private List<String> splitPipeSeparatedString(String string) { final List<String> values = new ArrayList<>(); mStringPipeSplitter.setString(string); while (mStringPipeSplitter.hasNext()) { values.add(mStringPipeSplitter.next()); } return values; } private void updateTimeThresholds() { // Query the values as an atomic set. final DeviceConfig.Properties screenThresholdProperties = Loading core/java/android/app/ActivityThread.java +22 −3 Original line number Diff line number Diff line Loading @@ -298,6 +298,11 @@ public final class ActivityThread extends ClientTransactionHandler /** Use background GC policy and default JIT threshold. */ private static final int VM_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1; /** The delay time for retrying to request DirectActions. */ private static final long REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS = 200; /** The max count for retrying to request DirectActions. */ private static final int REQUEST_DIRECT_ACTIONS_RETRY_MAX_COUNT = 7; /** * Denotes an invalid sequence number corresponding to a process state change. */ Loading Loading @@ -1864,7 +1869,8 @@ public final class ActivityThread extends ClientTransactionHandler cancellationCallback.sendResult(cancellationResult); } mH.sendMessage(PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions, ActivityThread.this, activityToken, interactor, cancellationSignal, callback)); ActivityThread.this, activityToken, interactor, cancellationSignal, callback, REQUEST_DIRECT_ACTIONS_RETRY_MAX_COUNT)); } @Override Loading Loading @@ -3970,7 +3976,7 @@ public final class ActivityThread extends ClientTransactionHandler /** Fetches the user actions for the corresponding activity */ private void handleRequestDirectActions(@NonNull IBinder activityToken, @NonNull IVoiceInteractor interactor, @NonNull CancellationSignal cancellationSignal, @NonNull RemoteCallback callback) { @NonNull RemoteCallback callback, int retryCount) { final ActivityClientRecord r = mActivities.get(activityToken); if (r == null) { Log.w(TAG, "requestDirectActions(): no activity for " + activityToken); Loading @@ -3978,7 +3984,20 @@ public final class ActivityThread extends ClientTransactionHandler return; } final int lifecycleState = r.getLifecycleState(); if (lifecycleState < ON_START || lifecycleState >= ON_STOP) { if (lifecycleState < ON_START) { // TODO(b/234173463): requestDirectActions callback should indicate errors if (retryCount > 0) { mH.sendMessageDelayed( PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions, ActivityThread.this, activityToken, interactor, cancellationSignal, callback, retryCount - 1), REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS); return; } Log.w(TAG, "requestDirectActions(" + r + "): wrong lifecycle: " + lifecycleState); callback.sendResult(null); return; } if (lifecycleState >= ON_STOP) { Log.w(TAG, "requestDirectActions(" + r + "): wrong lifecycle: " + lifecycleState); callback.sendResult(null); return; Loading core/java/android/app/WallpaperColors.java +52 −65 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import com.android.internal.graphics.cam.Cam; import com.android.internal.graphics.palette.CelebiQuantizer; import com.android.internal.graphics.palette.Palette; import com.android.internal.graphics.palette.VariationalKMeansQuantizer; import com.android.internal.util.ContrastColorUtil; import java.io.FileOutputStream; import java.lang.annotation.Retention; Loading Loading @@ -93,10 +94,18 @@ public final class WallpaperColors implements Parcelable { // using the area instead. This way our comparisons are aspect ratio independent. private static final int MAX_WALLPAPER_EXTRACTION_AREA = MAX_BITMAP_SIZE * MAX_BITMAP_SIZE; // Decides when dark theme is optimal for this wallpaper. // The midpoint of perceptual luminance, 50, is 18.42 in relative luminance. // ColorUtils.calculateLuminance returns relative luminance on a scale from 0 to 1. private static final float DARK_THEME_MEAN_LUMINANCE = 0.1842f; // When extracting the main colors, only consider colors // present in at least MIN_COLOR_OCCURRENCE of the image private static final float MIN_COLOR_OCCURRENCE = 0.05f; // Decides when dark theme is optimal for this wallpaper private static final float DARK_THEME_MEAN_LUMINANCE = 0.3f; // Minimum mean luminosity that an image needs to have to support dark text private static final float BRIGHT_IMAGE_MEAN_LUMINANCE = 0.7f; // We also check if the image has dark pixels in it, // to avoid bright images with some dark spots. private static final float DARK_PIXEL_CONTRAST = 5.5f; private static final float MAX_DARK_AREA = 0.05f; private final List<Color> mMainColors; private final Map<Integer, Integer> mAllColors; Loading Loading @@ -244,9 +253,12 @@ public final class WallpaperColors implements Parcelable { this(primaryColor, secondaryColor, tertiaryColor, 0); // Calculate dark theme support based on primary color. final double relativeLuminance = ColorUtils.calculateLuminance(primaryColor.toArgb()); final boolean wallpaperIsDark = relativeLuminance < DARK_THEME_MEAN_LUMINANCE; mColorHints |= wallpaperIsDark ? HINT_SUPPORTS_DARK_THEME : HINT_SUPPORTS_DARK_TEXT; final float[] tmpHsl = new float[3]; ColorUtils.colorToHSL(primaryColor.toArgb(), tmpHsl); final float luminance = tmpHsl[2]; if (luminance < DARK_THEME_MEAN_LUMINANCE) { mColorHints |= HINT_SUPPORTS_DARK_THEME; } } /** Loading Loading @@ -524,6 +536,9 @@ public final class WallpaperColors implements Parcelable { dimAmount = MathUtils.saturate(dimAmount); int[] pixels = new int[source.getWidth() * source.getHeight()]; double totalLuminance = 0; final int maxDarkPixels = (int) (pixels.length * MAX_DARK_AREA); int darkPixels = 0; source.getPixels(pixels, 0 /* offset */, source.getWidth(), 0 /* x */, 0 /* y */, source.getWidth(), source.getHeight()); Loading @@ -532,70 +547,42 @@ public final class WallpaperColors implements Parcelable { int dimmingLayerAlpha = (int) (255 * dimAmount); int blackTransparent = ColorUtils.setAlphaComponent(Color.BLACK, dimmingLayerAlpha); // The median luminance in the wallpaper will be used to decide if it is light or dark. // // Calculating the luminances, adding them to a data structure, then selecting // the middle element would be expensive, the sort would be O(n), where n is the number // of pixels. // // Instead, we create an integer array with 101 elements initialized to zero. // Why 101? 0 through 100, inclusive, matching the range of luminance. // Then, for each pixel, the luminance is calculated, and the integer at the array index // equal to the rounded luminance is incremented. // // After processing the pixels, the median luminance is determined by iterating over the // array containing the count for each luminance. Starting from 0, we adding the count at // each index until pixels.length/2 is exceeded. When that occurs, it means the current // array index contains the pixel of median luminance, thus the current array index is the // median luminance. int[] luminanceCounts = new int[101]; // This bitmap was already resized to fit the maximum allowed area. // Let's just loop through the pixels, no sweat! float[] tmpHsl = new float[3]; for (int i = 0; i < pixels.length; i++) { int pixelColor = pixels[i]; ColorUtils.colorToHSL(pixelColor, tmpHsl); final int alpha = Color.alpha(pixelColor); if (alpha == 0) { continue; } // If the wallpaper is dimmed, apply dimming before calculating luminance. int compositeColor = dimAmount <= 0 ? pixelColor : ColorUtils.compositeColors(blackTransparent, pixelColor); // calculateLuminance will return relative luminance on a scale from 0 to 1. Intent // is normalize to 0 to 100, and that is done by defensively normalizing to // luminanceCounts.length, then flooring the result to defensively avoid any imprecision // in the result of calculateLuminance that could cause it to exceed 1 and thus the // array bounds. float relativeLuminance = (float) ColorUtils.calculateLuminance(compositeColor) * luminanceCounts.length - 1; int intRelativeLuminance = (int) Math.floor(relativeLuminance); int clampedRelativeLuminance = (intRelativeLuminance < 0) ? 0 : (intRelativeLuminance > luminanceCounts.length - 1) ? luminanceCounts.length - 1 : intRelativeLuminance; luminanceCounts[clampedRelativeLuminance] += 1; } int criticalRelativeLuminance = 0; int luminancesProcessed = 0; int criticalLuminanceIndex = (int) Math.floor(pixels.length * 0.5); for (int i = 0; i < 100; i++) { luminancesProcessed += luminanceCounts[i]; if (luminancesProcessed > criticalLuminanceIndex) { criticalRelativeLuminance = i; break; } } // Wallpaper is dark if the median pixel is less than mid-gray. // // Relative luminance places mid-gray at 18.42, 19 is used since luminances were rounded to // ints to be stored in the array. // // Why not use perceptual luminance? It would require one more conversion step at each // pixel, or adding a function to convert relative luminance to perceptual luminance just // for this line. boolean wallpaperIsDark = criticalRelativeLuminance < 19; // Apply composite colors where the foreground is a black layer with an alpha value of // the dim amount and the background is the wallpaper pixel color. int compositeColors = ColorUtils.compositeColors(blackTransparent, pixelColor); // Calculate the adjusted luminance of the dimmed wallpaper pixel color. double adjustedLuminance = ColorUtils.calculateLuminance(compositeColors); // Make sure we don't have a dark pixel mass that will // make text illegible. final boolean satisfiesTextContrast = ContrastColorUtil .calculateContrast(pixelColor, Color.BLACK) > DARK_PIXEL_CONTRAST; if (!satisfiesTextContrast && alpha != 0) { darkPixels++; if (DEBUG_DARK_PIXELS) { pixels[i] = Color.RED; } } totalLuminance += adjustedLuminance; } int hints = 0; hints |= wallpaperIsDark ? HINT_SUPPORTS_DARK_THEME : HINT_SUPPORTS_DARK_TEXT; double meanLuminance = totalLuminance / pixels.length; if (meanLuminance > BRIGHT_IMAGE_MEAN_LUMINANCE && darkPixels < maxDarkPixels) { hints |= HINT_SUPPORTS_DARK_TEXT; } if (meanLuminance < DARK_THEME_MEAN_LUMINANCE) { hints |= HINT_SUPPORTS_DARK_THEME; } if (DEBUG_DARK_PIXELS) { try (FileOutputStream out = new FileOutputStream("/data/pixels.png")) { Loading @@ -605,8 +592,8 @@ public final class WallpaperColors implements Parcelable { } catch (Exception e) { e.printStackTrace(); } Log.d("WallpaperColors", "median relative L: " + criticalRelativeLuminance + ", numPixels: " + pixels.length); Log.d("WallpaperColors", "l: " + meanLuminance + ", d: " + darkPixels + " maxD: " + maxDarkPixels + " numPixels: " + pixels.length); } return hints; Loading core/java/android/view/InputWindowHandle.java +1 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,7 @@ public final class InputWindowHandle { .append(", scaleFactor=").append(scaleFactor) .append(", transform=").append(transform) .append(", windowToken=").append(windowToken) .append(", isClone=").append(isClone) .toString(); } Loading Loading
apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +14 −0 Original line number Diff line number Diff line Loading @@ -280,6 +280,20 @@ public interface AppStandbyInternal { */ boolean shouldNoteResponseEventForAllBroadcastSessions(); /** * Returns the list of roles whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. */ @NonNull List<String> getBroadcastResponseExemptedRoles(); /** * Returns the list of permissions whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. */ @NonNull List<String> getBroadcastResponseExemptedPermissions(); /** * Return the last known value corresponding to the {@code key} from * {@link android.provider.DeviceConfig#NAMESPACE_APP_STANDBY} in AppStandbyController. Loading
apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +73 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings.Global; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; Loading Loading @@ -420,6 +421,26 @@ public class AppStandbyController volatile boolean mNoteResponseEventForAllBroadcastSessions = ConstantsObserver.DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS; /** * List of roles whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. * * The list of roles will be separated by '|' in the string. */ volatile String mBroadcastResponseExemptedRoles = ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES; volatile List<String> mBroadcastResponseExemptedRolesList = Collections.EMPTY_LIST; /** * List of permissions whose holders are exempted from the requirement of starting * a response event after receiving a broadcast. * * The list of permissions will be separated by '|' in the string. */ volatile String mBroadcastResponseExemptedPermissions = ConstantsObserver.DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS; volatile List<String> mBroadcastResponseExemptedPermissionsList = Collections.EMPTY_LIST; /** * Map of last known values of keys in {@link DeviceConfig#NAMESPACE_APP_STANDBY}. * Loading Loading @@ -1959,6 +1980,18 @@ public class AppStandbyController return mNoteResponseEventForAllBroadcastSessions; } @Override @NonNull public List<String> getBroadcastResponseExemptedRoles() { return mBroadcastResponseExemptedRolesList; } @Override @NonNull public List<String> getBroadcastResponseExemptedPermissions() { return mBroadcastResponseExemptedPermissionsList; } @Override @Nullable public String getAppStandbyConstant(@NonNull String key) { Loading Loading @@ -2311,6 +2344,14 @@ public class AppStandbyController pw.print(mNoteResponseEventForAllBroadcastSessions); pw.println(); pw.print(" mBroadcastResponseExemptedRoles"); pw.print(mBroadcastResponseExemptedRoles); pw.println(); pw.print(" mBroadcastResponseExemptedPermissions"); pw.print(mBroadcastResponseExemptedPermissions); pw.println(); pw.println(); pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled); pw.print(" mAllowRestrictedBucket="); Loading Loading @@ -2795,6 +2836,10 @@ public class AppStandbyController "broadcast_sessions_with_response_duration_ms"; private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = "note_response_event_for_all_broadcast_sessions"; private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES = "brodacast_response_exempted_roles"; private static final String KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = "brodacast_response_exempted_permissions"; public static final long DEFAULT_CHECK_IDLE_INTERVAL_MS = COMPRESS_TIME ? ONE_MINUTE : 4 * ONE_HOUR; Loading Loading @@ -2837,6 +2882,11 @@ public class AppStandbyController 2 * ONE_MINUTE; public static final boolean DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS = true; private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES = ""; private static final String DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS = ""; private final TextUtils.SimpleStringSplitter mStringPipeSplitter = new TextUtils.SimpleStringSplitter('|'); ConstantsObserver(Handler handler) { super(handler); Loading Loading @@ -2989,6 +3039,20 @@ public class AppStandbyController KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS, DEFAULT_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS); break; case KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES: mBroadcastResponseExemptedRoles = properties.getString( KEY_BROADCAST_RESPONSE_EXEMPTED_ROLES, DEFAULT_BROADCAST_RESPONSE_EXEMPTED_ROLES); mBroadcastResponseExemptedRolesList = splitPipeSeparatedString( mBroadcastResponseExemptedRoles); break; case KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS: mBroadcastResponseExemptedPermissions = properties.getString( KEY_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS, DEFAULT_BROADCAST_RESPONSE_EXEMPTED_PERMISSIONS); mBroadcastResponseExemptedPermissionsList = splitPipeSeparatedString( mBroadcastResponseExemptedPermissions); break; default: if (!timeThresholdsUpdated && (name.startsWith(KEY_PREFIX_SCREEN_TIME_THRESHOLD) Loading @@ -3003,6 +3067,15 @@ public class AppStandbyController } } private List<String> splitPipeSeparatedString(String string) { final List<String> values = new ArrayList<>(); mStringPipeSplitter.setString(string); while (mStringPipeSplitter.hasNext()) { values.add(mStringPipeSplitter.next()); } return values; } private void updateTimeThresholds() { // Query the values as an atomic set. final DeviceConfig.Properties screenThresholdProperties = Loading
core/java/android/app/ActivityThread.java +22 −3 Original line number Diff line number Diff line Loading @@ -298,6 +298,11 @@ public final class ActivityThread extends ClientTransactionHandler /** Use background GC policy and default JIT threshold. */ private static final int VM_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1; /** The delay time for retrying to request DirectActions. */ private static final long REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS = 200; /** The max count for retrying to request DirectActions. */ private static final int REQUEST_DIRECT_ACTIONS_RETRY_MAX_COUNT = 7; /** * Denotes an invalid sequence number corresponding to a process state change. */ Loading Loading @@ -1864,7 +1869,8 @@ public final class ActivityThread extends ClientTransactionHandler cancellationCallback.sendResult(cancellationResult); } mH.sendMessage(PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions, ActivityThread.this, activityToken, interactor, cancellationSignal, callback)); ActivityThread.this, activityToken, interactor, cancellationSignal, callback, REQUEST_DIRECT_ACTIONS_RETRY_MAX_COUNT)); } @Override Loading Loading @@ -3970,7 +3976,7 @@ public final class ActivityThread extends ClientTransactionHandler /** Fetches the user actions for the corresponding activity */ private void handleRequestDirectActions(@NonNull IBinder activityToken, @NonNull IVoiceInteractor interactor, @NonNull CancellationSignal cancellationSignal, @NonNull RemoteCallback callback) { @NonNull RemoteCallback callback, int retryCount) { final ActivityClientRecord r = mActivities.get(activityToken); if (r == null) { Log.w(TAG, "requestDirectActions(): no activity for " + activityToken); Loading @@ -3978,7 +3984,20 @@ public final class ActivityThread extends ClientTransactionHandler return; } final int lifecycleState = r.getLifecycleState(); if (lifecycleState < ON_START || lifecycleState >= ON_STOP) { if (lifecycleState < ON_START) { // TODO(b/234173463): requestDirectActions callback should indicate errors if (retryCount > 0) { mH.sendMessageDelayed( PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions, ActivityThread.this, activityToken, interactor, cancellationSignal, callback, retryCount - 1), REQUEST_DIRECT_ACTIONS_RETRY_TIME_MS); return; } Log.w(TAG, "requestDirectActions(" + r + "): wrong lifecycle: " + lifecycleState); callback.sendResult(null); return; } if (lifecycleState >= ON_STOP) { Log.w(TAG, "requestDirectActions(" + r + "): wrong lifecycle: " + lifecycleState); callback.sendResult(null); return; Loading
core/java/android/app/WallpaperColors.java +52 −65 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import com.android.internal.graphics.cam.Cam; import com.android.internal.graphics.palette.CelebiQuantizer; import com.android.internal.graphics.palette.Palette; import com.android.internal.graphics.palette.VariationalKMeansQuantizer; import com.android.internal.util.ContrastColorUtil; import java.io.FileOutputStream; import java.lang.annotation.Retention; Loading Loading @@ -93,10 +94,18 @@ public final class WallpaperColors implements Parcelable { // using the area instead. This way our comparisons are aspect ratio independent. private static final int MAX_WALLPAPER_EXTRACTION_AREA = MAX_BITMAP_SIZE * MAX_BITMAP_SIZE; // Decides when dark theme is optimal for this wallpaper. // The midpoint of perceptual luminance, 50, is 18.42 in relative luminance. // ColorUtils.calculateLuminance returns relative luminance on a scale from 0 to 1. private static final float DARK_THEME_MEAN_LUMINANCE = 0.1842f; // When extracting the main colors, only consider colors // present in at least MIN_COLOR_OCCURRENCE of the image private static final float MIN_COLOR_OCCURRENCE = 0.05f; // Decides when dark theme is optimal for this wallpaper private static final float DARK_THEME_MEAN_LUMINANCE = 0.3f; // Minimum mean luminosity that an image needs to have to support dark text private static final float BRIGHT_IMAGE_MEAN_LUMINANCE = 0.7f; // We also check if the image has dark pixels in it, // to avoid bright images with some dark spots. private static final float DARK_PIXEL_CONTRAST = 5.5f; private static final float MAX_DARK_AREA = 0.05f; private final List<Color> mMainColors; private final Map<Integer, Integer> mAllColors; Loading Loading @@ -244,9 +253,12 @@ public final class WallpaperColors implements Parcelable { this(primaryColor, secondaryColor, tertiaryColor, 0); // Calculate dark theme support based on primary color. final double relativeLuminance = ColorUtils.calculateLuminance(primaryColor.toArgb()); final boolean wallpaperIsDark = relativeLuminance < DARK_THEME_MEAN_LUMINANCE; mColorHints |= wallpaperIsDark ? HINT_SUPPORTS_DARK_THEME : HINT_SUPPORTS_DARK_TEXT; final float[] tmpHsl = new float[3]; ColorUtils.colorToHSL(primaryColor.toArgb(), tmpHsl); final float luminance = tmpHsl[2]; if (luminance < DARK_THEME_MEAN_LUMINANCE) { mColorHints |= HINT_SUPPORTS_DARK_THEME; } } /** Loading Loading @@ -524,6 +536,9 @@ public final class WallpaperColors implements Parcelable { dimAmount = MathUtils.saturate(dimAmount); int[] pixels = new int[source.getWidth() * source.getHeight()]; double totalLuminance = 0; final int maxDarkPixels = (int) (pixels.length * MAX_DARK_AREA); int darkPixels = 0; source.getPixels(pixels, 0 /* offset */, source.getWidth(), 0 /* x */, 0 /* y */, source.getWidth(), source.getHeight()); Loading @@ -532,70 +547,42 @@ public final class WallpaperColors implements Parcelable { int dimmingLayerAlpha = (int) (255 * dimAmount); int blackTransparent = ColorUtils.setAlphaComponent(Color.BLACK, dimmingLayerAlpha); // The median luminance in the wallpaper will be used to decide if it is light or dark. // // Calculating the luminances, adding them to a data structure, then selecting // the middle element would be expensive, the sort would be O(n), where n is the number // of pixels. // // Instead, we create an integer array with 101 elements initialized to zero. // Why 101? 0 through 100, inclusive, matching the range of luminance. // Then, for each pixel, the luminance is calculated, and the integer at the array index // equal to the rounded luminance is incremented. // // After processing the pixels, the median luminance is determined by iterating over the // array containing the count for each luminance. Starting from 0, we adding the count at // each index until pixels.length/2 is exceeded. When that occurs, it means the current // array index contains the pixel of median luminance, thus the current array index is the // median luminance. int[] luminanceCounts = new int[101]; // This bitmap was already resized to fit the maximum allowed area. // Let's just loop through the pixels, no sweat! float[] tmpHsl = new float[3]; for (int i = 0; i < pixels.length; i++) { int pixelColor = pixels[i]; ColorUtils.colorToHSL(pixelColor, tmpHsl); final int alpha = Color.alpha(pixelColor); if (alpha == 0) { continue; } // If the wallpaper is dimmed, apply dimming before calculating luminance. int compositeColor = dimAmount <= 0 ? pixelColor : ColorUtils.compositeColors(blackTransparent, pixelColor); // calculateLuminance will return relative luminance on a scale from 0 to 1. Intent // is normalize to 0 to 100, and that is done by defensively normalizing to // luminanceCounts.length, then flooring the result to defensively avoid any imprecision // in the result of calculateLuminance that could cause it to exceed 1 and thus the // array bounds. float relativeLuminance = (float) ColorUtils.calculateLuminance(compositeColor) * luminanceCounts.length - 1; int intRelativeLuminance = (int) Math.floor(relativeLuminance); int clampedRelativeLuminance = (intRelativeLuminance < 0) ? 0 : (intRelativeLuminance > luminanceCounts.length - 1) ? luminanceCounts.length - 1 : intRelativeLuminance; luminanceCounts[clampedRelativeLuminance] += 1; } int criticalRelativeLuminance = 0; int luminancesProcessed = 0; int criticalLuminanceIndex = (int) Math.floor(pixels.length * 0.5); for (int i = 0; i < 100; i++) { luminancesProcessed += luminanceCounts[i]; if (luminancesProcessed > criticalLuminanceIndex) { criticalRelativeLuminance = i; break; } } // Wallpaper is dark if the median pixel is less than mid-gray. // // Relative luminance places mid-gray at 18.42, 19 is used since luminances were rounded to // ints to be stored in the array. // // Why not use perceptual luminance? It would require one more conversion step at each // pixel, or adding a function to convert relative luminance to perceptual luminance just // for this line. boolean wallpaperIsDark = criticalRelativeLuminance < 19; // Apply composite colors where the foreground is a black layer with an alpha value of // the dim amount and the background is the wallpaper pixel color. int compositeColors = ColorUtils.compositeColors(blackTransparent, pixelColor); // Calculate the adjusted luminance of the dimmed wallpaper pixel color. double adjustedLuminance = ColorUtils.calculateLuminance(compositeColors); // Make sure we don't have a dark pixel mass that will // make text illegible. final boolean satisfiesTextContrast = ContrastColorUtil .calculateContrast(pixelColor, Color.BLACK) > DARK_PIXEL_CONTRAST; if (!satisfiesTextContrast && alpha != 0) { darkPixels++; if (DEBUG_DARK_PIXELS) { pixels[i] = Color.RED; } } totalLuminance += adjustedLuminance; } int hints = 0; hints |= wallpaperIsDark ? HINT_SUPPORTS_DARK_THEME : HINT_SUPPORTS_DARK_TEXT; double meanLuminance = totalLuminance / pixels.length; if (meanLuminance > BRIGHT_IMAGE_MEAN_LUMINANCE && darkPixels < maxDarkPixels) { hints |= HINT_SUPPORTS_DARK_TEXT; } if (meanLuminance < DARK_THEME_MEAN_LUMINANCE) { hints |= HINT_SUPPORTS_DARK_THEME; } if (DEBUG_DARK_PIXELS) { try (FileOutputStream out = new FileOutputStream("/data/pixels.png")) { Loading @@ -605,8 +592,8 @@ public final class WallpaperColors implements Parcelable { } catch (Exception e) { e.printStackTrace(); } Log.d("WallpaperColors", "median relative L: " + criticalRelativeLuminance + ", numPixels: " + pixels.length); Log.d("WallpaperColors", "l: " + meanLuminance + ", d: " + darkPixels + " maxD: " + maxDarkPixels + " numPixels: " + pixels.length); } return hints; Loading
core/java/android/view/InputWindowHandle.java +1 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,7 @@ public final class InputWindowHandle { .append(", scaleFactor=").append(scaleFactor) .append(", transform=").append(transform) .append(", windowToken=").append(windowToken) .append(", isClone=").append(isClone) .toString(); } Loading