Merge "Add Note Task shortcut" into tm-qpr-dev

This commit is contained in:
Marcello Galhardo
2022-12-06 17:55:37 +00:00
committed by Android (Google) Code Review
10 changed files with 364 additions and 48 deletions

View File

@@ -904,6 +904,29 @@
<service android:name=".controls.controller.AuxiliaryPersistenceWrapper$DeletionJobService" <service android:name=".controls.controller.AuxiliaryPersistenceWrapper$DeletionJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/> android:permission="android.permission.BIND_JOB_SERVICE"/>
<!-- region Note Task -->
<activity
android:name=".notetask.shortcut.CreateNoteTaskShortcutActivity"
android:enabled="false"
android:exported="true"
android:excludeFromRecents="true"
android:theme="@android:style/Theme.NoDisplay"
android:label="@string/note_task_button_label"
android:icon="@drawable/ic_note_task_button">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".notetask.shortcut.LaunchNoteTaskActivity"
android:exported="true"
android:excludeFromRecents="true"
android:theme="@android:style/Theme.NoDisplay" />
<!-- endregion -->
<!-- started from ControlsRequestReceiver --> <!-- started from ControlsRequestReceiver -->
<activity <activity
android:name=".controls.management.ControlsRequestDialog" android:name=".controls.management.ControlsRequestDialog"

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2022 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#636C6F"
android:pathData="M17.6258,4.96L19.0358,6.37L7.4058,18.01L5.9958,16.6L17.6258,4.96ZM16.1358,3.62L4.1258,15.63L3.0158,19.83C2.9058,20.45 3.3858,21 3.9958,21C4.0558,21 4.1058,21 4.1658,20.99L8.3658,19.88L20.3758,7.86C20.7758,7.46 20.9958,6.93 20.9958,6.37C20.9958,5.81 20.7758,5.28 20.3758,4.88L19.1058,3.61C18.7158,3.22 18.1858,3 17.6258,3C17.0658,3 16.5358,3.22 16.1358,3.62Z" />
<path
android:fillColor="#636C6F"
android:fillType="evenOdd"
android:pathData="M20.1936,15.3369C20.3748,16.3837 19.9151,17.5414 18.8846,18.7597C19.1546,18.872 19.4576,18.9452 19.7724,18.9867C20.0839,19.0278 20.3683,19.0325 20.5749,19.0266C20.6772,19.0236 20.7578,19.0181 20.8101,19.0138C20.8362,19.0116 20.855,19.0097 20.8657,19.0085L20.8754,19.0074L20.875,19.0075C21.4217,18.9385 21.9214,19.325 21.9918,19.8718C22.0624,20.4195 21.6756,20.9208 21.1279,20.9914L21,19.9996C21.1279,20.9914 21.1265,20.9916 21.1265,20.9916L21.1249,20.9918L21.1211,20.9923L21.1107,20.9935L21.0795,20.997C21.0542,20.9998 21.0199,21.0032 20.9775,21.0067C20.8929,21.0138 20.7753,21.0216 20.6323,21.0257C20.3481,21.0339 19.9533,21.0279 19.5109,20.9695C18.873,20.8854 18.0393,20.6793 17.3106,20.1662C16.9605,20.3559 16.5876,20.4952 16.2299,20.6003C15.5742,20.7927 14.8754,20.8968 14.2534,20.9534C13.6801,21.0055 13.4553,21.0037 13.1015,21.0008C13.0689,21.0005 13.0352,21.0002 13,21H12.8594C12.8214,21.0002 12.785,21.0006 12.7504,21.0009C12.6524,21.0019 12.5683,21.0027 12.5,21H12.0562C12.0277,21.0003 12.0054,21.0006 11.9926,21.001L11.9751,21H9L11,19H11.9795C11.9929,18.9997 12.0064,18.9997 12.0199,19H12.4117C12.4534,18.9996 12.4864,18.9995 12.5,19H12.9675C12.977,18.9999 12.9878,18.9999 13,19C13.0446,19.0003 13.0859,19.0007 13.1249,19.0011C13.4259,19.0038 13.591,19.0054 14.0723,18.9616C14.6201,18.9118 15.1795,18.8242 15.6665,18.6813C15.753,18.6559 15.8346,18.6295 15.9114,18.6022C15.0315,17.2981 14.7125,16.1044 15.015,15.0829C15.4095,13.7511 16.6784,13.2418 17.7026,13.2864C18.7262,13.3309 19.954,13.9529 20.1936,15.3369ZM16.9327,15.6508C16.873,15.8523 16.8651,16.3878 17.4697,17.334C18.2007,16.4284 18.2585,15.8839 18.2229,15.6781C18.1939,15.5108 18.0297,15.3025 17.6157,15.2845C17.2025,15.2665 16.9885,15.4626 16.9327,15.6508Z" />
</vector>

View File

@@ -2669,6 +2669,10 @@
<xliff:g id="weather_condition" example="Partly cloudy">%1$s</xliff:g>, <xliff:g id="temperature" example="7°C">%2$s</xliff:g> <xliff:g id="weather_condition" example="Partly cloudy">%1$s</xliff:g>, <xliff:g id="temperature" example="7°C">%2$s</xliff:g>
</string> </string>
<!-- TODO(b/259369672): Replace with final resource. -->
<!-- [CHAR LIMIT=30] Label used to open Note Task -->
<string name="note_task_button_label">Notetaking</string>
<!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, media app is broadcasting --> <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, media app is broadcasting -->
<string name="broadcasting_description_is_broadcasting">Broadcasting</string> <string name="broadcasting_description_is_broadcasting">Broadcasting</string>
<!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, title --> <!-- [CHAR LIMIT=NONE] Le audio broadcast dialog, title -->

View File

@@ -17,10 +17,12 @@
package com.android.systemui.notetask package com.android.systemui.notetask
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.pm.PackageManager
import android.os.UserManager import android.os.UserManager
import android.view.KeyEvent
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.util.kotlin.getOrNull import com.android.systemui.util.kotlin.getOrNull
import com.android.wm.shell.bubbles.Bubbles import com.android.wm.shell.bubbles.Bubbles
import java.util.Optional import java.util.Optional
@@ -45,15 +47,22 @@ constructor(
@NoteTaskEnabledKey private val isEnabled: Boolean, @NoteTaskEnabledKey private val isEnabled: Boolean,
) { ) {
fun handleSystemKey(keyCode: Int) { /**
* Shows a note task. How the task is shown will depend on when the method is invoked.
*
* If in multi-window mode, notes will open as a full screen experience. That is particularly
* important for Large screen devices. These devices may support a taskbar that let users to
* drag and drop a shortcut into multi-window mode, and notes should comply with this behaviour.
*
* If the keyguard is locked, notes will open as a full screen experience. A locked device has
* no contextual information which let us use the whole screen space available.
*
* If no in multi-window or the keyguard is unlocked, notes will open as a floating experience.
* That will let users open other apps in full screen, and take contextual notes.
*/
fun showNoteTask(isInMultiWindowMode: Boolean = false) {
if (!isEnabled) return if (!isEnabled) return
if (keyCode == KeyEvent.KEYCODE_VIDEO_APP_1) {
showNoteTask()
}
}
private fun showNoteTask() {
val bubbles = optionalBubbles.getOrNull() ?: return val bubbles = optionalBubbles.getOrNull() ?: return
val keyguardManager = optionalKeyguardManager.getOrNull() ?: return val keyguardManager = optionalKeyguardManager.getOrNull() ?: return
val userManager = optionalUserManager.getOrNull() ?: return val userManager = optionalUserManager.getOrNull() ?: return
@@ -62,11 +71,35 @@ constructor(
// TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing. // TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
if (!userManager.isUserUnlocked) return if (!userManager.isUserUnlocked) return
if (keyguardManager.isKeyguardLocked) { if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
context.startActivity(intent) context.startActivity(intent)
} else { } else {
// TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter. // TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter.
bubbles.showAppBubble(intent) bubbles.showAppBubble(intent)
} }
} }
/**
* Set `android:enabled` property in the `AndroidManifest` associated with the Shortcut
* component to [value].
*
* If the shortcut entry `android:enabled` is set to `true`, the shortcut will be visible in the
* Widget Picker to all users.
*/
fun setNoteTaskShortcutEnabled(value: Boolean) {
val componentName = ComponentName(context, CreateNoteTaskShortcutActivity::class.java)
val enabledState =
if (value) {
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
} else {
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
}
context.packageManager.setComponentEnabledSetting(
componentName,
enabledState,
PackageManager.DONT_KILL_APP,
)
}
} }

View File

@@ -16,9 +16,10 @@
package com.android.systemui.notetask package com.android.systemui.notetask
import android.view.KeyEvent
import androidx.annotation.VisibleForTesting
import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.CommandQueue
import com.android.wm.shell.bubbles.Bubbles import com.android.wm.shell.bubbles.Bubbles
import dagger.Lazy
import java.util.Optional import java.util.Optional
import javax.inject.Inject import javax.inject.Inject
@@ -27,15 +28,18 @@ internal class NoteTaskInitializer
@Inject @Inject
constructor( constructor(
private val optionalBubbles: Optional<Bubbles>, private val optionalBubbles: Optional<Bubbles>,
private val lazyNoteTaskController: Lazy<NoteTaskController>, private val noteTaskController: NoteTaskController,
private val commandQueue: CommandQueue, private val commandQueue: CommandQueue,
@NoteTaskEnabledKey private val isEnabled: Boolean, @NoteTaskEnabledKey private val isEnabled: Boolean,
) { ) {
private val callbacks = @VisibleForTesting
val callbacks =
object : CommandQueue.Callbacks { object : CommandQueue.Callbacks {
override fun handleSystemKey(keyCode: Int) { override fun handleSystemKey(keyCode: Int) {
lazyNoteTaskController.get().handleSystemKey(keyCode) if (keyCode == KeyEvent.KEYCODE_VIDEO_APP_1) {
noteTaskController.showNoteTask()
}
} }
} }
@@ -43,5 +47,6 @@ constructor(
if (isEnabled && optionalBubbles.isPresent) { if (isEnabled && optionalBubbles.isPresent) {
commandQueue.addCallback(callbacks) commandQueue.addCallback(callbacks)
} }
noteTaskController.setNoteTaskShortcutEnabled(isEnabled)
} }
} }

View File

