Merge "Statsd UiEvent logging for notification history." into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
5c1b9c357d
@@ -26,7 +26,6 @@ import android.app.ActivityManager;
|
|||||||
import android.app.INotificationManager;
|
import android.app.INotificationManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Outline;
|
import android.graphics.Outline;
|
||||||
@@ -49,10 +48,12 @@ import android.widget.ImageButton;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.internal.logging.UiEvent;
|
||||||
|
import com.android.internal.logging.UiEventLogger;
|
||||||
|
import com.android.internal.logging.UiEventLoggerImpl;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.notification.NotificationBackend;
|
import com.android.settings.notification.NotificationBackend;
|
||||||
import com.android.settings.widget.SwitchBar;
|
import com.android.settings.widget.SwitchBar;
|
||||||
@@ -82,6 +83,48 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
private PackageManager mPm;
|
private PackageManager mPm;
|
||||||
private CountDownLatch mCountdownLatch;
|
private CountDownLatch mCountdownLatch;
|
||||||
private Future mCountdownFuture;
|
private Future mCountdownFuture;
|
||||||
|
private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
|
||||||
|
|
||||||
|
enum NotificationHistoryEvent implements UiEventLogger.UiEventEnum {
|
||||||
|
@UiEvent(doc = "User turned on notification history")
|
||||||
|
NOTIFICATION_HISTORY_ON(504),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User turned off notification history")
|
||||||
|
NOTIFICATION_HISTORY_OFF(505),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User opened notification history page")
|
||||||
|
NOTIFICATION_HISTORY_OPEN(506),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User closed notification history page")
|
||||||
|
NOTIFICATION_HISTORY_CLOSE(507),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User clicked on a notification history item in recently dismissed section")
|
||||||
|
NOTIFICATION_HISTORY_RECENT_ITEM_CLICK(508),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User clicked on a notification history item in snoozed section")
|
||||||
|
NOTIFICATION_HISTORY_SNOOZED_ITEM_CLICK(509),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User clicked to expand the notification history of a package (app)")
|
||||||
|
NOTIFICATION_HISTORY_PACKAGE_HISTORY_OPEN(510),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User clicked to close the notification history of a package (app)")
|
||||||
|
NOTIFICATION_HISTORY_PACKAGE_HISTORY_CLOSE(511),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User clicked on a notification history item in an expanded by-app section")
|
||||||
|
NOTIFICATION_HISTORY_OLDER_ITEM_CLICK(512),
|
||||||
|
|
||||||
|
@UiEvent(doc = "User dismissed a notification history item in an expanded by-app section")
|
||||||
|
NOTIFICATION_HISTORY_OLDER_ITEM_DELETE(513);
|
||||||
|
|
||||||
|
private int mId;
|
||||||
|
NotificationHistoryEvent(int id) {
|
||||||
|
mId = id;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private HistoryLoader.OnHistoryLoaderListener mOnHistoryLoaderListener = notifications -> {
|
private HistoryLoader.OnHistoryLoaderListener mOnHistoryLoaderListener = notifications -> {
|
||||||
findViewById(R.id.today_list).setVisibility(
|
findViewById(R.id.today_list).setVisibility(
|
||||||
@@ -105,7 +148,8 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// for each package, new header and recycler view
|
// for each package, new header and recycler view
|
||||||
for (NotificationHistoryPackage nhp : notifications) {
|
for (int i = 0, notificationsSize = notifications.size(); i < notificationsSize; i++) {
|
||||||
|
NotificationHistoryPackage nhp = notifications.get(i);
|
||||||
View viewForPackage = LayoutInflater.from(this)
|
View viewForPackage = LayoutInflater.from(this)
|
||||||
.inflate(R.layout.notification_history_app_layout, null);
|
.inflate(R.layout.notification_history_app_layout, null);
|
||||||
|
|
||||||
@@ -115,6 +159,7 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
expand.setContentDescription(container.getVisibility() == View.VISIBLE
|
expand.setContentDescription(container.getVisibility() == View.VISIBLE
|
||||||
? getString(R.string.condition_expand_hide)
|
? getString(R.string.condition_expand_hide)
|
||||||
: getString(R.string.condition_expand_show));
|
: getString(R.string.condition_expand_show));
|
||||||
|
int finalI = i;
|
||||||
expand.setOnClickListener(v -> {
|
expand.setOnClickListener(v -> {
|
||||||
container.setVisibility(container.getVisibility() == View.VISIBLE
|
container.setVisibility(container.getVisibility() == View.VISIBLE
|
||||||
? View.GONE : View.VISIBLE);
|
? View.GONE : View.VISIBLE);
|
||||||
@@ -125,6 +170,11 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
? getString(R.string.condition_expand_hide)
|
? getString(R.string.condition_expand_hide)
|
||||||
: getString(R.string.condition_expand_show));
|
: getString(R.string.condition_expand_show));
|
||||||
expand.sendAccessibilityEvent(TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
expand.sendAccessibilityEvent(TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
||||||
|
mUiEventLogger.logWithPosition(
|
||||||
|
(container.getVisibility() == View.VISIBLE)
|
||||||
|
? NotificationHistoryEvent.NOTIFICATION_HISTORY_PACKAGE_HISTORY_OPEN
|
||||||
|
: NotificationHistoryEvent.NOTIFICATION_HISTORY_PACKAGE_HISTORY_CLOSE,
|
||||||
|
nhp.uid, nhp.pkgName, finalI);
|
||||||
});
|
});
|
||||||
|
|
||||||
TextView label = viewForPackage.findViewById(R.id.label);
|
TextView label = viewForPackage.findViewById(R.id.label);
|
||||||
@@ -148,7 +198,7 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
if (newCount == 0) {
|
if (newCount == 0) {
|
||||||
viewForPackage.setVisibility(View.GONE);
|
viewForPackage.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}));
|
}, mUiEventLogger));
|
||||||
((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete(
|
((NotificationHistoryAdapter) rv.getAdapter()).onRebuildComplete(
|
||||||
new ArrayList<>(nhp.notifications));
|
new ArrayList<>(nhp.notifications));
|
||||||
|
|
||||||
@@ -217,6 +267,8 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mUiEventLogger.log(NotificationHistoryEvent.NOTIFICATION_HISTORY_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -226,6 +278,7 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Cannot unregister listener", e);
|
Log.e(TAG, "Cannot unregister listener", e);
|
||||||
}
|
}
|
||||||
|
mUiEventLogger.log(NotificationHistoryEvent.NOTIFICATION_HISTORY_CLOSE);
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,9 +326,21 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
|
|
||||||
private final SwitchBar.OnSwitchChangeListener mOnSwitchClickListener =
|
private final SwitchBar.OnSwitchChangeListener mOnSwitchClickListener =
|
||||||
(switchView, isChecked) -> {
|
(switchView, isChecked) -> {
|
||||||
Settings.Secure.putInt(getContentResolver(),
|
int oldState = 0;
|
||||||
NOTIFICATION_HISTORY_ENABLED,
|
try {
|
||||||
isChecked ? 1 : 0);
|
oldState = Settings.Secure.getInt(getContentResolver(),
|
||||||
|
NOTIFICATION_HISTORY_ENABLED);
|
||||||
|
} catch (Settings.SettingNotFoundException ignored) {
|
||||||
|
}
|
||||||
|
final int newState = isChecked ? 1 : 0;
|
||||||
|
if (oldState != newState) {
|
||||||
|
Settings.Secure.putInt(getContentResolver(),
|
||||||
|
NOTIFICATION_HISTORY_ENABLED, newState);
|
||||||
|
mUiEventLogger.log(isChecked ? NotificationHistoryEvent.NOTIFICATION_HISTORY_ON
|
||||||
|
: NotificationHistoryEvent.NOTIFICATION_HISTORY_OFF);
|
||||||
|
Log.d(TAG, "onSwitchChange history to " + isChecked);
|
||||||
|
}
|
||||||
|
// Reset UI visibility to ensure it matches real state.
|
||||||
mHistoryOn.setVisibility(View.GONE);
|
mHistoryOn.setVisibility(View.GONE);
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
mHistoryEmpty.setVisibility(View.VISIBLE);
|
mHistoryEmpty.setVisibility(View.VISIBLE);
|
||||||
@@ -308,7 +373,8 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
LinearLayoutManager lm = new LinearLayoutManager(NotificationHistoryActivity.this);
|
LinearLayoutManager lm = new LinearLayoutManager(NotificationHistoryActivity.this);
|
||||||
mSnoozedRv.setLayoutManager(lm);
|
mSnoozedRv.setLayoutManager(lm);
|
||||||
mSnoozedRv.setAdapter(
|
mSnoozedRv.setAdapter(
|
||||||
new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm));
|
new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm,
|
||||||
|
true, mUiEventLogger));
|
||||||
mSnoozedRv.setNestedScrollingEnabled(false);
|
mSnoozedRv.setNestedScrollingEnabled(false);
|
||||||
|
|
||||||
if (snoozed == null || snoozed.length == 0) {
|
if (snoozed == null || snoozed.length == 0) {
|
||||||
@@ -323,7 +389,8 @@ public class NotificationHistoryActivity extends Activity {
|
|||||||
new LinearLayoutManager(NotificationHistoryActivity.this);
|
new LinearLayoutManager(NotificationHistoryActivity.this);
|
||||||
mDismissedRv.setLayoutManager(dismissLm);
|
mDismissedRv.setLayoutManager(dismissLm);
|
||||||
mDismissedRv.setAdapter(
|
mDismissedRv.setAdapter(
|
||||||
new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm));
|
new NotificationSbnAdapter(NotificationHistoryActivity.this, mPm, mUm,
|
||||||
|
false , mUiEventLogger));
|
||||||
mDismissedRv.setNestedScrollingEnabled(false);
|
mDismissedRv.setNestedScrollingEnabled(false);
|
||||||
|
|
||||||
if (dismissed == null || dismissed.length == 0) {
|
if (dismissed == null || dismissed.length == 0) {
|
||||||
|
@@ -36,6 +36,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -50,15 +51,17 @@ public class NotificationHistoryAdapter extends
|
|||||||
private INotificationManager mNm;
|
private INotificationManager mNm;
|
||||||
private List<HistoricalNotification> mValues;
|
private List<HistoricalNotification> mValues;
|
||||||
private OnItemDeletedListener mListener;
|
private OnItemDeletedListener mListener;
|
||||||
|
private UiEventLogger mUiEventLogger;
|
||||||
public NotificationHistoryAdapter(INotificationManager nm,
|
public NotificationHistoryAdapter(INotificationManager nm,
|
||||||
NotificationHistoryRecyclerView listView,
|
NotificationHistoryRecyclerView listView,
|
||||||
OnItemDeletedListener listener) {
|
OnItemDeletedListener listener,
|
||||||
|
UiEventLogger uiEventLogger) {
|
||||||
mValues = new ArrayList<>();
|
mValues = new ArrayList<>();
|
||||||
setHasStableIds(true);
|
setHasStableIds(true);
|
||||||
listView.setOnItemSwipeDeleteListener(this);
|
listView.setOnItemSwipeDeleteListener(this);
|
||||||
mNm = nm;
|
mNm = nm;
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
|
mUiEventLogger = uiEventLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,6 +79,8 @@ public class NotificationHistoryAdapter extends
|
|||||||
holder.setSummary(hn.getText());
|
holder.setSummary(hn.getText());
|
||||||
holder.setPostedTime(hn.getPostedTimeMs());
|
holder.setPostedTime(hn.getPostedTimeMs());
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
|
mUiEventLogger.logWithPosition(NotificationHistoryActivity.NotificationHistoryEvent
|
||||||
|
.NOTIFICATION_HISTORY_OLDER_ITEM_CLICK, hn.getUid(), hn.getPackage(), position);
|
||||||
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
||||||
.putExtra(EXTRA_APP_PACKAGE, hn.getPackage())
|
.putExtra(EXTRA_APP_PACKAGE, hn.getPackage())
|
||||||
.putExtra(EXTRA_CHANNEL_ID, hn.getChannelId())
|
.putExtra(EXTRA_CHANNEL_ID, hn.getChannelId())
|
||||||
@@ -136,6 +141,9 @@ public class NotificationHistoryAdapter extends
|
|||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Failed to delete item", e);
|
Slog.e(TAG, "Failed to delete item", e);
|
||||||
}
|
}
|
||||||
|
mUiEventLogger.logWithPosition(NotificationHistoryActivity.NotificationHistoryEvent
|
||||||
|
.NOTIFICATION_HISTORY_OLDER_ITEM_DELETE, hn.getUid(), hn.getPackage(),
|
||||||
|
position);
|
||||||
}
|
}
|
||||||
mListener.onItemDeleted(mValues.size());
|
mListener.onItemDeleted(mValues.size());
|
||||||
notifyItemRemoved(position);
|
notifyItemRemoved(position);
|
||||||
|
@@ -49,11 +49,11 @@ import android.view.ViewGroup;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.internal.util.ContrastColorUtil;
|
import com.android.internal.util.ContrastColorUtil;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -70,8 +70,11 @@ public class NotificationSbnAdapter extends
|
|||||||
private boolean mInNightMode;
|
private boolean mInNightMode;
|
||||||
private @UserIdInt int mCurrentUser;
|
private @UserIdInt int mCurrentUser;
|
||||||
private List<Integer> mEnabledProfiles = new ArrayList<>();
|
private List<Integer> mEnabledProfiles = new ArrayList<>();
|
||||||
|
private boolean mIsSnoozed;
|
||||||
|
private UiEventLogger mUiEventLogger;
|
||||||
|
|
||||||
public NotificationSbnAdapter(Context context, PackageManager pm, UserManager um) {
|
public NotificationSbnAdapter(Context context, PackageManager pm, UserManager um,
|
||||||
|
boolean isSnoozed, UiEventLogger uiEventLogger) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mPm = pm;
|
mPm = pm;
|
||||||
mUserBadgeCache = new HashMap<>();
|
mUserBadgeCache = new HashMap<>();
|
||||||
@@ -89,6 +92,9 @@ public class NotificationSbnAdapter extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setHasStableIds(true);
|
setHasStableIds(true);
|
||||||
|
// If true, this is the panel for snoozed notifs, otherwise the one for dismissed notifs.
|
||||||
|
mIsSnoozed = isSnoozed;
|
||||||
|
mUiEventLogger = uiEventLogger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -116,8 +122,9 @@ public class NotificationSbnAdapter extends
|
|||||||
mUserBadgeCache.put(userId, profile);
|
mUserBadgeCache.put(userId, profile);
|
||||||
}
|
}
|
||||||
holder.setProfileBadge(mUserBadgeCache.get(userId));
|
holder.setProfileBadge(mUserBadgeCache.get(userId));
|
||||||
holder.addOnClick(sbn.getPackageName(), sbn.getUserId(),
|
holder.addOnClick(position, sbn.getPackageName(), sbn.getUid(), sbn.getUserId(),
|
||||||
sbn.getNotification().contentIntent);
|
sbn.getNotification().contentIntent, sbn.getInstanceId(), mIsSnoozed,
|
||||||
|
mUiEventLogger);
|
||||||
holder.itemView.setOnLongClickListener(v -> {
|
holder.itemView.setOnLongClickListener(v -> {
|
||||||
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
|
||||||
.putExtra(EXTRA_APP_PACKAGE, sbn.getPackageName())
|
.putExtra(EXTRA_APP_PACKAGE, sbn.getPackageName())
|
||||||
|
@@ -20,7 +20,6 @@ import android.app.PendingIntent;
|
|||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
@@ -34,6 +33,8 @@ import androidx.core.view.ViewCompat;
|
|||||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.internal.logging.InstanceId;
|
||||||
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
public class NotificationSbnViewHolder extends RecyclerView.ViewHolder {
|
public class NotificationSbnViewHolder extends RecyclerView.ViewHolder {
|
||||||
@@ -91,13 +92,22 @@ public class NotificationSbnViewHolder extends RecyclerView.ViewHolder {
|
|||||||
mDivider.setVisibility(visible ? View.VISIBLE : View.GONE);
|
mDivider.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addOnClick(String pkg, int userId, PendingIntent pi) {
|
void addOnClick(int position, String pkg, int uid, int userId, PendingIntent pi,
|
||||||
|
InstanceId instanceId,
|
||||||
|
boolean isSnoozed, UiEventLogger uiEventLogger) {
|
||||||
Intent appIntent = itemView.getContext().getPackageManager()
|
Intent appIntent = itemView.getContext().getPackageManager()
|
||||||
.getLaunchIntentForPackage(pkg);
|
.getLaunchIntentForPackage(pkg);
|
||||||
boolean isPendingIntentValid = pi != null && PendingIntent.getActivity(
|
boolean isPendingIntentValid = pi != null && PendingIntent.getActivity(
|
||||||
itemView.getContext(), 0, pi.getIntent(), PendingIntent.FLAG_NO_CREATE) != null;
|
itemView.getContext(), 0, pi.getIntent(), PendingIntent.FLAG_NO_CREATE) != null;
|
||||||
if (isPendingIntentValid || appIntent != null) {
|
if (isPendingIntentValid || appIntent != null) {
|
||||||
itemView.setOnClickListener(v -> {
|
itemView.setOnClickListener(v -> {
|
||||||
|
uiEventLogger.logWithInstanceIdAndPosition(
|
||||||
|
isSnoozed
|
||||||
|
? NotificationHistoryActivity.NotificationHistoryEvent
|
||||||
|
.NOTIFICATION_HISTORY_SNOOZED_ITEM_CLICK
|
||||||
|
: NotificationHistoryActivity.NotificationHistoryEvent
|
||||||
|
.NOTIFICATION_HISTORY_RECENT_ITEM_CLICK,
|
||||||
|
uid, pkg, instanceId, position);
|
||||||
if (pi != null) {
|
if (pi != null) {
|
||||||
try {
|
try {
|
||||||
pi.send();
|
pi.send();
|
||||||
|
Reference in New Issue
Block a user