Merge "Support single conversation in People Space widget"
This commit is contained in:
@@ -14484,10 +14484,11 @@ public final class Settings {
|
||||
public static final String SHOW_PEOPLE_SPACE = "show_people_space";
|
||||
|
||||
/**
|
||||
* Which types of conversations to show in People Space.
|
||||
* Which types of conversation(s) to show in People Space.
|
||||
* Values are:
|
||||
* 0: All conversations (default)
|
||||
* 0: Single user-selected conversation (default)
|
||||
* 1: Priority conversations only
|
||||
* 2: All conversations
|
||||
* @hide
|
||||
*/
|
||||
public static final String PEOPLE_SPACE_CONVERSATION_TYPE =
|
||||
|
||||
@@ -576,6 +576,7 @@
|
||||
android:launchMode="singleInstance">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<!--
|
||||
~ Copyright (C) 2020 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.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="?android:attr/colorAccent" />
|
||||
<corners android:radius="@dimen/people_space_widget_radius" />
|
||||
</shape>
|
||||
@@ -17,8 +17,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/holo_blue_light">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/people_space_layout"
|
||||
@@ -30,16 +29,15 @@
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/people_space_cloud"
|
||||
android:layout_width="67dp"
|
||||
android:layout_height="67dp"
|
||||
<TextView
|
||||
android:id="@+id/select_conversation"
|
||||
android:text="@string/select_conversation_text"
|
||||
android:layout_width="match_parent"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:textSize="24sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:scaleType="fitCenter"
|
||||
android:focusable="false"
|
||||
android:paddingBottom="16dp"
|
||||
android:tint="?android:attr/colorControlNormal"
|
||||
android:src="@drawable/cloud" />
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
@@ -20,46 +20,53 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:background="@drawable/people_space_tile_view_card"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/people_space_activity_card"
|
||||
android:padding="12dp"
|
||||
android:elevation="4dp"
|
||||
android:gravity="start">
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/tile_view_package_icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="end" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/tile_view_person_icon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="start" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tile_view_name"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:paddingVertical="4dp"
|
||||
android:textSize="22sp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start" />
|
||||
android:gravity="start">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tile_view_status"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:paddingVertical="4dp"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:layout_gravity="start" />
|
||||
<ImageView
|
||||
android:id="@+id/tile_view_person_icon"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/tile_view_package_icon"
|
||||
android:layout_width="16dp"
|
||||
android:layout_marginStart="-8dp"
|
||||
android:layout_height="16dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tile_view_name"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:textSize="22sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tile_view_status"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:paddingVertical="4dp"
|
||||
android:textSize="12sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -22,6 +22,6 @@
|
||||
android:background="@drawable/people_space_widget_background"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:padding="5dp"
|
||||
android:padding="2dp"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"/>
|
||||
@@ -22,38 +22,57 @@
|
||||
android:background="@drawable/people_space_tile_view_card"
|
||||
android:id="@+id/item"
|
||||
android:orientation="vertical"
|
||||
android:padding="6dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:padding="4dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:elevation="4dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start">
|
||||
<ImageView
|
||||
android:id="@+id/package_icon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="end" />
|
||||
<ImageView
|
||||
android:id="@+id/person_icon"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="start" />
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:textSize="18sp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start" />
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:paddingVertical="2dp"
|
||||
android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/person_icon"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/package_icon"
|
||||
android:gravity="bottom|end"
|
||||
android:layout_width="14dp"
|
||||
android:layout_marginStart="-8dp"
|
||||
android:layout_height="14dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="4dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="16sp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:paddingVertical="2dp"
|
||||
android:textSize="12sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -2824,13 +2824,15 @@
|
||||
<string name="build_number_copy_toast">Build number copied to clipboard.</string>
|
||||
|
||||
<!-- Status for last interaction with exact time [CHAR LIMIT=120] -->
|
||||
<string name="last_interaction_status" translatable="false">You last chatted <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
|
||||
<string name="last_interaction_status" translatable="false">Last chatted <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
|
||||
<!-- Status for last interaction when less than a certain time window [CHAR LIMIT=120] -->
|
||||
<string name="last_interaction_status_less_than" translatable="false">You last chatted less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
|
||||
<string name="last_interaction_status_less_than" translatable="false">Last chatted less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
|
||||
<!-- Status for last interaction when over a certain time window [CHAR LIMIT=120] -->
|
||||
<string name="last_interaction_status_over" translatable="false">You last chatted over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
|
||||
<string name="last_interaction_status_over" translatable="false">Last chatted over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
|
||||
<!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
|
||||
<string name="basic_status" translatable="false">Open conversation</string>
|
||||
<!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
|
||||
<string name="select_conversation_text" translatable="false">Select one conversation to show in your widget:</string>
|
||||
|
||||
<!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false
|
||||
[CHAR LIMIT=NONE] -->
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
-->
|
||||
|
||||
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minWidth="72dp"
|
||||
android:minHeight="150dp"
|
||||
android:minWidth="180dp"
|
||||
android:minHeight="40dp"
|
||||
android:updatePeriodMillis="60000"
|
||||
android:previewImage="@drawable/cloud"
|
||||
android:previewImage="@drawable/ic_android"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:configure="com.android.systemui.people.PeopleSpaceActivity"
|
||||
android:initialLayout="@layout/people_space_widget">
|
||||
</appwidget-provider>
|
||||
|
||||
@@ -16,19 +16,30 @@
|
||||
|
||||
package com.android.systemui.people;
|
||||
|
||||
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
|
||||
import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.people.IPeopleManager;
|
||||
import android.app.people.PeopleSpaceTile;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.ServiceManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -46,6 +57,9 @@ public class PeopleSpaceActivity extends Activity {
|
||||
private PackageManager mPackageManager;
|
||||
private LauncherApps mLauncherApps;
|
||||
private Context mContext;
|
||||
private AppWidgetManager mAppWidgetManager;
|
||||
private int mAppWidgetId;
|
||||
private boolean mShowSingleConversation;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -59,7 +73,18 @@ public class PeopleSpaceActivity extends Activity {
|
||||
mPeopleManager = IPeopleManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.PEOPLE_SERVICE));
|
||||
mLauncherApps = mContext.getSystemService(LauncherApps.class);
|
||||
mAppWidgetManager = AppWidgetManager.getInstance(mContext);
|
||||
setTileViewsWithPriorityConversations();
|
||||
mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID,
|
||||
INVALID_APPWIDGET_ID);
|
||||
mShowSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
|
||||
// Finish the configuration activity immediately if a widget is added for multiple
|
||||
// conversations. If the mAppWidgetId is INVALID, then the activity wasn't launched as a
|
||||
// widget configuration activity.
|
||||
if (!mShowSingleConversation && mAppWidgetId != INVALID_APPWIDGET_ID) {
|
||||
finishActivity();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,12 +118,39 @@ public class PeopleSpaceActivity extends Activity {
|
||||
tileView.setName(tile.getUserName().toString());
|
||||
tileView.setPackageIcon(mPackageManager.getApplicationIcon(pkg));
|
||||
tileView.setPersonIcon(tile.getUserIcon());
|
||||
tileView.setOnClickListener(mLauncherApps, tile);
|
||||
tileView.setOnClickListener(v -> storeWidgetConfiguration(tile));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Couldn't retrieve shortcut information", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Stores the user selected configuration for {@code mAppWidgetId}. */
|
||||
private void storeWidgetConfiguration(PeopleSpaceTile tile) {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
if (PeopleSpaceUtils.DEBUG) {
|
||||
Log.d(TAG, "Put " + tile.getUserName() + "'s shortcut ID: "
|
||||
+ tile.getId() + " for widget ID: "
|
||||
+ mAppWidgetId);
|
||||
}
|
||||
editor.putString(String.valueOf(mAppWidgetId), tile.getId());
|
||||
editor.commit();
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
|
||||
int[] widgetIds = appWidgetManager.getAppWidgetIds(
|
||||
new ComponentName(mContext, PeopleSpaceWidgetProvider.class));
|
||||
PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, mAppWidgetManager,
|
||||
mNotificationManager);
|
||||
finishActivity();
|
||||
}
|
||||
|
||||
/** Finish activity with a successful widget configuration result. */
|
||||
private void finishActivity() {
|
||||
Intent resultValue = new Intent();
|
||||
resultValue.putExtra(EXTRA_APPWIDGET_ID, mAppWidgetId);
|
||||
setResult(RESULT_OK, resultValue);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
@@ -84,4 +84,9 @@ public class PeopleSpaceTileView extends LinearLayout {
|
||||
launcherApps.startShortcut(tile.getPackageName(), tile.getId(), null, null,
|
||||
UserHandle.getUserHandleForUid(tile.getUid())));
|
||||
}
|
||||
|
||||
/** Sets the click listener of the tile directly. */
|
||||
public void setOnClickListener(OnClickListener onClickListener) {
|
||||
mTileView.setOnClickListener(onClickListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,17 @@
|
||||
package com.android.systemui.people;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.people.ConversationChannel;
|
||||
import android.app.people.IPeopleManager;
|
||||
import android.app.people.PeopleSpaceTile;
|
||||
import android.appwidget.AppWidgetHost;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
@@ -29,17 +35,24 @@ import android.graphics.drawable.Drawable;
|
||||
import android.icu.text.MeasureFormat;
|
||||
import android.icu.util.Measure;
|
||||
import android.icu.util.MeasureUnit;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.ConversationChannelWrapper;
|
||||
import android.util.Log;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.people.widget.LaunchConversationActivity;
|
||||
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -57,14 +70,15 @@ public class PeopleSpaceUtils {
|
||||
Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
|
||||
LauncherApps launcherApps)
|
||||
throws Exception {
|
||||
boolean showAllConversations = Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
|
||||
boolean showOnlyPriority = Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1;
|
||||
List<ConversationChannelWrapper> conversations = notificationManager.getConversations(
|
||||
true).getList();
|
||||
List<Map.Entry<Long, PeopleSpaceTile>> tiles = getSortedTiles(peopleManager,
|
||||
conversations.stream().map(c ->
|
||||
new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build()));
|
||||
if (showAllConversations) {
|
||||
if (!showOnlyPriority) {
|
||||
if (DEBUG) Log.d(TAG, "Add recent conversations");
|
||||
List<ConversationChannel> recentConversations =
|
||||
peopleManager.getRecentConversations().getList();
|
||||
List<Map.Entry<Long, PeopleSpaceTile>> recentTiles =
|
||||
@@ -77,6 +91,73 @@ public class PeopleSpaceUtils {
|
||||
return tiles;
|
||||
}
|
||||
|
||||
/** Updates {@code appWidgetIds} with their associated conversation stored. */
|
||||
public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds,
|
||||
AppWidgetManager appWidgetManager, INotificationManager notificationManager) {
|
||||
PackageManager mPackageManager = context.getPackageManager();
|
||||
IPeopleManager mPeopleManager = IPeopleManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.PEOPLE_SERVICE));
|
||||
LauncherApps mLauncherApps = context.getSystemService(LauncherApps.class);
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
|
||||
activityIntent.addFlags(
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
| Intent.FLAG_ACTIVITY_NO_HISTORY
|
||||
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
try {
|
||||
List<Map.Entry<Long, PeopleSpaceTile>> shortcutInfos =
|
||||
PeopleSpaceUtils.getTiles(
|
||||
context, notificationManager,
|
||||
mPeopleManager, mLauncherApps);
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(),
|
||||
R.layout.people_space_widget_item);
|
||||
String shortcutId = sp.getString(String.valueOf(appWidgetId), null);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Set widget: " + appWidgetId + " with shortcut ID: " + shortcutId);
|
||||
}
|
||||
|
||||
Optional<Map.Entry<Long, PeopleSpaceTile>> entry = shortcutInfos.stream().filter(
|
||||
e -> e.getValue().getId().equals(shortcutId)).findFirst();
|
||||
if (!entry.isPresent() || shortcutId == null) {
|
||||
if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID");
|
||||
AppWidgetHost host = new AppWidgetHost(context, 0);
|
||||
host.deleteAppWidgetId(appWidgetId);
|
||||
continue;
|
||||
}
|
||||
PeopleSpaceTile tile = entry.get().getValue();
|
||||
|
||||
String status = PeopleSpaceUtils.getLastInteractionString(context,
|
||||
entry.get().getKey());
|
||||
views.setTextViewText(R.id.status, status);
|
||||
views.setTextViewText(R.id.name, tile.getUserName().toString());
|
||||
|
||||
activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
|
||||
activityIntent.putExtra(
|
||||
PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
|
||||
activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
|
||||
views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
|
||||
context,
|
||||
appWidgetId,
|
||||
activityIntent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE));
|
||||
|
||||
views.setImageViewBitmap(
|
||||
R.id.package_icon,
|
||||
PeopleSpaceUtils.convertDrawableToBitmap(
|
||||
mPackageManager.getApplicationIcon(tile.getPackageName())
|
||||
)
|
||||
);
|
||||
views.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
|
||||
// Tell the AppWidgetManager to perform an update on the current app widget.
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to retrieve conversations to set tiles");
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns a list sorted by ascending last interaction time from {@code stream}. */
|
||||
private static List<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
|
||||
IPeopleManager peopleManager, Stream<PeopleSpaceTile> stream) {
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
|
||||
package com.android.systemui.people.widget;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.NotificationChannel;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.Log;
|
||||
@@ -42,13 +45,18 @@ public class PeopleSpaceWidgetManager {
|
||||
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
|
||||
|
||||
private final Context mContext;
|
||||
private IAppWidgetService mAppWidgetManager;
|
||||
private IAppWidgetService mAppWidgetService;
|
||||
private AppWidgetManager mAppWidgetManager;
|
||||
private INotificationManager mNotificationManager;
|
||||
|
||||
@Inject
|
||||
public PeopleSpaceWidgetManager(Context context, IAppWidgetService appWidgetService) {
|
||||
if (DEBUG) Log.d(TAG, "constructor");
|
||||
mContext = context;
|
||||
mAppWidgetManager = appWidgetService;
|
||||
mAppWidgetService = appWidgetService;
|
||||
mAppWidgetManager = AppWidgetManager.getInstance(context);
|
||||
mNotificationManager = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
}
|
||||
|
||||
/** Constructor used for testing. */
|
||||
@@ -56,21 +64,24 @@ public class PeopleSpaceWidgetManager {
|
||||
protected PeopleSpaceWidgetManager(Context context) {
|
||||
if (DEBUG) Log.d(TAG, "constructor");
|
||||
mContext = context;
|
||||
mAppWidgetManager = IAppWidgetService.Stub.asInterface(
|
||||
mAppWidgetService = IAppWidgetService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.APPWIDGET_SERVICE));
|
||||
}
|
||||
|
||||
/** AppWidgetManager setter used for testing. */
|
||||
@VisibleForTesting
|
||||
protected void setAppWidgetManager(IAppWidgetService appWidgetService) {
|
||||
mAppWidgetManager = appWidgetService;
|
||||
protected void setAppWidgetManager(IAppWidgetService appWidgetService,
|
||||
AppWidgetManager appWidgetManager, INotificationManager notificationManager) {
|
||||
mAppWidgetService = appWidgetService;
|
||||
mAppWidgetManager = appWidgetManager;
|
||||
mNotificationManager = notificationManager;
|
||||
}
|
||||
|
||||
/** Updates People Space widgets. */
|
||||
public void updateWidgets() {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "updateWidgets called");
|
||||
int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
|
||||
int[] widgetIds = mAppWidgetService.getAppWidgetIds(
|
||||
new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
|
||||
);
|
||||
|
||||
@@ -80,9 +91,16 @@ public class PeopleSpaceWidgetManager {
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets");
|
||||
mAppWidgetManager
|
||||
.notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds,
|
||||
R.id.widget_list_view);
|
||||
boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
|
||||
if (showSingleConversation) {
|
||||
PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds,
|
||||
mAppWidgetManager, mNotificationManager);
|
||||
} else {
|
||||
mAppWidgetService
|
||||
.notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds,
|
||||
R.id.widget_list_view);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception: " + e);
|
||||
}
|
||||
@@ -125,7 +143,8 @@ public class PeopleSpaceWidgetManager {
|
||||
|
||||
@Override
|
||||
public void onNotificationRankingUpdate(
|
||||
NotificationListenerService.RankingMap rankingMap) { }
|
||||
NotificationListenerService.RankingMap rankingMap) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationsInitialized() {
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
|
||||
package com.android.systemui.people.widget;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.ServiceManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
@@ -41,6 +44,14 @@ public class PeopleSpaceWidgetProvider extends AppWidgetProvider {
|
||||
super.onUpdate(context, appWidgetManager, appWidgetIds);
|
||||
|
||||
if (DEBUG) Log.d(TAG, "onUpdate called");
|
||||
boolean showSingleConversation = Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
|
||||
if (showSingleConversation) {
|
||||
PeopleSpaceUtils.updateSingleConversationWidgets(context, appWidgetIds,
|
||||
appWidgetManager, INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE)));
|
||||
return;
|
||||
}
|
||||
// Perform this loop procedure for each App Widget that belongs to this provider
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
RemoteViews views =
|
||||
|
||||
@@ -29,12 +29,20 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.NotificationChannel;
|
||||
import android.content.Context;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.ConversationChannelWrapper;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.appwidget.IAppWidgetService;
|
||||
@@ -54,6 +62,9 @@ import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
@@ -65,14 +76,23 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
private static final String TEST_CHANNEL_NAME = "channel_name";
|
||||
private static final String TEST_PARENT_CHANNEL_ID = "parent_channel_id";
|
||||
private static final String TEST_CONVERSATION_ID = "conversation_id";
|
||||
private static final int WIDGET_ID_WITH_SHORTCUT = 1;
|
||||
private static final int WIDGET_ID_WITHOUT_SHORTCUT = 2;
|
||||
private static final String SHORTCUT_ID = "101";
|
||||
|
||||
private PeopleSpaceWidgetManager mManager;
|
||||
|
||||
@Mock private NotificationListener mListenerService;
|
||||
@Mock private IAppWidgetService mIAppWidgetService;
|
||||
@Mock private Context mContext;
|
||||
@Mock
|
||||
private NotificationListener mListenerService;
|
||||
@Mock
|
||||
private IAppWidgetService mIAppWidgetService;
|
||||
@Mock
|
||||
private AppWidgetManager mAppWidgetManager;
|
||||
@Mock
|
||||
private INotificationManager mINotificationManager;
|
||||
|
||||
@Captor private ArgumentCaptor<NotificationHandler> mListenerCaptor;
|
||||
@Captor
|
||||
private ArgumentCaptor<NotificationHandler> mListenerCaptor;
|
||||
|
||||
private final NoManSimulator mNoMan = new NoManSimulator();
|
||||
private final FakeSystemClock mClock = new FakeSystemClock();
|
||||
@@ -80,18 +100,18 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mManager =
|
||||
new PeopleSpaceWidgetManager(mContext);
|
||||
mManager.setAppWidgetManager(mIAppWidgetService);
|
||||
mManager.setAppWidgetManager(mIAppWidgetService, mAppWidgetManager, mINotificationManager);
|
||||
mManager.attach(mListenerService);
|
||||
|
||||
verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
|
||||
NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue());
|
||||
mNoMan.addListener(serviceListener);
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 2);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDoNotNotifyAppWidgetIfNoWidgets() throws RemoteException {
|
||||
int[] widgetIdsArray = {};
|
||||
@@ -105,7 +125,24 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
|
||||
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoNotNotifySingleConversationAppWidgetIfNoWidgets() throws RemoteException {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
|
||||
int[] widgetIdsArray = {};
|
||||
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(
|
||||
new NotificationEntryBuilder()
|
||||
.setId(0)
|
||||
.setPkg(TEST_PACKAGE_A));
|
||||
mClock.advanceTime(MIN_LINGER_DURATION);
|
||||
|
||||
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
|
||||
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), any(RemoteViews.class));
|
||||
verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,7 +159,66 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, times(1))
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
verify(mIAppWidgetService, never()).updateAppWidgetIds(any(), any(),
|
||||
any(RemoteViews.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifySingleConversationAppWidgetOnceIfNotificationPosted()
|
||||
throws RemoteException {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
|
||||
when(mINotificationManager.getConversations(true)).thenReturn(
|
||||
new ParceledListSlice(getConversationWithShortcutId()));
|
||||
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
|
||||
editor.commit();
|
||||
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_A)
|
||||
.setId(1));
|
||||
|
||||
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, never())
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
|
||||
any(RemoteViews.class));
|
||||
verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITHOUT_SHORTCUT),
|
||||
any(RemoteViews.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifySingleConversationAppWidgetTwiceIfTwoNotificationsPosted()
|
||||
throws RemoteException {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
|
||||
when(mINotificationManager.getConversations(true)).thenReturn(
|
||||
new ParceledListSlice(getConversationWithShortcutId()));
|
||||
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
|
||||
editor.commit();
|
||||
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
|
||||
|
||||
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_A)
|
||||
.setId(1));
|
||||
mClock.advanceTime(4);
|
||||
NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
|
||||
.setPkg(TEST_PACKAGE_B)
|
||||
.setId(2));
|
||||
|
||||
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, never())
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
|
||||
any(RemoteViews.class));
|
||||
verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITHOUT_SHORTCUT),
|
||||
any(RemoteViews.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -141,6 +237,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, times(2))
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
|
||||
any(RemoteViews.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -157,6 +255,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, times(2))
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
|
||||
any(RemoteViews.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -173,7 +273,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
|
||||
verify(mIAppWidgetService, never()).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
|
||||
|
||||
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
|
||||
any(RemoteViews.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,6 +293,17 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
|
||||
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
|
||||
verify(mIAppWidgetService, times(1))
|
||||
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
|
||||
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
|
||||
any(RemoteViews.class));
|
||||
}
|
||||
|
||||
/** Returns a list of a single conversation associated with {@code SHORTCUT_ID}. */
|
||||
private List<ConversationChannelWrapper> getConversationWithShortcutId() {
|
||||
List<ConversationChannelWrapper> convos = new ArrayList<>();
|
||||
ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
|
||||
convo1.setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID).setLongLabel(
|
||||
"name").build());
|
||||
convos.add(convo1);
|
||||
return convos;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user