Merge "Add Keyguard Shortcut for Note Task" into tm-qpr-dev

This commit is contained in:
Marcello Galhardo
2023-01-19 14:00:51 +00:00
committed by Android (Google) Code Review
11 changed files with 264 additions and 8 deletions

View File

@@ -921,7 +921,7 @@
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:theme="@android:style/Theme.NoDisplay" android:theme="@android:style/Theme.NoDisplay"
android:label="@string/note_task_button_label" android:label="@string/note_task_button_label"
android:icon="@drawable/ic_note_task_button"> android:icon="@drawable/ic_note_task_shortcut_widget">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" /> <action android:name="android.intent.action.CREATE_SHORTCUT" />

View File

@@ -0,0 +1,31 @@
<?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:fillAlpha="1"
android:fillColor="@android:color/white"
android:fillType="nonZero"
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:fillAlpha="1"
android:fillColor="@android:color/white"
android:fillType="nonZero"
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

@@ -19,10 +19,13 @@
android:viewportHeight="24" android:viewportHeight="24"
android:viewportWidth="24"> android:viewportWidth="24">
<path <path
android:fillAlpha="1"
android:fillColor="#636C6F" android:fillColor="#636C6F"
android:fillType="nonZero"
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" /> 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 <path
android:fillAlpha="1"
android:fillColor="#636C6F" android:fillColor="#636C6F"
android:fillType="evenOdd" android:fillType="nonZero"
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" /> 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> </vector>

View File

@@ -36,4 +36,15 @@
<integer name="qs_security_footer_maxLines">1</integer> <integer name="qs_security_footer_maxLines">1</integer>
<bool name="config_use_large_screen_shade_header">true</bool> <bool name="config_use_large_screen_shade_header">true</bool>
<!-- A collection of defaults for the quick affordances on the lock screen. Each item must be a
string with two parts: the ID of the slot and the comma-delimited list of affordance IDs,
separated by a colon ':' character. For example: <item>bottom_end:home,wallet</item>. The
default is displayed by System UI as long as the user hasn't made a different choice for that
slot. If the user did make a choice, even if the choice is the "None" option, the default is
ignored. -->
<string-array name="config_keyguardQuickAffordanceDefaults" translatable="false">
<item>bottom_start:home</item>
<item>bottom_end:create_note</item>
</string-array>
</resources> </resources>

View File

