diff options
10 files changed, 316 insertions, 0 deletions
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml index 7a986835359a..bcb1d292fce2 100644 --- a/libs/WindowManager/Shell/AndroidManifest.xml +++ b/libs/WindowManager/Shell/AndroidManifest.xml @@ -30,5 +30,29 @@ android:excludeFromRecents="true" android:launchMode="singleInstance" android:theme="@style/DesktopWallpaperTheme" /> + + <activity + android:name=".bubbles.shortcut.CreateBubbleShortcutActivity" + android:exported="true" + android:excludeFromRecents="true" + android:theme="@android:style/Theme.NoDisplay" + android:label="Bubbles" + android:icon="@drawable/ic_bubbles_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=".bubbles.shortcut.ShowBubblesActivity" + android:exported="true" + android:excludeFromRecents="true" + android:theme="@android:style/Theme.NoDisplay" > + <intent-filter> + <action android:name="com.android.wm.shell.bubbles.action.SHOW_BUBBLES"/> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> </application> </manifest> diff --git a/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget.xml b/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget.xml new file mode 100644 index 000000000000..b208f2fea7b2 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2024 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. + --> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/ic_bubbles_shortcut_widget_background" /> + <foreground android:drawable="@drawable/ic_bubbles_shortcut_widget_foreground" /> +</adaptive-icon> diff --git a/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget_background.xml b/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget_background.xml new file mode 100644 index 000000000000..510221fb2859 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget_background.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2024 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="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:pathData="M0,0h108v108h-108z" + android:fillColor="#FFC20C"/> +</vector> diff --git a/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget_foreground.xml b/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget_foreground.xml new file mode 100644 index 000000000000..a41b6a961bb2 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/ic_bubbles_shortcut_widget_foreground.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2024 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="108dp" + android:height="108dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="@android:color/white"> + <group android:scaleX="0.58" + android:scaleY="0.58" + android:translateX="5.04" + android:translateY="5.04"> + <path + android:fillColor="@android:color/white" + android:pathData="M7.2,14.4m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/> + <path + android:fillColor="@android:color/white" + android:pathData="M14.8,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/> + <path + android:fillColor="@android:color/white" + android:pathData="M15.2,8.8m-4.8,0a4.8,4.8 0,1 1,9.6 0a4.8,4.8 0,1 1,-9.6 0"/> + </group> +</vector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index bf654d979856..47846746b205 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -182,6 +182,12 @@ <!-- Content description to tell the user a bubble has been dismissed. --> <string name="accessibility_bubble_dismissed">Bubble dismissed.</string> + <!-- Label used to for bubbles shortcut [CHAR_LIMIT=10] --> + <string name="bubble_shortcut_label">Bubbles</string> + + <!-- Longer label used to for bubbles shortcut, shown if there is enough space [CHAR_LIMIT=25] --> + <string name="bubble_shortcut_long_label">Show Bubbles</string> + <!-- Description of the restart button in the hint of size compatibility mode. [CHAR LIMIT=NONE] --> <string name="restart_button_description">Tap to restart this app for a better view</string> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index d9055fbba408..a86164a8ed7d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -86,6 +86,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.util.CollectionUtils; import com.android.launcher3.icons.BubbleIconFactory; import com.android.wm.shell.Flags; import com.android.wm.shell.R; @@ -93,6 +94,7 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.bubbles.properties.BubbleProperties; +import com.android.wm.shell.bubbles.shortcut.BubbleShortcutHelper; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ExternalInterfaceBinder; import com.android.wm.shell.common.FloatingContentCoordinator; @@ -511,6 +513,10 @@ public class BubbleController implements ConfigurationChangeListener, } mCurrentProfiles = userProfiles; + if (Flags.enableRetrievableBubbles()) { + registerShortcutBroadcastReceiver(); + } + mShellController.addConfigurationChangeListener(this); mShellController.addExternalInterface(KEY_EXTRA_SHELL_BUBBLES, this::createExternalInterface, this); @@ -986,6 +992,25 @@ public class BubbleController implements ConfigurationChangeListener, } }; + private void registerShortcutBroadcastReceiver() { + IntentFilter shortcutFilter = new IntentFilter(); + shortcutFilter.addAction(BubbleShortcutHelper.ACTION_SHOW_BUBBLES); + ProtoLog.d(WM_SHELL_BUBBLES, "register broadcast receive for bubbles shortcut"); + mContext.registerReceiver(mShortcutBroadcastReceiver, shortcutFilter, + Context.RECEIVER_NOT_EXPORTED); + } + + private final BroadcastReceiver mShortcutBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + ProtoLog.v(WM_SHELL_BUBBLES, "receive broadcast to show bubbles %s", + intent.getAction()); + if (BubbleShortcutHelper.ACTION_SHOW_BUBBLES.equals(intent.getAction())) { + mMainExecutor.execute(() -> showBubblesFromShortcut()); + } + } + }; + /** * Called by the BubbleStackView and whenever all bubbles have animated out, and none have been * added in the meantime. @@ -2221,6 +2246,34 @@ public class BubbleController implements ConfigurationChangeListener, } /** + * Show bubbles UI when triggered via shortcut. + * + * <p>When there are bubbles visible, expands the top-most bubble. When there are no bubbles + * visible, opens the bubbles overflow UI. + */ + public void showBubblesFromShortcut() { + if (isStackExpanded()) { + ProtoLog.v(WM_SHELL_BUBBLES, "showBubblesFromShortcut: stack visible, skip"); + return; + } + if (mBubbleData.getSelectedBubble() != null) { + ProtoLog.v(WM_SHELL_BUBBLES, "showBubblesFromShortcut: open selected bubble"); + expandStackWithSelectedBubble(); + return; + } + BubbleViewProvider bubbleToSelect = CollectionUtils.firstOrNull(mBubbleData.getBubbles()); + if (bubbleToSelect == null) { + ProtoLog.v(WM_SHELL_BUBBLES, "showBubblesFromShortcut: no bubbles"); + // make sure overflow bubbles are loaded + loadOverflowBubblesFromDisk(); + bubbleToSelect = mBubbleData.getOverflow(); + } + ProtoLog.v(WM_SHELL_BUBBLES, "showBubblesFromShortcut: select and open %s", + bubbleToSelect.getKey()); + mBubbleData.setSelectedBubbleAndExpandStack(bubbleToSelect); + } + + /** * Description of current bubble state. */ private void dump(PrintWriter pw, String prefix) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 874102c20925..5f913f766164 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -912,6 +912,9 @@ public class BubbleData { ((Bubble) bubble).markAsAccessedAt(mTimeSource.currentTimeMillis()); } mSelectedBubble = bubble; + if (isOverflow) { + mShowingOverflow = true; + } mStateChange.selectedBubble = bubble; mStateChange.selectionChanged = true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/BubbleShortcutHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/BubbleShortcutHelper.kt new file mode 100644 index 000000000000..efa12383f188 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/BubbleShortcutHelper.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 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.wm.shell.bubbles.shortcut + +import android.content.Context +import android.content.pm.ShortcutInfo +import android.graphics.drawable.Icon +import com.android.wm.shell.R + +/** Helper class for creating a shortcut to open bubbles */ +object BubbleShortcutHelper { + const val SHORTCUT_ID = "bubbles_shortcut_id" + const val ACTION_SHOW_BUBBLES = "com.android.wm.shell.bubbles.action.SHOW_BUBBLES" + + /** Create a shortcut that launches [ShowBubblesActivity] */ + fun createShortcut(context: Context, icon: Icon): ShortcutInfo { + return ShortcutInfo.Builder(context, SHORTCUT_ID) + .setIntent(ShowBubblesActivity.createIntent(context)) + .setActivity(ShowBubblesActivity.createComponent(context)) + .setShortLabel(context.getString(R.string.bubble_shortcut_label)) + .setLongLabel(context.getString(R.string.bubble_shortcut_long_label)) + .setLongLived(true) + .setIcon(icon) + .build() + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/CreateBubbleShortcutActivity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/CreateBubbleShortcutActivity.kt new file mode 100644 index 000000000000..a124f95d7431 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/CreateBubbleShortcutActivity.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 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.wm.shell.bubbles.shortcut + +import android.app.Activity +import android.content.pm.ShortcutManager +import android.graphics.drawable.Icon +import android.os.Bundle +import com.android.wm.shell.Flags +import com.android.wm.shell.R +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES +import com.android.wm.shell.util.KtProtoLog + +/** Activity to create a shortcut to open bubbles */ +class CreateBubbleShortcutActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (Flags.enableRetrievableBubbles()) { + KtProtoLog.d(WM_SHELL_BUBBLES, "Creating a shortcut for bubbles") + createShortcut() + } + finish() + } + + private fun createShortcut() { + val icon = Icon.createWithResource(this, R.drawable.ic_bubbles_shortcut_widget) + // TODO(b/340337839): shortcut shows the sysui icon + val shortcutInfo = BubbleShortcutHelper.createShortcut(this, icon) + val shortcutManager = getSystemService(ShortcutManager::class.java) + val shortcutIntent = shortcutManager?.createShortcutResultIntent(shortcutInfo) + if (shortcutIntent != null) { + setResult(RESULT_OK, shortcutIntent) + } else { + setResult(RESULT_CANCELED) + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/ShowBubblesActivity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/ShowBubblesActivity.kt new file mode 100644 index 000000000000..ae7940ca1b65 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/shortcut/ShowBubblesActivity.kt @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 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.wm.shell.bubbles.shortcut + +import android.app.Activity +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.android.wm.shell.Flags +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES +import com.android.wm.shell.util.KtProtoLog + +/** Activity that sends a broadcast to open bubbles */ +class ShowBubblesActivity : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (Flags.enableRetrievableBubbles()) { + val intent = + Intent().apply { + action = BubbleShortcutHelper.ACTION_SHOW_BUBBLES + // Set the package as the receiver is not exported + `package` = packageName + } + KtProtoLog.v(WM_SHELL_BUBBLES, "Sending broadcast to show bubbles") + sendBroadcast(intent) + } + finish() + } + + companion object { + /** Create intent to launch this activity */ + fun createIntent(context: Context): Intent { + return Intent(context, ShowBubblesActivity::class.java).apply { + action = BubbleShortcutHelper.ACTION_SHOW_BUBBLES + } + } + + /** Create component for this activity */ + fun createComponent(context: Context): ComponentName { + return ComponentName(context, ShowBubblesActivity::class.java) + } + } +} |