Create interface and data to pass bubble updates to launcher

1) Create a common folder for bubbles in wm shell so that we can share
data between shell and launcher, the information shared will be:

- BubbleBarUpdate - a specific change in bubble state that launcher
  can use to update the bubble bar, the update will be created via
  the BubbleData.Update object
- BubbleInfo - an object representing the necessary information to
  render a bubble, BubbleInfo can be created via a Bubble object
- RemovedBubble - an object representing a removed bubble

2) Create a two aidl interfaces allowing launcher to register a
listener to get notified of BubbleBarUpdates and to notify WMShell
of UI interactions with the bubble bar so that shell can show or hide
the TaskView associated with the bubble.

3) Create the impl of the aidl interfaces in BubbleController

4) The listener is only registered if the flag is active

Bug: 253318833
Test: treehugger / manual with other CLs
Change-Id: I0955772db2502d99367e793d3e2cb229d31bd7b7
This commit is contained in:
Mady Mellor
2022-11-11 15:13:22 -08:00
parent bb5a64213a
commit 0c83394aae
11 changed files with 669 additions and 2 deletions

View File

@@ -46,6 +46,8 @@ filegroup {
"src/com/android/wm/shell/common/split/SplitScreenConstants.java",
"src/com/android/wm/shell/sysui/ShellSharedConstants.java",
"src/com/android/wm/shell/common/TransactionPool.java",
"src/com/android/wm/shell/common/bubbles/*.java",
"src/com/android/wm/shell/common/TriangleShape.java",
"src/com/android/wm/shell/animation/Interpolators.java",
"src/com/android/wm/shell/pip/PipContentOverlay.java",
"src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java",

View File

@@ -47,6 +47,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.wm.shell.common.bubbles.BubbleInfo;
import java.io.PrintWriter;
import java.util.List;
@@ -244,6 +245,16 @@ public class Bubble implements BubbleViewProvider {
setEntry(entry);
}
/** Converts this bubble into a {@link BubbleInfo} object to be shared with external callers. */
public BubbleInfo asBubbleBarBubble() {
return new BubbleInfo(getKey(),
getFlags(),
getShortcutInfo().getId(),
getIcon(),
getUser().getIdentifier(),
getPackageName());
}
@Override
public String getKey() {
return mKey;
@@ -545,8 +556,13 @@ public class Bubble implements BubbleViewProvider {
}
}
/**
* @return the icon set on BubbleMetadata, if it exists. This is only non-null for bubbles
* created via a PendingIntent. This is null for bubbles created by a shortcut, as we use the
* icon from the shortcut.
*/
@Nullable
Icon getIcon() {
public Icon getIcon() {
return mIcon;
}

View File

@@ -38,7 +38,9 @@ import static com.android.wm.shell.bubbles.Bubbles.DISMISS_NO_LONGER_BUBBLE;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_PACKAGE_REMOVED;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_SHORTCUT_REMOVED;
import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
import android.annotation.BinderThread;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -59,6 +61,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -88,13 +91,17 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
@@ -123,7 +130,8 @@ import java.util.function.IntConsumer;
*
* The controller manages addition, removal, and visible state of bubbles on screen.
*/
public class BubbleController implements ConfigurationChangeListener {
public class BubbleController implements ConfigurationChangeListener,
RemoteCallable<BubbleController> {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
@@ -248,6 +256,8 @@ public class BubbleController implements ConfigurationChangeListener {
private Optional<OneHandedController> mOneHandedOptional;
/** Drag and drop controller to register listener for onDragStarted. */
private DragAndDropController mDragAndDropController;
/** Used to send bubble events to launcher. */
private Bubbles.BubbleStateListener mBubbleStateListener;
public BubbleController(Context context,
ShellInit shellInit,
@@ -458,9 +468,15 @@ public class BubbleController implements ConfigurationChangeListener {
mCurrentProfiles = userProfiles;
mShellController.addConfigurationChangeListener(this);
mShellController.addExternalInterface(KEY_EXTRA_SHELL_BUBBLES,
this::createExternalInterface, this);
mShellCommandHandler.addDumpCallback(this::dump, this);
}
private ExternalInterfaceBinder createExternalInterface() {
return new BubbleController.IBubblesImpl(this);
}
@VisibleForTesting
public Bubbles asBubbles() {
return mImpl;
@@ -475,6 +491,48 @@ public class BubbleController implements ConfigurationChangeListener {
return mMainExecutor;
}
@Override
public Context getContext() {
return mContext;
}
@Override
public ShellExecutor getRemoteCallExecutor() {
return mMainExecutor;
}
/**
* Sets a listener to be notified of bubble updates. This is used by launcher so that
* it may render bubbles in itself. Only one listener is supported.
*/
public void registerBubbleStateListener(Bubbles.BubbleStateListener listener) {
if (isShowingAsBubbleBar()) {
// Only set the listener if bubble bar is showing.
mBubbleStateListener = listener;
sendInitialListenerUpdate();
} else {
mBubbleStateListener = null;
}
}
/**
* Unregisters the {@link Bubbles.BubbleStateListener}.
*/
public void unregisterBubbleStateListener() {
mBubbleStateListener = null;
}
/**
* If a {@link Bubbles.BubbleStateListener} is present, this will send the current bubble
* state to it.
*/
private void sendInitialListenerUpdate() {
if (mBubbleStateListener != null) {
BubbleBarUpdate update = mBubbleData.getInitialStateForBubbleBar();
mBubbleStateListener.onBubbleStateChange(update);
}
}
/**
* Hides the current input method, wherever it may be focused, via InputMethodManagerInternal.
*/
@@ -1722,6 +1780,73 @@ public class BubbleController implements ConfigurationChangeListener {
}
}
/**
* The interface for calls from outside the host process.
*/
@BinderThread
private class IBubblesImpl extends IBubbles.Stub implements ExternalInterfaceBinder {
private BubbleController mController;
private final SingleInstanceRemoteListener<BubbleController, IBubblesListener> mListener;
private final Bubbles.BubbleStateListener mBubbleListener =
new Bubbles.BubbleStateListener() {
@Override
public void onBubbleStateChange(BubbleBarUpdate update) {
Bundle b = new Bundle();
b.setClassLoader(BubbleBarUpdate.class.getClassLoader());
b.putParcelable(BubbleBarUpdate.BUNDLE_KEY, update);
mListener.call(l -> l.onBubbleStateChange(b));
}
};
IBubblesImpl(BubbleController controller) {
mController = controller;
mListener = new SingleInstanceRemoteListener<>(mController,
c -> c.registerBubbleStateListener(mBubbleListener),
c -> c.unregisterBubbleStateListener());
}
/**
* Invalidates this instance, preventing future calls from updating the controller.
*/
@Override
public void invalidate() {
mController = null;
}
@Override
public void registerBubbleListener(IBubblesListener listener) {
mMainExecutor.execute(() -> {
mListener.register(listener);
});
}
@Override
public void unregisterBubbleListener(IBubblesListener listener) {
mMainExecutor.execute(() -> mListener.unregister());
}
@Override
public void showBubble(String key, boolean onLauncherHome) {
// TODO
}
@Override
public void removeBubble(String key, int reason) {
// TODO
}
@Override
public void collapseBubbles() {
// TODO
}
@Override
public void onTaskbarStateChanged(int newState) {
// TODO (b/269670598)
}
}
private class BubblesImpl implements Bubbles {
// Up-to-date cached state of bubbles data for SysUI to query from the calling thread
@VisibleForTesting
@@ -1835,6 +1960,17 @@ public class BubbleController implements ConfigurationChangeListener {
private CachedState mCachedState = new CachedState();
private IBubblesImpl mIBubbles;
@Override
public IBubbles createExternalInterface() {
if (mIBubbles != null) {
mIBubbles.invalidate();
}
mIBubbles = new IBubblesImpl(BubbleController.this);
return mIBubbles;
}
@Override
public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
return mCachedState.isBubbleNotificationSuppressedFromShade(key, groupKey);

View File

@@ -40,6 +40,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubbles.DismissReason;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
import com.android.wm.shell.common.bubbles.RemovedBubble;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -113,6 +115,61 @@ public class BubbleData {
void bubbleRemoved(Bubble bubbleToRemove, @DismissReason int reason) {
removedBubbles.add(new Pair<>(bubbleToRemove, reason));
}
/**
* Converts the update to a {@link BubbleBarUpdate} which contains updates relevant
* to the bubble bar. Only used when {@link BubbleController#isShowingAsBubbleBar()} is
* true.
*/
BubbleBarUpdate toBubbleBarUpdate() {
BubbleBarUpdate bubbleBarUpdate = new BubbleBarUpdate();
bubbleBarUpdate.expandedChanged = expandedChanged;
bubbleBarUpdate.expanded = expanded;
if (selectionChanged) {
bubbleBarUpdate.selectedBubbleKey = selectedBubble != null
? selectedBubble.getKey()
: null;
}
bubbleBarUpdate.addedBubble = addedBubble != null
? addedBubble.asBubbleBarBubble()
: null;
// TODO(b/269670235): We need to handle updates better, I think for the bubble bar only
// certain updates need to be sent instead of any updatedBubble.
bubbleBarUpdate.updatedBubble = updatedBubble != null
? updatedBubble.asBubbleBarBubble()
: null;
bubbleBarUpdate.suppressedBubbleKey = suppressedBubble != null
? suppressedBubble.getKey()
: null;
bubbleBarUpdate.unsupressedBubbleKey = unsuppressedBubble != null
? unsuppressedBubble.getKey()
: null;
for (int i = 0; i < removedBubbles.size(); i++) {
Pair<Bubble, Integer> pair = removedBubbles.get(i);
bubbleBarUpdate.removedBubbles.add(
new RemovedBubble(pair.first.getKey(), pair.second));
}
if (orderChanged) {
// Include the new order
for (int i = 0; i < bubbles.size(); i++) {
bubbleBarUpdate.bubbleKeysInOrder.add(bubbles.get(i).getKey());
}
}
return bubbleBarUpdate;
}
/**
* Gets the current state of active bubbles and populates the update with that. Only
* used when {@link BubbleController#isShowingAsBubbleBar()} is true.
*/
BubbleBarUpdate getInitialState() {
BubbleBarUpdate bubbleBarUpdate = new BubbleBarUpdate();
for (int i = 0; i < bubbles.size(); i++) {
bubbleBarUpdate.currentBubbleList.add(bubbles.get(i).asBubbleBarBubble());
}
return bubbleBarUpdate;
}
}
/**
@@ -190,6 +247,13 @@ public class BubbleData {
mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow);
}
/**
* Returns a bubble bar update populated with the current list of active bubbles.
*/
public BubbleBarUpdate getInitialStateForBubbleBar() {
return mStateChange.getInitialState();
}
public void setSuppressionChangedListener(Bubbles.BubbleMetadataFlagListener listener) {
mBubbleMetadataFlagListener = listener;
}

View File

@@ -39,6 +39,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -81,6 +82,11 @@ public interface Bubbles {
int DISMISS_RELOAD_FROM_DISK = 15;
int DISMISS_USER_REMOVED = 16;
/** Returns a binder that can be passed to an external process to manipulate Bubbles. */
default IBubbles createExternalInterface() {
return null;
}
/**
* @return {@code true} if there is a bubble associated with the provided key and if its
* notification is hidden from the shade or there is a group summary associated with the
@@ -277,6 +283,17 @@ public interface Bubbles {
*/
void onUserRemoved(int removedUserId);
/**
* A listener to be notified of bubble state changes, used by launcher to render bubbles in
* its process.
*/
interface BubbleStateListener {
/**
* Called when the bubbles state changes.
*/
void onBubbleStateChange(BubbleBarUpdate update);
}
/** Listener to find out about stack expansion / collapse events. */
interface BubbleExpandListener {
/**

View File

@@ -0,0 +1,40 @@
/*
* 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.wm.shell.bubbles;
import android.content.Intent;
import com.android.wm.shell.bubbles.IBubblesListener;
/**
* Interface that is exposed to remote callers (launcher) to manipulate the bubbles feature when
* showing in the bubble bar.
*/
interface IBubbles {
oneway void registerBubbleListener(in IBubblesListener listener) = 1;
oneway void unregisterBubbleListener(in IBubblesListener listener) = 2;
oneway void showBubble(in String key, in boolean onLauncherHome) = 3;
oneway void removeBubble(in String key, in int reason) = 4;
oneway void collapseBubbles() = 5;
oneway void onTaskbarStateChanged(in int newState) = 6;
}

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.wm.shell.bubbles;
import android.os.Bundle;
/**
* Listener interface that Launcher attaches to SystemUI to get bubbles callbacks.
*/
oneway interface IBubblesListener {
/**
* Called when the bubbles state changes.
*/
void onBubbleStateChange(in Bundle update);
}

View File

@@ -0,0 +1,137 @@
/*
* 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.wm.shell.common.bubbles;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
/**
* Represents an update to bubbles state. This is passed through
* {@link com.android.wm.shell.bubbles.IBubblesListener} to launcher so that taskbar may render
* bubbles. This should be kept this as minimal as possible in terms of data.
*/
public class BubbleBarUpdate implements Parcelable {
public static final String BUNDLE_KEY = "update";
public boolean expandedChanged;
public boolean expanded;
@Nullable
public String selectedBubbleKey;
@Nullable
public BubbleInfo addedBubble;
@Nullable
public BubbleInfo updatedBubble;
@Nullable
public String suppressedBubbleKey;
@Nullable
public String unsupressedBubbleKey;
// This is only populated if bubbles have been removed.
public List<RemovedBubble> removedBubbles = new ArrayList<>();
// This is only populated if the order of the bubbles has changed.
public List<String> bubbleKeysInOrder = new ArrayList<>();
// This is only populated the first time a listener is connected so it gets the current state.
public List<BubbleInfo> currentBubbleList = new ArrayList<>();
public BubbleBarUpdate() {
}
public BubbleBarUpdate(Parcel parcel) {
expandedChanged = parcel.readBoolean();
expanded = parcel.readBoolean();
selectedBubbleKey = parcel.readString();
addedBubble = parcel.readParcelable(BubbleInfo.class.getClassLoader(),
BubbleInfo.class);
updatedBubble = parcel.readParcelable(BubbleInfo.class.getClassLoader(),
BubbleInfo.class);
suppressedBubbleKey = parcel.readString();
unsupressedBubbleKey = parcel.readString();
removedBubbles = parcel.readParcelableList(new ArrayList<>(),
RemovedBubble.class.getClassLoader());
parcel.readStringList(bubbleKeysInOrder);
currentBubbleList = parcel.readParcelableList(new ArrayList<>(),
BubbleInfo.class.getClassLoader());
}
/**
* Returns whether anything has changed in this update.
*/
public boolean anythingChanged() {
return expandedChanged
|| selectedBubbleKey != null
|| addedBubble != null
|| updatedBubble != null
|| !removedBubbles.isEmpty()
|| !bubbleKeysInOrder.isEmpty()
|| suppressedBubbleKey != null
|| unsupressedBubbleKey != null
|| !currentBubbleList.isEmpty();
}
@Override
public String toString() {
return "BubbleBarUpdate{ expandedChanged=" + expandedChanged
+ " expanded=" + expanded
+ " selectedBubbleKey=" + selectedBubbleKey
+ " addedBubble=" + addedBubble
+ " updatedBubble=" + updatedBubble
+ " suppressedBubbleKey=" + suppressedBubbleKey
+ " unsuppressedBubbleKey=" + unsupressedBubbleKey
+ " removedBubbles=" + removedBubbles
+ " bubbles=" + bubbleKeysInOrder
+ " currentBubbleList=" + currentBubbleList
+ " }";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeBoolean(expandedChanged);
parcel.writeBoolean(expanded);
parcel.writeString(selectedBubbleKey);
parcel.writeParcelable(addedBubble, flags);
parcel.writeParcelable(updatedBubble, flags);
parcel.writeString(suppressedBubbleKey);
parcel.writeString(unsupressedBubbleKey);
parcel.writeParcelableList(removedBubbles, flags);
parcel.writeStringList(bubbleKeysInOrder);
parcel.writeParcelableList(currentBubbleList, flags);
}
@NonNull
public static final Creator<BubbleBarUpdate> CREATOR =
new Creator<BubbleBarUpdate>() {
public BubbleBarUpdate createFromParcel(Parcel source) {
return new BubbleBarUpdate(source);
}
public BubbleBarUpdate[] newArray(int size) {
return new BubbleBarUpdate[size];
}
};
}

View File

@@ -0,0 +1,154 @@
/*
* 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.wm.shell.common.bubbles;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* Contains information necessary to present a bubble.
*/
public class BubbleInfo implements Parcelable {
// TODO(b/269672147): needs a title string for a11y & that comes from notification
// TODO(b/269671451): needs whether the bubble is an 'important person' or not
private String mKey; // Same key as the Notification
private int mFlags; // Flags from BubbleMetadata
private String mShortcutId;
private int mUserId;
private String mPackageName;
/**
* All notification bubbles require a shortcut to be set on the notification, however, the
* app could still specify an Icon and PendingIntent to use for the bubble. In that case
* this icon will be populated. If the bubble is entirely shortcut based, this will be null.
*/
@Nullable
private Icon mIcon;
public BubbleInfo(String key, int flags, String shortcutId, @Nullable Icon icon,
int userId, String packageName) {
mKey = key;
mFlags = flags;
mShortcutId = shortcutId;
mIcon = icon;
mUserId = userId;
mPackageName = packageName;
}
public BubbleInfo(Parcel source) {
mKey = source.readString();
mFlags = source.readInt();
mShortcutId = source.readString();
mIcon = source.readTypedObject(Icon.CREATOR);
mUserId = source.readInt();
mPackageName = source.readString();
}
public String getKey() {
return mKey;
}
public String getShortcutId() {
return mShortcutId;
}
public Icon getIcon() {
return mIcon;
}
public int getFlags() {
return mFlags;
}
public int getUserId() {
return mUserId;
}
public String getPackageName() {
return mPackageName;
}
/**
* Whether this bubble is currently being hidden from the stack.
*/
public boolean isBubbleSuppressed() {
return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE) != 0;
}
/**
* Whether this bubble is able to be suppressed (i.e. has the developer opted into the API
* to
* hide the bubble when in the same content).
*/
public boolean isBubbleSuppressable() {
return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE) != 0;
}
/**
* Whether the notification for this bubble is hidden from the shade.
*/
public boolean isNotificationSuppressed() {
return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION) != 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BubbleInfo)) return false;
BubbleInfo bubble = (BubbleInfo) o;
return Objects.equals(mKey, bubble.mKey);
}
@Override
public int hashCode() {
return mKey.hashCode();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mKey);
parcel.writeInt(mFlags);
parcel.writeString(mShortcutId);
parcel.writeTypedObject(mIcon, flags);
parcel.writeInt(mUserId);
parcel.writeString(mPackageName);
}
@NonNull
public static final Creator<BubbleInfo> CREATOR =
new Creator<BubbleInfo>() {
public BubbleInfo createFromParcel(Parcel source) {
return new BubbleInfo(source);
}
public BubbleInfo[] newArray(int size) {
return new BubbleInfo[size];
}
};
}

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.wm.shell.common.bubbles;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Represents a removed bubble, defining the key and reason the bubble was removed.
*/
public class RemovedBubble implements Parcelable {
private final String mKey;
private final int mRemovalReason;
public RemovedBubble(String key, int removalReason) {
mKey = key;
mRemovalReason = removalReason;
}
public RemovedBubble(Parcel parcel) {
mKey = parcel.readString();
mRemovalReason = parcel.readInt();
}
public String getKey() {
return mKey;
}
public int getRemovalReason() {
return mRemovalReason;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mKey);
dest.writeInt(mRemovalReason);
}
@NonNull
public static final Creator<RemovedBubble> CREATOR =
new Creator<RemovedBubble>() {
public RemovedBubble createFromParcel(Parcel source) {
return new RemovedBubble(source);
}
public RemovedBubble[] newArray(int size) {
return new RemovedBubble[size];
}
};
}

View File

@@ -22,6 +22,8 @@ package com.android.wm.shell.sysui;
public class ShellSharedConstants {
// See IPip.aidl
public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
// See IBubbles.aidl
public static final String KEY_EXTRA_SHELL_BUBBLES = "extra_shell_bubbles";
// See ISplitScreen.aidl
public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
// See IOneHanded.aidl