@@ -25,6 +25,7 @@ package com.android.systemui.keyguard.data.quickaffordance
object BuiltInKeyguardQuickAffordanceKeys { object BuiltInKeyguardQuickAffordanceKeys {
// Please keep alphabetical order of const names to simplify future maintenance. // Please keep alphabetical order of const names to simplify future maintenance.
const val CAMERA = "camera" const val CAMERA = "camera"
const val CREATE_NOTE = "create_note"
const val DO_NOT_DISTURB = "do_not_disturb" const val DO_NOT_DISTURB = "do_not_disturb"
const val FLASHLIGHT = "flashlight" const val FLASHLIGHT = "flashlight"
const val HOME_CONTROLS = "home" const val HOME_CONTROLS = "home"

View File

@@ -72,6 +72,9 @@ constructor(
companion object { companion object {
// TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead. // TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE" const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
// TODO(b/265912743): Use RoleManager.NOTES_ROLE instead.
const val NOTE_ROLE = "android.app.role.NOTES"
} }
} }

View File

@@ -18,11 +18,13 @@ package com.android.systemui.notetask
import android.app.Activity import android.app.Activity
import android.app.KeyguardManager import android.app.KeyguardManager
import android.app.role.RoleManager
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.quickaffordance.NoteTaskQuickAffordanceModule
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
import dagger.Binds import dagger.Binds
@@ -33,20 +35,25 @@ import dagger.multibindings.IntoMap
import java.util.Optional import java.util.Optional
/** Compose all dependencies required by Note Task feature. */ /** Compose all dependencies required by Note Task feature. */
@Module @Module(includes = [NoteTaskQuickAffordanceModule::class])
internal interface NoteTaskModule { internal interface NoteTaskModule {
@[Binds IntoMap ClassKey(LaunchNoteTaskActivity::class)] @[Binds IntoMap ClassKey(LaunchNoteTaskActivity::class)]
fun bindNoteTaskLauncherActivity(activity: LaunchNoteTaskActivity): Activity? fun LaunchNoteTaskActivity.bindNoteTaskLauncherActivity(): Activity
@[Binds IntoMap ClassKey(CreateNoteTaskShortcutActivity::class)] @[Binds IntoMap ClassKey(CreateNoteTaskShortcutActivity::class)]
fun bindNoteTaskShortcutActivity(activity: CreateNoteTaskShortcutActivity): Activity? fun CreateNoteTaskShortcutActivity.bindNoteTaskShortcutActivity(): Activity
companion object { companion object {
@[Provides NoteTaskEnabledKey] @[Provides NoteTaskEnabledKey]
fun provideIsNoteTaskEnabled(featureFlags: FeatureFlags): Boolean { fun provideIsNoteTaskEnabled(
return featureFlags.isEnabled(Flags.NOTE_TASKS) featureFlags: FeatureFlags,
roleManager: RoleManager,
): Boolean {
val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.NOTE_ROLE)
val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS)
return isRoleAvailable && isFeatureEnabled
} }
@Provides @Provides

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2023 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.quickaffordance
import android.content.Context
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEnabledKey
import javax.inject.Inject
import kotlinx.coroutines.flow.flowOf
internal class NoteTaskQuickAffordanceConfig
@Inject
constructor(
context: Context,
private val noteTaskController: NoteTaskController,
@NoteTaskEnabledKey private val isEnabled: Boolean,
) : KeyguardQuickAffordanceConfig {
override val key = BuiltInKeyguardQuickAffordanceKeys.CREATE_NOTE
override val pickerName: String = context.getString(R.string.note_task_button_label)
override val pickerIconResourceId = R.drawable.ic_note_task_shortcut_keyguard
override val lockScreenState = flowOf(getLockScreenState())
// TODO(b/265949213)
private fun getLockScreenState() =
if (isEnabled) {
val icon = Icon.Resource(pickerIconResourceId, ContentDescription.Loaded(pickerName))
LockScreenState.Visible(icon)
} else {
LockScreenState.Hidden
}
override suspend fun getPickerScreenState() =
if (isEnabled) {
PickerScreenState.Default()
} else {
PickerScreenState.UnavailableOnDevice
}
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
noteTaskController.showNoteTask()
return OnTriggeredResult.Handled
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 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.quickaffordance
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
@Module
internal interface NoteTaskQuickAffordanceModule {
@[Binds IntoSet]
fun NoteTaskQuickAffordanceConfig.bindNoteTaskQuickAffordance(): KeyguardQuickAffordanceConfig
}

View File

@@ -46,7 +46,7 @@ internal class CreateNoteTaskShortcutActivity @Inject constructor() : ComponentA
id = SHORTCUT_ID, id = SHORTCUT_ID,
shortLabel = getString(R.string.note_task_button_label), shortLabel = getString(R.string.note_task_button_label),
intent = LaunchNoteTaskActivity.newIntent(context = this), intent = LaunchNoteTaskActivity.newIntent(context = this),
iconResource = R.drawable.ic_note_task_button, iconResource = R.drawable.ic_note_task_shortcut_widget,
) )
setResult(Activity.RESULT_OK, intent) setResult(Activity.RESULT_OK, intent)

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2023 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.
*/
@file:OptIn(ExperimentalCoroutinesApi::class)
package com.android.systemui.notetask.quickaffordance
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
/**
* Tests for [NoteTaskQuickAffordanceConfig].
*
* Build/Install/Run:
* - atest SystemUITests:NoteTaskQuickAffordanceConfigTest
*/
@SmallTest
@RunWith(AndroidJUnit4::class)
internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
@Mock lateinit var noteTaskController: NoteTaskController
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(noteTaskController.showNoteTask()).then {}
}
private fun createUnderTest(isEnabled: Boolean) =
NoteTaskQuickAffordanceConfig(
context = context,
noteTaskController = noteTaskController,
isEnabled = isEnabled,
)
@Test
fun lockScreenState_isNotEnabled_shouldEmitHidden() = runTest {
val underTest = createUnderTest(isEnabled = false)
val actual = collectLastValue(underTest.lockScreenState)
assertThat(actual()).isEqualTo(LockScreenState.Hidden)
}
@Test
fun lockScreenState_isEnabled_shouldEmitVisible() = runTest {
val stringResult = "Notetaking"
val underTest = createUnderTest(isEnabled = true)
val actual = collectLastValue(underTest.lockScreenState)
val expected =
LockScreenState.Visible(
icon =
Icon.Resource(
res = R.drawable.ic_note_task_shortcut_keyguard,
contentDescription = ContentDescription.Loaded(stringResult),
)
)
assertThat(actual()).isEqualTo(expected)
}
@Test
fun onTriggered_shouldLaunchNoteTask() {
val underTest = createUnderTest(isEnabled = false)
underTest.onTriggered(expandable = null)
verify(noteTaskController).showNoteTask()
}
}