@@ -16,19 +16,33 @@
package com.android.systemui.notetask package com.android.systemui.notetask
import android.app.Activity
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.os.UserManager import android.os.UserManager
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import java.util.* import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
import java.util.Optional
/** Compose all dependencies required by Note Task feature. */ /** Compose all dependencies required by Note Task feature. */
@Module @Module
internal class NoteTaskModule { internal interface NoteTaskModule {
@[Binds IntoMap ClassKey(LaunchNoteTaskActivity::class)]
fun bindNoteTaskLauncherActivity(activity: LaunchNoteTaskActivity): Activity?
@[Binds IntoMap ClassKey(CreateNoteTaskShortcutActivity::class)]
fun bindNoteTaskShortcutActivity(activity: CreateNoteTaskShortcutActivity): Activity?
companion object {
@[Provides NoteTaskEnabledKey] @[Provides NoteTaskEnabledKey]
fun provideIsNoteTaskEnabled(featureFlags: FeatureFlags): Boolean { fun provideIsNoteTaskEnabled(featureFlags: FeatureFlags): Boolean {
@@ -44,4 +58,5 @@ internal class NoteTaskModule {
fun provideOptionalUserManager(context: Context): Optional<UserManager> { fun provideOptionalUserManager(context: Context): Optional<UserManager> {
return Optional.ofNullable(context.getSystemService()) return Optional.ofNullable(context.getSystemService())
} }
}
} }

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.notetask.shortcut
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.annotation.DrawableRes
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.android.systemui.R
import javax.inject.Inject
/**
* Activity responsible for create a shortcut for notes action. If the shortcut is enabled, a new
* shortcut will appear in the widget picker. If the shortcut is selected, the Activity here will be
* launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish.
*
* @see <a
* href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating
* a custom shortcut activity</a>
*/
internal class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intent =
createShortcutIntent(
id = SHORTCUT_ID,
shortLabel = getString(R.string.note_task_button_label),
intent = LaunchNoteTaskActivity.newIntent(context = this),
iconResource = R.drawable.ic_note_task_button,
)
setResult(Activity.RESULT_OK, intent)
finish()
}
private fun createShortcutIntent(
id: String,
shortLabel: String,
intent: Intent,
@DrawableRes iconResource: Int,
): Intent {
val shortcutInfo =
ShortcutInfoCompat.Builder(this, id)
.setIntent(intent)
.setShortLabel(shortLabel)
.setLongLived(true)
.setIcon(IconCompat.createWithResource(this, iconResource))
.build()
return ShortcutManagerCompat.createShortcutResultIntent(
this,
shortcutInfo,
)
}
private companion object {
private const val SHORTCUT_ID = "note-task-shortcut-id"
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.notetask.shortcut
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskIntentResolver
import javax.inject.Inject
/** Activity responsible for launching the note experience, and finish. */
internal class LaunchNoteTaskActivity
@Inject
constructor(
private val noteTaskController: NoteTaskController,
) : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
noteTaskController.showNoteTask(isInMultiWindowMode)
finish()
}
companion object {
/** Creates a new [Intent] set to start [LaunchNoteTaskActivity]. */
fun newIntent(context: Context): Intent {
return Intent(context, LaunchNoteTaskActivity::class.java).apply {
// Intent's action must be set in shortcuts, or an exception will be thrown.
// TODO(b/254606432): Use Intent.ACTION_NOTES instead.
action = NoteTaskIntentResolver.NOTES_ACTION
}
}
}
}

View File

@@ -16,16 +16,21 @@
package com.android.systemui.notetask package com.android.systemui.notetask
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.UserManager import android.os.UserManager
import android.test.suitebuilder.annotation.SmallTest import android.test.suitebuilder.annotation.SmallTest
import android.view.KeyEvent
import androidx.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.NOTES_ACTION import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.NOTES_ACTION
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.android.wm.shell.bubbles.Bubbles import com.android.wm.shell.bubbles.Bubbles
import com.google.common.truth.Truth.assertThat
import java.util.Optional import java.util.Optional
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@@ -48,6 +53,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
private val notesIntent = Intent(NOTES_ACTION) private val notesIntent = Intent(NOTES_ACTION)
@Mock lateinit var context: Context @Mock lateinit var context: Context
@Mock lateinit var packageManager: PackageManager
@Mock lateinit var noteTaskIntentResolver: NoteTaskIntentResolver @Mock lateinit var noteTaskIntentResolver: NoteTaskIntentResolver
@Mock lateinit var bubbles: Bubbles @Mock lateinit var bubbles: Bubbles
@Mock lateinit var optionalBubbles: Optional<Bubbles> @Mock lateinit var optionalBubbles: Optional<Bubbles>
@@ -60,6 +66,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
whenever(context.packageManager).thenReturn(packageManager)
whenever(noteTaskIntentResolver.resolveIntent()).thenReturn(notesIntent) whenever(noteTaskIntentResolver.resolveIntent()).thenReturn(notesIntent)
whenever(optionalBubbles.orElse(null)).thenReturn(bubbles) whenever(optionalBubbles.orElse(null)).thenReturn(bubbles)
whenever(optionalKeyguardManager.orElse(null)).thenReturn(keyguardManager) whenever(optionalKeyguardManager.orElse(null)).thenReturn(keyguardManager)
@@ -78,89 +85,125 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
) )
} }
// region showNoteTask
@Test @Test
fun handleSystemKey_keyguardIsLocked_shouldStartActivity() { fun showNoteTask_keyguardIsLocked_shouldStartActivity() {
whenever(keyguardManager.isKeyguardLocked).thenReturn(true) whenever(keyguardManager.isKeyguardLocked).thenReturn(true)
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context).startActivity(notesIntent) verify(context).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
@Test @Test
fun handleSystemKey_keyguardIsUnlocked_shouldStartBubbles() { fun showNoteTask_keyguardIsUnlocked_shouldStartBubbles() {
whenever(keyguardManager.isKeyguardLocked).thenReturn(false) whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(bubbles).showAppBubble(notesIntent) verify(bubbles).showAppBubble(notesIntent)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
} }
@Test @Test
fun handleSystemKey_receiveInvalidSystemKey_shouldDoNothing() { fun showNoteTask_isInMultiWindowMode_shouldStartActivity() {
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_UNKNOWN) whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
verify(context, never()).startActivity(notesIntent) createNoteTaskController().showNoteTask(isInMultiWindowMode = true)
verify(context).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
@Test @Test
fun handleSystemKey_bubblesIsNull_shouldDoNothing() { fun showNoteTask_bubblesIsNull_shouldDoNothing() {
whenever(optionalBubbles.orElse(null)).thenReturn(null) whenever(optionalBubbles.orElse(null)).thenReturn(null)
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
@Test @Test
fun handleSystemKey_keyguardManagerIsNull_shouldDoNothing() { fun showNoteTask_keyguardManagerIsNull_shouldDoNothing() {
whenever(optionalKeyguardManager.orElse(null)).thenReturn(null) whenever(optionalKeyguardManager.orElse(null)).thenReturn(null)
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
@Test @Test
fun handleSystemKey_userManagerIsNull_shouldDoNothing() { fun showNoteTask_userManagerIsNull_shouldDoNothing() {
whenever(optionalUserManager.orElse(null)).thenReturn(null) whenever(optionalUserManager.orElse(null)).thenReturn(null)
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
@Test @Test
fun handleSystemKey_intentResolverReturnsNull_shouldDoNothing() { fun showNoteTask_intentResolverReturnsNull_shouldDoNothing() {
whenever(noteTaskIntentResolver.resolveIntent()).thenReturn(null) whenever(noteTaskIntentResolver.resolveIntent()).thenReturn(null)
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
@Test @Test
fun handleSystemKey_flagDisabled_shouldDoNothing() { fun showNoteTask_flagDisabled_shouldDoNothing() {
createNoteTaskController(isEnabled = false).handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController(isEnabled = false).showNoteTask()
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
@Test @Test
fun handleSystemKey_userIsLocked_shouldDoNothing() { fun showNoteTask_userIsLocked_shouldDoNothing() {
whenever(userManager.isUserUnlocked).thenReturn(false) whenever(userManager.isUserUnlocked).thenReturn(false)
createNoteTaskController().handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showAppBubble(notesIntent)
} }
// endregion
// region setNoteTaskShortcutEnabled
@Test
fun setNoteTaskShortcutEnabled_setTrue() {
createNoteTaskController().setNoteTaskShortcutEnabled(value = true)
val argument = argumentCaptor<ComponentName>()
verify(context.packageManager)
.setComponentEnabledSetting(
argument.capture(),
eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
eq(PackageManager.DONT_KILL_APP),
)
val expected = ComponentName(context, CreateNoteTaskShortcutActivity::class.java)
assertThat(argument.value.flattenToString()).isEqualTo(expected.flattenToString())
}
@Test
fun setNoteTaskShortcutEnabled_setFalse() {
createNoteTaskController().setNoteTaskShortcutEnabled(value = false)
val argument = argumentCaptor<ComponentName>()
verify(context.packageManager)
.setComponentEnabledSetting(
argument.capture(),
eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
eq(PackageManager.DONT_KILL_APP),
)
val expected = ComponentName(context, CreateNoteTaskShortcutActivity::class.java)
assertThat(argument.value.flattenToString()).isEqualTo(expected.flattenToString())
}
// endregion
} }

View File

@@ -16,10 +16,10 @@
package com.android.systemui.notetask package com.android.systemui.notetask
import android.test.suitebuilder.annotation.SmallTest import android.test.suitebuilder.annotation.SmallTest
import android.view.KeyEvent
import androidx.test.runner.AndroidJUnit4 import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever
import com.android.wm.shell.bubbles.Bubbles import com.android.wm.shell.bubbles.Bubbles
import java.util.Optional import java.util.Optional
@@ -45,6 +45,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
@Mock lateinit var commandQueue: CommandQueue @Mock lateinit var commandQueue: CommandQueue
@Mock lateinit var bubbles: Bubbles @Mock lateinit var bubbles: Bubbles
@Mock lateinit var optionalBubbles: Optional<Bubbles> @Mock lateinit var optionalBubbles: Optional<Bubbles>
@Mock lateinit var noteTaskController: NoteTaskController
@Before @Before
fun setUp() { fun setUp() {
@@ -57,12 +58,13 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
private fun createNoteTaskInitializer(isEnabled: Boolean = true): NoteTaskInitializer { private fun createNoteTaskInitializer(isEnabled: Boolean = true): NoteTaskInitializer {
return NoteTaskInitializer( return NoteTaskInitializer(
optionalBubbles = optionalBubbles, optionalBubbles = optionalBubbles,
lazyNoteTaskController = mock(), noteTaskController = noteTaskController,
commandQueue = commandQueue, commandQueue = commandQueue,
isEnabled = isEnabled, isEnabled = isEnabled,
) )
} }
// region initializer
@Test @Test
fun initialize_shouldAddCallbacks() { fun initialize_shouldAddCallbacks() {
createNoteTaskInitializer().initialize() createNoteTaskInitializer().initialize()
@@ -85,4 +87,35 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
verify(commandQueue, never()).addCallback(any()) verify(commandQueue, never()).addCallback(any())
} }
@Test
fun initialize_flagEnabled_shouldEnableShortcut() {
createNoteTaskInitializer().initialize()
verify(noteTaskController).setNoteTaskShortcutEnabled(true)
}
@Test
fun initialize_flagDisabled_shouldDisableShortcut() {
createNoteTaskInitializer(isEnabled = false).initialize()
verify(noteTaskController).setNoteTaskShortcutEnabled(false)
}
// endregion
// region handleSystemKey
@Test
fun handleSystemKey_receiveValidSystemKey_shouldShowNoteTask() {
createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent.KEYCODE_VIDEO_APP_1)
verify(noteTaskController).showNoteTask()
}
@Test
fun handleSystemKey_receiveInvalidSystemKey_shouldDoNothing() {
createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent.KEYCODE_UNKNOWN)
verify(noteTaskController, never()).showNoteTask()
}
// endregion
} }