diff options
13 files changed, 179 insertions, 25 deletions
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index b8ed05f73f46..a9fe34a9c0ff 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1427,17 +1427,32 @@ public final class InputMethodManager { * @see #startStylusHandwriting(View) */ public boolean isStylusHandwritingAvailable() { + return isStylusHandwritingAvailableAsUser(UserHandle.myUserId()); + } + + /** + * Returns {@code true} if currently selected IME supports Stylus handwriting & is enabled for + * the given userId. + * If the method returns {@code false}, {@link #startStylusHandwriting(View)} shouldn't be + * called and Stylus touch should continue as normal touch input. + * @see #startStylusHandwriting(View) + * @param userId user ID to query. + * @hide + */ + public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) { final Context fallbackContext = ActivityThread.currentApplication(); if (fallbackContext == null) { return false; } if (Settings.Global.getInt(fallbackContext.getContentResolver(), Settings.Global.STYLUS_HANDWRITING_ENABLED, 0) == 0) { - Log.d(TAG, "Stylus handwriting is not enabled in settings."); + if (DEBUG) { + Log.d(TAG, "Stylus handwriting is not enabled in settings."); + } return false; } try { - return mService.isStylusHandwritingAvailable(); + return mService.isStylusHandwritingAvailableAsUser(userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 508e4450d0f9..d550fef968a8 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -91,5 +91,5 @@ interface IInputMethodManager { /** Start Stylus handwriting session **/ void startStylusHandwriting(in IInputMethodClient client); /** Returns {@code true} if currently selected IME supports Stylus handwriting. */ - boolean isStylusHandwritingAvailable(); + boolean isStylusHandwritingAvailableAsUser(int userId); } diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml index 5e8b892018eb..2b3d11b0e191 100644 --- a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml +++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml @@ -14,20 +14,19 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<!-- TODO(b/203800646): layout_marginTop doesn't seem to work on some large screens. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/media_ttt_receiver_chip" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@drawable/media_ttt_chip_background_receiver" > <com.android.internal.widget.CachingIconView android:id="@+id/app_icon" android:layout_width="@dimen/media_ttt_icon_size_receiver" android:layout_height="@dimen/media_ttt_icon_size_receiver" - android:layout_gravity="center" + android:layout_gravity="center|bottom" + android:alpha="0.0" /> </FrameLayout> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 1210b79d3ff5..009a123de40c 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1051,6 +1051,7 @@ <!-- Since the generic icon isn't circular, we need to scale it down so it still fits within the circular chip. --> <dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen> + <dimen name="media_ttt_receiver_vert_translation">20dp</dimen> <!-- Window magnification --> <dimen name="magnification_border_drag_size">35dp</dimen> diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java index e0b11d83bf75..15b16ff971ea 100644 --- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java @@ -22,7 +22,9 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.Color; +import android.graphics.Rect; import android.icu.text.NumberFormat; +import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -30,16 +32,24 @@ import androidx.annotation.VisibleForTesting; import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.clocks.AnimatableClockView; +import com.android.systemui.shared.navigationbar.RegionSamplingHelper; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.ViewController; import java.io.PrintWriter; import java.util.Locale; import java.util.Objects; +import java.util.Optional; import java.util.TimeZone; +import java.util.concurrent.Executor; + +import javax.inject.Inject; /** * Controller for an AnimatableClockView on the keyguard. Instantiated by @@ -54,7 +64,10 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final BatteryController mBatteryController; private final int mDozingColor = Color.WHITE; + private Optional<RegionSamplingHelper> mRegionSamplingHelper = Optional.empty(); + private Rect mSamplingBounds = new Rect(); private int mLockScreenColor; + private final boolean mRegionSamplingEnabled; private boolean mIsDozing; private boolean mIsCharging; @@ -67,13 +80,17 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie private final float mBurmeseLineSpacing; private final float mDefaultLineSpacing; + @Inject public AnimatableClockController( AnimatableClockView view, StatusBarStateController statusBarStateController, BroadcastDispatcher broadcastDispatcher, BatteryController batteryController, KeyguardUpdateMonitor keyguardUpdateMonitor, - @Main Resources resources + @Main Resources resources, + @Main Executor mainExecutor, + @Background Executor bgExecutor, + FeatureFlags featureFlags ) { super(view); mStatusBarStateController = statusBarStateController; @@ -86,6 +103,40 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie R.dimen.keyguard_clock_line_spacing_scale_burmese); mDefaultLineSpacing = resources.getFloat( R.dimen.keyguard_clock_line_spacing_scale); + + mRegionSamplingEnabled = featureFlags.isEnabled(Flags.REGION_SAMPLING); + if (!mRegionSamplingEnabled) { + return; + } + + mRegionSamplingHelper = Optional.of(new RegionSamplingHelper(mView, + new RegionSamplingHelper.SamplingCallback() { + @Override + public void onRegionDarknessChanged(boolean isRegionDark) { + if (isRegionDark) { + mLockScreenColor = Color.WHITE; + } else { + mLockScreenColor = Color.BLACK; + } + initColors(); + } + + @Override + public Rect getSampledRegion(View sampledView) { + mSamplingBounds = new Rect(sampledView.getLeft(), sampledView.getTop(), + sampledView.getRight(), sampledView.getBottom()); + return mSamplingBounds; + } + + @Override + public boolean isSamplingEnabled() { + return mRegionSamplingEnabled; + } + }, mainExecutor, bgExecutor) + ); + mRegionSamplingHelper.ifPresent((regionSamplingHelper) -> { + regionSamplingHelper.setWindowVisible(true); + }); } private void reset() { @@ -169,6 +220,10 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie mStatusBarStateController.addCallback(mStatusBarStateListener); + mRegionSamplingHelper.ifPresent((regionSamplingHelper) -> { + regionSamplingHelper.start(mSamplingBounds); + }); + refreshTime(); initColors(); mView.animateDoze(mIsDozing, false); @@ -180,6 +235,9 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); mBatteryController.removeCallback(mBatteryCallback); mStatusBarStateController.removeCallback(mStatusBarStateListener); + mRegionSamplingHelper.ifPresent((regionSamplingHelper) -> { + regionSamplingHelper.stop(); + }); } /** Animate the clock appearance */ @@ -223,8 +281,10 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie } private void initColors() { - mLockScreenColor = Utils.getColorAttrDefaultColor(getContext(), - com.android.systemui.R.attr.wallpaperTextColorAccent); + if (!mRegionSamplingEnabled) { + mLockScreenColor = Utils.getColorAttrDefaultColor(getContext(), + com.android.systemui.R.attr.wallpaperTextColorAccent); + } mView.setColors(mDozingColor, mLockScreenColor); mView.animateDoze(mIsDozing, false); } @@ -235,5 +295,8 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie public void dump(@NonNull PrintWriter pw) { pw.println(this); mView.dump(pw); + mRegionSamplingHelper.ifPresent((regionSamplingHelper) -> { + regionSamplingHelper.dump(pw); + }); } } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 064388fa4514..2fa104a7ce18 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -162,6 +162,11 @@ public class Flags { new ResourceBooleanFlag(800, R.bool.flag_monet); /***************************************/ + // 801 - region sampling + public static final BooleanFlag REGION_SAMPLING = + new BooleanFlag(801, false); + + /***************************************/ // 900 - media public static final BooleanFlag MEDIA_TAP_TO_TRANSFER = new BooleanFlag(900, true); public static final BooleanFlag MEDIA_SESSION_ACTIONS = new BooleanFlag(901, false); diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt index fe1ac80e24df..0f1cdcc3fa5b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt @@ -25,17 +25,14 @@ import android.graphics.drawable.Drawable import android.os.PowerManager import android.os.SystemClock import android.util.Log -import android.view.Gravity import android.view.LayoutInflater import android.view.MotionEvent -import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.view.accessibility.AccessibilityManager import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT -import android.widget.LinearLayout import com.android.internal.widget.CachingIconView import com.android.settingslib.Utils import com.android.systemui.R @@ -65,12 +62,15 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>( private val powerManager: PowerManager, @LayoutRes private val chipLayoutRes: Int ) { - /** The window layout parameters we'll use when attaching the view to a window. */ + + /** + * Window layout params that will be used as a starting point for the [windowLayoutParams] of + * all subclasses. + */ @SuppressLint("WrongConstant") // We're allowed to use TYPE_VOLUME_OVERLAY - private val windowLayoutParams = WindowManager.LayoutParams().apply { + internal val commonWindowLayoutParams = WindowManager.LayoutParams().apply { width = WindowManager.LayoutParams.WRAP_CONTENT height = WindowManager.LayoutParams.WRAP_CONTENT - gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL title = WINDOW_TITLE @@ -78,6 +78,14 @@ abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>( setTrustedOverlay() } + /** + * The window layout parameters we'll use when attaching the view to a window. + * + * Subclasses must override this to provide their specific layout params, and they should use + * [commonWindowLayoutParams] as part of their layout params. + */ + internal abstract val windowLayoutParams: WindowManager.LayoutParams + /** The chip view currently being displayed. Null if the chip is not being displayed. */ private var chipView: ViewGroup? = null diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt index a5d763c5327b..f9818f0ad8be 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt @@ -24,6 +24,8 @@ import android.media.MediaRoute2Info import android.os.Handler import android.os.PowerManager import android.util.Log +import android.view.Gravity +import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.view.accessibility.AccessibilityManager @@ -36,6 +38,7 @@ import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCom import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.gesture.TapGestureDetector +import com.android.systemui.util.animation.AnimationUtil.Companion.frames import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.view.ViewUtil import javax.inject.Inject @@ -69,6 +72,11 @@ class MediaTttChipControllerReceiver @Inject constructor( powerManager, R.layout.media_ttt_chip_receiver ) { + override val windowLayoutParams = commonWindowLayoutParams.apply { + height = getWindowHeight() + gravity = Gravity.BOTTOM.or(Gravity.CENTER_HORIZONTAL) + } + private val commandQueueCallbacks = object : CommandQueue.Callbacks { override fun updateMediaTapToTransferReceiverDisplay( @StatusBarManager.MediaTransferReceiverState displayState: Int, @@ -131,6 +139,19 @@ class MediaTttChipControllerReceiver @Inject constructor( ) } + override fun animateChipIn(chipView: ViewGroup) { + val appIconView = chipView.requireViewById<View>(R.id.app_icon) + appIconView.animate() + .translationYBy(-1 * getTranslationAmount().toFloat()) + .setDuration(30.frames) + .start() + appIconView.animate() + .alpha(1f) + .setDuration(5.frames) + .start() + + } + override fun getIconSize(isAppIcon: Boolean): Int? = context.resources.getDimensionPixelSize( if (isAppIcon) { @@ -139,6 +160,17 @@ class MediaTttChipControllerReceiver @Inject constructor( R.dimen.media_ttt_generic_icon_size_receiver } ) + + private fun getWindowHeight(): Int { + return context.resources.getDimensionPixelSize(R.dimen.media_ttt_icon_size_receiver) + + // Make the window large enough to accommodate the animation amount + getTranslationAmount() + } + + /** Returns the amount that the chip will be translated by in its intro animation. */ + private fun getTranslationAmount(): Int { + return context.resources.getDimensionPixelSize(R.dimen.media_ttt_receiver_vert_translation) + } } data class ChipReceiverInfo( diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index 943604cff887..797a7701413b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -21,6 +21,7 @@ import android.content.Context import android.media.MediaRoute2Info import android.os.PowerManager import android.util.Log +import android.view.Gravity import android.view.View import android.view.ViewGroup import android.view.WindowManager @@ -69,6 +70,10 @@ class MediaTttChipControllerSender @Inject constructor( powerManager, R.layout.media_ttt_chip ) { + override val windowLayoutParams = commonWindowLayoutParams.apply { + gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) + } + private var currentlyDisplayedChipState: ChipStateSender? = null private val commandQueueCallbacks = object : CommandQueue.Callbacks { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java index df506b479b88..b5e9e8decb4c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/AnimatableClockControllerTest.java @@ -38,6 +38,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.Utils; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.clocks.AnimatableClockView; import com.android.systemui.statusbar.policy.BatteryController; @@ -53,6 +54,8 @@ import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; +import java.util.concurrent.Executor; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -69,6 +72,12 @@ public class AnimatableClockControllerTest extends SysuiTestCase { private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private Resources mResources; + @Mock + private Executor mMainExecutor; + @Mock + private Executor mBgExecutor; + @Mock + private FeatureFlags mFeatureFlags; private MockitoSession mStaticMockSession; private AnimatableClockController mAnimatableClockController; @@ -96,7 +105,10 @@ public class AnimatableClockControllerTest extends SysuiTestCase { mBroadcastDispatcher, mBatteryController, mKeyguardUpdateMonitor, - mResources + mResources, + mMainExecutor, + mBgExecutor, + mFeatureFlags ); mAnimatableClockController.init(); captureAttachListener(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt index 1527f0d0d71f..2eb478303cb2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt @@ -371,11 +371,9 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { powerManager, R.layout.media_ttt_chip ) { - override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) { - - } - - override fun getIconSize(isAppIcon: Boolean): Int? = ICON_SIZE + override val windowLayoutParams = commonWindowLayoutParams + override fun updateChipView(chipInfo: ChipInfo, currentChipView: ViewGroup) {} + override fun getIconSize(isAppIcon: Boolean): Int = ICON_SIZE } inner class ChipInfo : ChipInfoCommon { @@ -386,4 +384,4 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { private const val PACKAGE_NAME = "com.android.systemui" private const val APP_NAME = "Fake App Name" private const val TIMEOUT_MS = 10000L -private const val ICON_SIZE = 47
\ No newline at end of file +private const val ICON_SIZE = 47 diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 178b6bbe755e..132309e8efc4 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -5129,6 +5129,7 @@ public final class ProcessList { private static final String EXTRA_REQUESTER = "requester"; private static final String DROPBOX_TAG_IMPERCEPTIBLE_KILL = "imperceptible_app_kill"; + private static final boolean LOG_TO_DROPBOX = false; // uid -> killing information mapping private SparseArray<List<Bundle>> mWorkItems = new SparseArray<List<Bundle>>(); @@ -5234,7 +5235,7 @@ public final class ProcessList { private void handleDeviceIdle() { final DropBoxManager dbox = mService.mContext.getSystemService(DropBoxManager.class); - final boolean logToDropbox = dbox != null + final boolean logToDropbox = LOG_TO_DROPBOX && dbox != null && dbox.isTagEnabled(DROPBOX_TAG_IMPERCEPTIBLE_KILL); synchronized (mService) { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3fceba77567b..b45dc7ff0f6b 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2108,9 +2108,24 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } @Override - public boolean isStylusHandwritingAvailable() { + public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) { + if (UserHandle.getCallingUserId() != userId) { + mContext.enforceCallingPermission( + Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); + } + synchronized (ImfLock.class) { - return mBindingController.supportsStylusHandwriting(); + if (userId == mSettings.getCurrentUserId()) { + return mBindingController.supportsStylusHandwriting(); + } + + //TODO(b/197848765): This can be optimized by caching multi-user methodMaps/methodList. + //TODO(b/210039666): use cache. + final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId); + final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(), + mContext.getContentResolver(), methodMap, userId, true); + final InputMethodInfo imi = methodMap.get(settings.getSelectedInputMethod()); + return imi != null && imi.supportsStylusHandwriting(); } } |