Merge "Add recent tasks to Taskbar" into sc-dev
This commit is contained in:
commit
d10b587003
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<View
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="@dimen/taskbar_divider_thickness"
|
||||
android:layout_height="@dimen/taskbar_divider_height"
|
||||
android:layout_marginStart="@dimen/taskbar_icon_spacing"
|
||||
android:layout_marginEnd="@dimen/taskbar_icon_spacing"
|
||||
android:background="@color/taskbar_divider" />
|
|
@ -27,4 +27,5 @@
|
|||
|
||||
<!-- Taskbar -->
|
||||
<color name="taskbar_background">#101010</color>
|
||||
<color name="taskbar_divider">#C0C0C0</color>
|
||||
</resources>
|
|
@ -127,4 +127,6 @@
|
|||
<dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
|
||||
<!-- Note that this applies to both sides of all icons, so visible space is double this. -->
|
||||
<dimen name="taskbar_icon_spacing">14dp</dimen>
|
||||
<dimen name="taskbar_divider_thickness">1dp</dimen>
|
||||
<dimen name="taskbar_divider_height">24dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -23,6 +23,8 @@ import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTT
|
|||
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.ComponentName;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Point;
|
||||
import android.view.Gravity;
|
||||
|
@ -42,8 +44,13 @@ import com.android.launcher3.model.data.ItemInfo;
|
|||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.touch.ItemClickHandler;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interfaces with Launcher/WindowManager/SystemUI to determine what to show in TaskbarView.
|
||||
*/
|
||||
|
@ -60,11 +67,17 @@ public class TaskbarController {
|
|||
private final TaskbarStateHandler mTaskbarStateHandler;
|
||||
private final TaskbarVisibilityController mTaskbarVisibilityController;
|
||||
private final TaskbarHotseatController mHotseatController;
|
||||
private final TaskbarRecentsController mRecentsController;
|
||||
private final TaskbarDragController mDragController;
|
||||
|
||||
// Initialized in init().
|
||||
private WindowManager.LayoutParams mWindowLayoutParams;
|
||||
|
||||
// Contains all loaded Tasks, not yet deduped from Hotseat items.
|
||||
private List<Task> mLatestLoadedRecentTasks;
|
||||
// Contains all loaded Hotseat items.
|
||||
private ItemInfo[] mLatestLoadedHotseatItems;
|
||||
|
||||
public TaskbarController(BaseQuickstepLauncher launcher,
|
||||
TaskbarContainerView taskbarContainerView) {
|
||||
mLauncher = launcher;
|
||||
|
@ -79,6 +92,8 @@ public class TaskbarController {
|
|||
createTaskbarVisibilityControllerCallbacks());
|
||||
mHotseatController = new TaskbarHotseatController(mLauncher,
|
||||
createTaskbarHotseatControllerCallbacks());
|
||||
mRecentsController = new TaskbarRecentsController(mLauncher,
|
||||
createTaskbarRecentsControllerCallbacks());
|
||||
mDragController = new TaskbarDragController(mLauncher);
|
||||
}
|
||||
|
||||
|
@ -101,7 +116,16 @@ public class TaskbarController {
|
|||
return new TaskbarViewCallbacks() {
|
||||
@Override
|
||||
public View.OnClickListener getItemOnClickListener() {
|
||||
return ItemClickHandler.INSTANCE;
|
||||
return view -> {
|
||||
Object tag = view.getTag();
|
||||
if (tag instanceof Task) {
|
||||
Task task = (Task) tag;
|
||||
ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
|
||||
ActivityOptions.makeBasic());
|
||||
} else {
|
||||
ItemClickHandler.INSTANCE.onClick(view);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,6 +140,23 @@ public class TaskbarController {
|
|||
@Override
|
||||
public void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
|
||||
mTaskbarView.updateHotseatItems(hotseatItemInfos);
|
||||
mLatestLoadedHotseatItems = hotseatItemInfos;
|
||||
dedupeAndUpdateRecentItems();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private TaskbarRecentsControllerCallbacks createTaskbarRecentsControllerCallbacks() {
|
||||
return new TaskbarRecentsControllerCallbacks() {
|
||||
@Override
|
||||
public void updateRecentItems(ArrayList<Task> recentTasks) {
|
||||
mLatestLoadedRecentTasks = recentTasks;
|
||||
dedupeAndUpdateRecentItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecentTaskAtIndex(int taskIndex, Task task) {
|
||||
mTaskbarView.updateRecentTaskAtIndex(taskIndex, task);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -124,11 +165,13 @@ public class TaskbarController {
|
|||
* Initializes the Taskbar, including adding it to the screen.
|
||||
*/
|
||||
public void init() {
|
||||
mTaskbarView.init(mHotseatController.getNumHotseatIcons());
|
||||
mTaskbarView.init(mHotseatController.getNumHotseatIcons(),
|
||||
mRecentsController.getNumRecentIcons());
|
||||
addToWindowManager();
|
||||
mTaskbarStateHandler.setTaskbarCallbacks(createTaskbarStateHandlerCallbacks());
|
||||
mTaskbarVisibilityController.init();
|
||||
mHotseatController.init();
|
||||
mRecentsController.init();
|
||||
}
|
||||
|
||||
private TaskbarStateHandlerCallbacks createTaskbarStateHandlerCallbacks() {
|
||||
|
@ -149,6 +192,7 @@ public class TaskbarController {
|
|||
mTaskbarStateHandler.setTaskbarCallbacks(null);
|
||||
mTaskbarVisibilityController.cleanup();
|
||||
mHotseatController.cleanup();
|
||||
mRecentsController.cleanup();
|
||||
}
|
||||
|
||||
private void removeFromWindowManager() {
|
||||
|
@ -246,6 +290,52 @@ public class TaskbarController {
|
|||
return mTaskbarView.isDraggingItem();
|
||||
}
|
||||
|
||||
private void dedupeAndUpdateRecentItems() {
|
||||
if (mLatestLoadedRecentTasks == null || mLatestLoadedHotseatItems == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int numRecentIcons = mRecentsController.getNumRecentIcons();
|
||||
|
||||
// From most recent to least recently opened.
|
||||
List<Task> dedupedTasksInDescendingOrder = new ArrayList<>();
|
||||
for (int i = mLatestLoadedRecentTasks.size() - 1; i >= 0; i--) {
|
||||
Task task = mLatestLoadedRecentTasks.get(i);
|
||||
boolean isTaskInHotseat = false;
|
||||
for (ItemInfo hotseatItem : mLatestLoadedHotseatItems) {
|
||||
if (hotseatItem == null) {
|
||||
continue;
|
||||
}
|
||||
ComponentName hotseatActivity = hotseatItem.getTargetComponent();
|
||||
if (hotseatActivity != null && task.key.sourceComponent.getPackageName()
|
||||
.equals(hotseatActivity.getPackageName())) {
|
||||
isTaskInHotseat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isTaskInHotseat) {
|
||||
dedupedTasksInDescendingOrder.add(task);
|
||||
if (dedupedTasksInDescendingOrder.size() == numRecentIcons) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TaskbarView expects an array of all the recent tasks to show, in the order to show them.
|
||||
// So we create an array of the proper size, then fill it in such that the most recent items
|
||||
// are at the end. If there aren't enough elements to fill the array, leave them null.
|
||||
Task[] tasksArray = new Task[numRecentIcons];
|
||||
for (int i = 0; i < tasksArray.length; i++) {
|
||||
Task task = i >= dedupedTasksInDescendingOrder.size()
|
||||
? null
|
||||
: dedupedTasksInDescendingOrder.get(i);
|
||||
tasksArray[tasksArray.length - 1 - i] = task;
|
||||
}
|
||||
|
||||
mTaskbarView.updateRecentTasks(tasksArray);
|
||||
mRecentsController.loadIconsForTasks(tasksArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the given View is in the same window as Taskbar.
|
||||
*/
|
||||
|
@ -283,4 +373,12 @@ public class TaskbarController {
|
|||
protected interface TaskbarHotseatControllerCallbacks {
|
||||
void updateHotseatItems(ItemInfo[] hotseatItemInfos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains methods that TaskbarRecentsController can call to interface with TaskbarController.
|
||||
*/
|
||||
protected interface TaskbarRecentsControllerCallbacks {
|
||||
void updateRecentItems(ArrayList<Task> recentTasks);
|
||||
void updateRecentTaskAtIndex(int taskIndex, Task task);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.content.pm.LauncherApps;
|
|||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Point;
|
||||
import android.os.UserHandle;
|
||||
import android.view.DragEvent;
|
||||
import android.view.View;
|
||||
|
||||
|
@ -33,6 +34,7 @@ import com.android.launcher3.BubbleTextView;
|
|||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ClipDescriptionCompat;
|
||||
import com.android.systemui.shared.system.LauncherAppsCompat;
|
||||
|
||||
|
@ -102,6 +104,15 @@ public class TaskbarDragController {
|
|||
item.getIntent().getComponent(), null, item.user));
|
||||
}
|
||||
intent.putExtra(Intent.EXTRA_USER, item.user);
|
||||
} else if (tag instanceof Task) {
|
||||
Task task = (Task) tag;
|
||||
clipDescription = new ClipDescription(task.titleDescription,
|
||||
new String[] {
|
||||
ClipDescriptionCompat.MIMETYPE_APPLICATION_TASK
|
||||
});
|
||||
intent = new Intent();
|
||||
intent.putExtra(ClipDescriptionCompat.EXTRA_TASK_ID, task.key.id);
|
||||
intent.putExtra(Intent.EXTRA_USER, UserHandle.of(task.key.userId));
|
||||
}
|
||||
|
||||
if (clipDescription != null && intent != null) {
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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.launcher3.taskbar;
|
||||
|
||||
import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.util.CancellableTask;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListener;
|
||||
import com.android.systemui.shared.system.TaskStackChangeListeners;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Works with TaskbarController to update the TaskbarView's Recent items.
|
||||
*/
|
||||
public class TaskbarRecentsController {
|
||||
|
||||
private final int mNumRecentIcons = 2;
|
||||
private final BaseQuickstepLauncher mLauncher;
|
||||
private final TaskbarController.TaskbarRecentsControllerCallbacks mTaskbarCallbacks;
|
||||
private final RecentsModel mRecentsModel;
|
||||
|
||||
private final TaskStackChangeListener mTaskStackChangeListener = new TaskStackChangeListener() {
|
||||
@Override
|
||||
public void onTaskStackChanged() {
|
||||
reloadRecentTasksIfNeeded();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: add TaskbarVisualsChangedListener as well (for calendar/clock?)
|
||||
|
||||
// Used to keep track of the last requested task list id, so that we do not request to load the
|
||||
// tasks again if we have already requested it and the task list has not changed
|
||||
private int mTaskListChangeId = -1;
|
||||
|
||||
// The current background requests to load the task icons
|
||||
private CancellableTask[] mIconLoadRequests = new CancellableTask[mNumRecentIcons];
|
||||
|
||||
public TaskbarRecentsController(BaseQuickstepLauncher launcher,
|
||||
TaskbarController.TaskbarRecentsControllerCallbacks taskbarCallbacks) {
|
||||
mLauncher = launcher;
|
||||
mTaskbarCallbacks = taskbarCallbacks;
|
||||
mRecentsModel = RecentsModel.INSTANCE.get(mLauncher);
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackChangeListener);
|
||||
reloadRecentTasksIfNeeded();
|
||||
}
|
||||
|
||||
protected void cleanup() {
|
||||
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
|
||||
mTaskStackChangeListener);
|
||||
cancelAllPendingIconLoadTasks();
|
||||
}
|
||||
|
||||
private void reloadRecentTasksIfNeeded() {
|
||||
if (!mRecentsModel.isTaskListValid(mTaskListChangeId)) {
|
||||
mTaskListChangeId = mRecentsModel.getTasks(this::onRecentTasksChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelAllPendingIconLoadTasks() {
|
||||
for (int i = 0; i < mIconLoadRequests.length; i++) {
|
||||
if (mIconLoadRequests[i] != null) {
|
||||
mIconLoadRequests[i].cancel();
|
||||
}
|
||||
mIconLoadRequests[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void onRecentTasksChanged(ArrayList<Task> tasks) {
|
||||
mTaskbarCallbacks.updateRecentItems(tasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* For each Task, loads its icon from the cache in the background, then calls
|
||||
* {@link TaskbarController.TaskbarRecentsControllerCallbacks#updateRecentTaskAtIndex}.
|
||||
*/
|
||||
protected void loadIconsForTasks(Task[] tasks) {
|
||||
cancelAllPendingIconLoadTasks();
|
||||
for (int i = 0; i < tasks.length; i++) {
|
||||
Task task = tasks[i];
|
||||
if (task == null) {
|
||||
continue;
|
||||
}
|
||||
final int taskIndex = i;
|
||||
mIconLoadRequests[i] = mRecentsModel.getIconCache().updateIconInBackground(
|
||||
task, updatedTask -> onTaskIconLoaded(task, taskIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private void onTaskIconLoaded(Task task, int taskIndex) {
|
||||
mTaskbarCallbacks.updateRecentTaskAtIndex(taskIndex, task);
|
||||
}
|
||||
|
||||
protected int getNumRecentIcons() {
|
||||
return mNumRecentIcons;
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import android.content.Context;
|
|||
import android.content.res.Resources;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.DragEvent;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -35,6 +36,7 @@ import com.android.launcher3.BubbleTextView;
|
|||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
/**
|
||||
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
|
||||
|
@ -52,6 +54,9 @@ public class TaskbarView extends LinearLayout {
|
|||
// Initialized in init().
|
||||
private int mHotseatStartIndex;
|
||||
private int mHotseatEndIndex;
|
||||
private View mHotseatRecentsDivider;
|
||||
private int mRecentsStartIndex;
|
||||
private int mRecentsEndIndex;
|
||||
|
||||
private TaskbarController.TaskbarViewCallbacks mControllerCallbacks;
|
||||
|
||||
|
@ -89,10 +94,17 @@ public class TaskbarView extends LinearLayout {
|
|||
mControllerCallbacks = taskbarViewCallbacks;
|
||||
}
|
||||
|
||||
protected void init(int numHotseatIcons) {
|
||||
protected void init(int numHotseatIcons, int numRecentIcons) {
|
||||
mHotseatStartIndex = 0;
|
||||
mHotseatEndIndex = mHotseatStartIndex + numHotseatIcons - 1;
|
||||
updateHotseatItems(new ItemInfo[numHotseatIcons]);
|
||||
|
||||
int dividerIndex = mHotseatEndIndex + 1;
|
||||
mHotseatRecentsDivider = addDivider(dividerIndex);
|
||||
|
||||
mRecentsStartIndex = dividerIndex + 1;
|
||||
mRecentsEndIndex = mRecentsStartIndex + numRecentIcons - 1;
|
||||
updateRecentTasks(new Task[numRecentIcons]);
|
||||
}
|
||||
|
||||
protected void cleanup() {
|
||||
|
@ -147,6 +159,93 @@ public class TaskbarView extends LinearLayout {
|
|||
hotseatView.setOnLongClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
updateHotseatRecentsDividerVisibility();
|
||||
}
|
||||
|
||||
private View addDivider(int dividerIndex) {
|
||||
View divider = inflate(R.layout.taskbar_divider);
|
||||
addView(divider, dividerIndex);
|
||||
return divider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflates/binds the Recents items to show in the Taskbar given their Tasks.
|
||||
*/
|
||||
protected void updateRecentTasks(Task[] tasks) {
|
||||
for (int i = 0; i < tasks.length; i++) {
|
||||
Task task = tasks[i];
|
||||
int recentsIndex = mRecentsStartIndex + i;
|
||||
View recentsView = getChildAt(recentsIndex);
|
||||
|
||||
// Inflate empty icon Views.
|
||||
if (recentsView == null) {
|
||||
BubbleTextView btv = (BubbleTextView) inflate(R.layout.taskbar_app_icon);
|
||||
LayoutParams lp = new LayoutParams(btv.getIconSize(), btv.getIconSize());
|
||||
lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
|
||||
recentsView = btv;
|
||||
addView(recentsView, recentsIndex, lp);
|
||||
}
|
||||
|
||||
// Apply the Task, or hide the view if there is none for a given index.
|
||||
if (recentsView instanceof BubbleTextView && task != null) {
|
||||
applyTaskToBubbleTextView((BubbleTextView) recentsView, task);
|
||||
recentsView.setVisibility(VISIBLE);
|
||||
recentsView.setOnClickListener(mControllerCallbacks.getItemOnClickListener());
|
||||
recentsView.setOnLongClickListener(
|
||||
mControllerCallbacks.getItemOnLongClickListener());
|
||||
} else {
|
||||
recentsView.setVisibility(GONE);
|
||||
recentsView.setOnClickListener(null);
|
||||
recentsView.setOnLongClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
updateHotseatRecentsDividerVisibility();
|
||||
}
|
||||
|
||||
private void applyTaskToBubbleTextView(BubbleTextView btv, Task task) {
|
||||
if (task.icon != null) {
|
||||
Drawable icon = task.icon.getConstantState().newDrawable().mutate();
|
||||
btv.applyIconAndLabel(icon, task.titleDescription);
|
||||
}
|
||||
btv.setTag(task);
|
||||
}
|
||||
|
||||
protected void updateRecentTaskAtIndex(int taskIndex, Task task) {
|
||||
View taskView = getChildAt(mRecentsStartIndex + taskIndex);
|
||||
if (taskView instanceof BubbleTextView) {
|
||||
applyTaskToBubbleTextView((BubbleTextView) taskView, task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the divider VISIBLE between the Hotseat and Recents if there is at least one icon in
|
||||
* each, otherwise make it GONE.
|
||||
*/
|
||||
private void updateHotseatRecentsDividerVisibility() {
|
||||
if (mHotseatRecentsDivider == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasAtLeastOneHotseatItem = false;
|
||||
for (int i = mHotseatStartIndex; i <= mHotseatEndIndex; i++) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
hasAtLeastOneHotseatItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasAtLeastOneRecentItem = false;
|
||||
for (int i = mRecentsStartIndex; i <= mRecentsEndIndex; i++) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
hasAtLeastOneRecentItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mHotseatRecentsDivider.setVisibility(hasAtLeastOneHotseatItem && hasAtLeastOneRecentItem
|
||||
? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -358,6 +358,16 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly set the icon and label.
|
||||
*/
|
||||
@UiThread
|
||||
public void applyIconAndLabel(Drawable icon, CharSequence label) {
|
||||
setIcon(icon);
|
||||
setText(label);
|
||||
setContentDescription(label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default long press timeout.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue