Add Note Task Shortcut to Settings
Test: manual
Fixes: b/272757160
Change-Id: I9ce69aa674a774e9150d16718b9558bea7a5560e
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ccf002a..cb57321 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4825,6 +4825,22 @@
</receiver>
<activity
+ android:name=".notetask.shortcut.CreateNoteTaskShortcutActivity"
+ android:enabled="false"
+ android:exported="true"
+ android:excludeFromRecents="true"
+ android:resizeableActivity="false"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:label="@string/note_task_button_label"
+ android:icon="@drawable/ic_note_task_shortcut_widget">
+
+ <intent-filter>
+ <action android:name="android.intent.action.CREATE_SHORTCUT" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="com.android.settings.bluetooth.QrCodeScanModeActivity"
android:permission="android.permission.BLUETOOTH_CONNECT"
android:exported="true">
diff --git a/res/drawable/ic_note_task_shortcut_widget.xml b/res/drawable/ic_note_task_shortcut_widget.xml
new file mode 100644
index 0000000..e37c22a
--- /dev/null
+++ b/res/drawable/ic_note_task_shortcut_widget.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ -->
+<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="#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" />
+ <path
+ android:fillAlpha="1"
+ android:fillColor="#636C6F"
+ 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>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f23fb5f..0524879 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -12019,4 +12019,7 @@
<!-- Warning message when we try to dock an app not supporting multiple instances split into multiple sides [CHAR LIMIT=NONE] -->
<string name="dock_multi_instances_not_supported_text">"This app can only be opened in 1 window"</string>
+
+ <!-- [CHAR LIMIT=30] Label used to open Note Task -->
+ <string name="note_task_button_label">Notetaking</string>
</resources>
diff --git a/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
new file mode 100644
index 0000000..b984622
--- /dev/null
+++ b/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
@@ -0,0 +1,113 @@
+/*
+ * 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.settings.notetask.shortcut
+
+import android.app.Activity
+import android.app.role.RoleManager
+import android.app.role.RoleManager.ROLE_NOTES
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ShortcutInfo
+import android.content.pm.ShortcutManager
+import android.graphics.drawable.Icon
+import android.os.Bundle
+import android.os.PersistableBundle
+import android.os.UserHandle
+import androidx.activity.ComponentActivity
+import androidx.core.content.getSystemService
+import com.android.settings.R
+
+/**
+ * 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 : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ val roleManager = requireNotNull(getSystemService<RoleManager>())
+ val shortcutManager = requireNotNull(getSystemService<ShortcutManager>())
+
+ super.onCreate(savedInstanceState)
+
+ val shortcutInfo = roleManager.createNoteShortcutInfoAsUser(context = this, user)
+ val shortcutIntent = shortcutManager.createShortcutResultIntent(shortcutInfo)
+ setResult(Activity.RESULT_OK, shortcutIntent)
+
+ finish()
+ }
+
+ private companion object {
+
+ private const val SHORTCUT_ID = "note_task_shortcut_id"
+ private const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE =
+ "extra_shortcut_badge_override_package"
+ private const val ACTION_LAUNCH_NOTE_TASK = "com.android.systemui.action.LAUNCH_NOTE_TASK"
+
+ private fun RoleManager.createNoteShortcutInfoAsUser(
+ context: Context,
+ user: UserHandle,
+ ): ShortcutInfo? {
+ val systemUiComponent = context.getSystemUiComponent() ?: return null
+
+ val extras = PersistableBundle()
+ getDefaultRoleHolderAsUser(ROLE_NOTES, user)?.let { packageName ->
+ // Set custom app badge using the icon from ROLES_NOTES default app.
+ extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, packageName)
+ }
+
+ val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
+
+ val intent = Intent(ACTION_LAUNCH_NOTE_TASK).apply {
+ setPackage(systemUiComponent.packageName)
+ }
+
+ return ShortcutInfo.Builder(context, SHORTCUT_ID)
+ .setIntent(intent)
+ .setShortLabel(context.getString(R.string.note_task_button_label))
+ .setLongLived(true)
+ .setIcon(icon)
+ .setExtras(extras)
+ .build()
+ }
+
+ private fun RoleManager.getDefaultRoleHolderAsUser(
+ role: String,
+ user: UserHandle,
+ ): String? = getRoleHoldersAsUser(role, user).firstOrNull()
+
+ private fun Context.getSystemUiComponent(): ComponentName? {
+ val flattenName = getString(
+ com.android.internal.R.string.config_systemUIServiceComponent)
+ check(flattenName.isNotEmpty()) {
+ "No 'com.android.internal.R.string.config_systemUIServiceComponent' resource"
+ }
+ return try {
+ ComponentName.unflattenFromString(flattenName)
+ } catch (e: RuntimeException) {
+ val message = "Invalid component name defined by 'com.android.internal.R.string." +
+ "config_systemUIServiceComponent' resource: $flattenName"
+ throw IllegalStateException(message, e)
+ }
+ }
+ }
+}