Fix issues 6512411 and 6512951 in ManageApplications.
6512411 java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0 6512951 Settings crash while returning from App info screen Also fix padding around the UI, and display of storage use. Change-Id: Ibfcfe1a4a80f25f81ba2cabbb2e3d60aaa9ac04e
This commit is contained in:
@@ -42,6 +42,7 @@ import android.os.IBinder;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
|
import android.preference.PreferenceFrameLayout;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.support.v4.view.PagerAdapter;
|
import android.support.v4.view.PagerAdapter;
|
||||||
import android.support.v4.view.PagerTabStrip;
|
import android.support.v4.view.PagerTabStrip;
|
||||||
@@ -55,17 +56,13 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.AdapterView.OnItemClickListener;
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.Filter;
|
import android.widget.Filter;
|
||||||
import android.widget.Filterable;
|
import android.widget.Filterable;
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.internal.app.IMediaContainerService;
|
import com.android.internal.app.IMediaContainerService;
|
||||||
@@ -122,6 +119,11 @@ final class CanBeOnSdCardChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AppClickListener {
|
||||||
|
void onItemClick(ManageApplications.TabInfo tab, AdapterView<?> parent,
|
||||||
|
View view, int position, long id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity to pick an application that will be used to display installation information and
|
* Activity to pick an application that will be used to display installation information and
|
||||||
* options to uninstall/delete user data for system applications. This activity
|
* options to uninstall/delete user data for system applications. This activity
|
||||||
@@ -129,7 +131,7 @@ final class CanBeOnSdCardChecker {
|
|||||||
* intent.
|
* intent.
|
||||||
*/
|
*/
|
||||||
public class ManageApplications extends Fragment implements
|
public class ManageApplications extends Fragment implements
|
||||||
OnItemClickListener, DialogInterface.OnClickListener,
|
AppClickListener, DialogInterface.OnClickListener,
|
||||||
DialogInterface.OnDismissListener {
|
DialogInterface.OnDismissListener {
|
||||||
|
|
||||||
static final String TAG = "ManageApplications";
|
static final String TAG = "ManageApplications";
|
||||||
@@ -174,11 +176,10 @@ public class ManageApplications extends Fragment implements
|
|||||||
public static class TabInfo implements OnItemClickListener {
|
public static class TabInfo implements OnItemClickListener {
|
||||||
public final ManageApplications mOwner;
|
public final ManageApplications mOwner;
|
||||||
public final ApplicationsState mApplicationsState;
|
public final ApplicationsState mApplicationsState;
|
||||||
public final IMediaContainerService mContainerService;
|
|
||||||
public final CharSequence mLabel;
|
public final CharSequence mLabel;
|
||||||
public final int mListType;
|
public final int mListType;
|
||||||
public final int mFilter;
|
public final int mFilter;
|
||||||
public final OnItemClickListener mClickListener;
|
public final AppClickListener mClickListener;
|
||||||
public final CharSequence mInvalidSizeStr;
|
public final CharSequence mInvalidSizeStr;
|
||||||
public final CharSequence mComputingSizeStr;
|
public final CharSequence mComputingSizeStr;
|
||||||
private final Bundle mSavedInstanceState;
|
private final Bundle mSavedInstanceState;
|
||||||
@@ -187,6 +188,8 @@ public class ManageApplications extends Fragment implements
|
|||||||
public LayoutInflater mInflater;
|
public LayoutInflater mInflater;
|
||||||
public View mRootView;
|
public View mRootView;
|
||||||
|
|
||||||
|
private IMediaContainerService mContainerService;
|
||||||
|
|
||||||
private View mLoadingContainer;
|
private View mLoadingContainer;
|
||||||
|
|
||||||
private View mListContainer;
|
private View mListContainer;
|
||||||
@@ -200,6 +203,7 @@ public class ManageApplications extends Fragment implements
|
|||||||
private TextView mStorageChartLabel;
|
private TextView mStorageChartLabel;
|
||||||
private TextView mUsedStorageText;
|
private TextView mUsedStorageText;
|
||||||
private TextView mFreeStorageText;
|
private TextView mFreeStorageText;
|
||||||
|
private long mFreeStorage = 0, mAppStorage = 0, mTotalStorage = 0;
|
||||||
private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
|
private long mLastUsedStorage, mLastAppStorage, mLastFreeStorage;
|
||||||
|
|
||||||
final Runnable mRunningProcessesAvail = new Runnable() {
|
final Runnable mRunningProcessesAvail = new Runnable() {
|
||||||
@@ -209,12 +213,10 @@ public class ManageApplications extends Fragment implements
|
|||||||
};
|
};
|
||||||
|
|
||||||
public TabInfo(ManageApplications owner, ApplicationsState apps,
|
public TabInfo(ManageApplications owner, ApplicationsState apps,
|
||||||
IMediaContainerService containerService,
|
CharSequence label, int listType, AppClickListener clickListener,
|
||||||
CharSequence label, int listType, OnItemClickListener clickListener,
|
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
mOwner = owner;
|
mOwner = owner;
|
||||||
mApplicationsState = apps;
|
mApplicationsState = apps;
|
||||||
mContainerService = containerService;
|
|
||||||
mLabel = label;
|
mLabel = label;
|
||||||
mListType = listType;
|
mListType = listType;
|
||||||
switch (listType) {
|
switch (listType) {
|
||||||
@@ -228,6 +230,11 @@ public class ManageApplications extends Fragment implements
|
|||||||
mSavedInstanceState = savedInstanceState;
|
mSavedInstanceState = savedInstanceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setContainerService(IMediaContainerService containerService) {
|
||||||
|
mContainerService = containerService;
|
||||||
|
updateStorageUsage();
|
||||||
|
}
|
||||||
|
|
||||||
public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
|
public View build(LayoutInflater inflater, ViewGroup contentParent, View contentChild) {
|
||||||
if (mRootView != null) {
|
if (mRootView != null) {
|
||||||
return mRootView;
|
return mRootView;
|
||||||
@@ -260,6 +267,14 @@ public class ManageApplications extends Fragment implements
|
|||||||
mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
|
mUsedStorageText = (TextView)mListContainer.findViewById(R.id.usedStorageText);
|
||||||
mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
|
mFreeStorageText = (TextView)mListContainer.findViewById(R.id.freeStorageText);
|
||||||
Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
|
Utils.prepareCustomPreferencesList(contentParent, contentChild, mListView, false);
|
||||||
|
if (mFilter == FILTER_APPS_SDCARD) {
|
||||||
|
mStorageChartLabel.setText(mOwner.getActivity().getText(
|
||||||
|
R.string.sd_card_storage));
|
||||||
|
} else {
|
||||||
|
mStorageChartLabel.setText(mOwner.getActivity().getText(
|
||||||
|
R.string.internal_storage));
|
||||||
|
}
|
||||||
|
applyCurrentStorage();
|
||||||
}
|
}
|
||||||
mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
|
mRunningProcessesView = (RunningProcessesView)mRootView.findViewById(
|
||||||
R.id.running_processes);
|
R.id.running_processes);
|
||||||
@@ -270,6 +285,15 @@ public class ManageApplications extends Fragment implements
|
|||||||
return mRootView;
|
return mRootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void detachView() {
|
||||||
|
if (mRootView != null) {
|
||||||
|
ViewGroup group = (ViewGroup)mRootView.getParent();
|
||||||
|
if (group != null) {
|
||||||
|
group.removeView(mRootView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void resume(int sortOrder) {
|
public void resume(int sortOrder) {
|
||||||
if (mApplications != null) {
|
if (mApplications != null) {
|
||||||
mApplications.resume(sortOrder);
|
mApplications.resume(sortOrder);
|
||||||
@@ -295,27 +319,22 @@ public class ManageApplications extends Fragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateStorageUsage() {
|
void updateStorageUsage() {
|
||||||
// Fragment view not yet created?
|
|
||||||
if (mRootView == null) return;
|
|
||||||
// Make sure a callback didn't come at an inopportune time.
|
// Make sure a callback didn't come at an inopportune time.
|
||||||
if (mOwner.getActivity() == null) return;
|
if (mOwner.getActivity() == null) return;
|
||||||
// Doesn't make sense for stuff that is not an app list.
|
// Doesn't make sense for stuff that is not an app list.
|
||||||
if (mApplications == null) return;
|
if (mApplications == null) return;
|
||||||
|
|
||||||
long freeStorage = 0;
|
mFreeStorage = 0;
|
||||||
long appStorage = 0;
|
mAppStorage = 0;
|
||||||
long totalStorage = 0;
|
mTotalStorage = 0;
|
||||||
CharSequence newLabel = null;
|
|
||||||
|
|
||||||
if (mFilter == FILTER_APPS_SDCARD) {
|
if (mFilter == FILTER_APPS_SDCARD) {
|
||||||
newLabel = mOwner.getActivity().getText(R.string.sd_card_storage);
|
|
||||||
|
|
||||||
if (mContainerService != null) {
|
if (mContainerService != null) {
|
||||||
try {
|
try {
|
||||||
final long[] stats = mContainerService.getFileSystemStats(
|
final long[] stats = mContainerService.getFileSystemStats(
|
||||||
Environment.getExternalStorageDirectory().getPath());
|
Environment.getExternalStorageDirectory().getPath());
|
||||||
totalStorage = stats[0];
|
mTotalStorage = stats[0];
|
||||||
freeStorage = stats[1];
|
mFreeStorage = stats[1];
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w(TAG, "Problem in container service", e);
|
Log.w(TAG, "Problem in container service", e);
|
||||||
}
|
}
|
||||||
@@ -325,18 +344,16 @@ public class ManageApplications extends Fragment implements
|
|||||||
final int N = mApplications.getCount();
|
final int N = mApplications.getCount();
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
|
ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
|
||||||
appStorage += ae.externalCodeSize + ae.externalDataSize;
|
mAppStorage += ae.externalCodeSize + ae.externalDataSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newLabel = mOwner.getActivity().getText(R.string.internal_storage);
|
|
||||||
|
|
||||||
if (mContainerService != null) {
|
if (mContainerService != null) {
|
||||||
try {
|
try {
|
||||||
final long[] stats = mContainerService.getFileSystemStats(
|
final long[] stats = mContainerService.getFileSystemStats(
|
||||||
Environment.getDataDirectory().getPath());
|
Environment.getDataDirectory().getPath());
|
||||||
totalStorage = stats[0];
|
mTotalStorage = stats[0];
|
||||||
freeStorage = stats[1];
|
mFreeStorage = stats[1];
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w(TAG, "Problem in container service", e);
|
Log.w(TAG, "Problem in container service", e);
|
||||||
}
|
}
|
||||||
@@ -347,21 +364,27 @@ public class ManageApplications extends Fragment implements
|
|||||||
final int N = mApplications.getCount();
|
final int N = mApplications.getCount();
|
||||||
for (int i=0; i<N; i++) {
|
for (int i=0; i<N; i++) {
|
||||||
ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
|
ApplicationsState.AppEntry ae = mApplications.getAppEntry(i);
|
||||||
appStorage += ae.codeSize + ae.dataSize;
|
mAppStorage += ae.codeSize + ae.dataSize;
|
||||||
if (emulatedStorage) {
|
if (emulatedStorage) {
|
||||||
appStorage += ae.externalCodeSize + ae.externalDataSize;
|
mAppStorage += ae.externalCodeSize + ae.externalDataSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeStorage += mApplicationsState.sumCacheSizes();
|
mFreeStorage += mApplicationsState.sumCacheSizes();
|
||||||
}
|
}
|
||||||
if (newLabel != null) {
|
|
||||||
mStorageChartLabel.setText(newLabel);
|
applyCurrentStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyCurrentStorage() {
|
||||||
|
// If view hierarchy is not yet created, no views to update.
|
||||||
|
if (mRootView == null) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (totalStorage > 0) {
|
if (mTotalStorage > 0) {
|
||||||
mColorBar.setRatios((totalStorage-freeStorage-appStorage)/(float)totalStorage,
|
mColorBar.setRatios((mTotalStorage-mFreeStorage-mAppStorage)/(float)mTotalStorage,
|
||||||
appStorage/(float)totalStorage, freeStorage/(float)totalStorage);
|
mAppStorage/(float)mTotalStorage, mFreeStorage/(float)mTotalStorage);
|
||||||
long usedStorage = totalStorage - freeStorage;
|
long usedStorage = mTotalStorage - mFreeStorage;
|
||||||
if (mLastUsedStorage != usedStorage) {
|
if (mLastUsedStorage != usedStorage) {
|
||||||
mLastUsedStorage = usedStorage;
|
mLastUsedStorage = usedStorage;
|
||||||
String sizeStr = Formatter.formatShortFileSize(
|
String sizeStr = Formatter.formatShortFileSize(
|
||||||
@@ -369,10 +392,10 @@ public class ManageApplications extends Fragment implements
|
|||||||
mUsedStorageText.setText(mOwner.getActivity().getResources().getString(
|
mUsedStorageText.setText(mOwner.getActivity().getResources().getString(
|
||||||
R.string.service_foreground_processes, sizeStr));
|
R.string.service_foreground_processes, sizeStr));
|
||||||
}
|
}
|
||||||
if (mLastFreeStorage != freeStorage) {
|
if (mLastFreeStorage != mFreeStorage) {
|
||||||
mLastFreeStorage = freeStorage;
|
mLastFreeStorage = mFreeStorage;
|
||||||
String sizeStr = Formatter.formatShortFileSize(
|
String sizeStr = Formatter.formatShortFileSize(
|
||||||
mOwner.getActivity(), freeStorage);
|
mOwner.getActivity(), mFreeStorage);
|
||||||
mFreeStorageText.setText(mOwner.getActivity().getResources().getString(
|
mFreeStorageText.setText(mOwner.getActivity().getResources().getString(
|
||||||
R.string.service_background_processes, sizeStr));
|
R.string.service_background_processes, sizeStr));
|
||||||
}
|
}
|
||||||
@@ -391,7 +414,7 @@ public class ManageApplications extends Fragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
mClickListener.onItemClick(parent, view, position, id);
|
mClickListener.onItemClick(this, parent, view, position, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleRunningProcessesAvail() {
|
void handleRunningProcessesAvail() {
|
||||||
@@ -711,6 +734,7 @@ public class ManageApplications extends Fragment implements
|
|||||||
if (mLastSortMode == SORT_ORDER_SIZE) {
|
if (mLastSortMode == SORT_ORDER_SIZE) {
|
||||||
rebuild(false);
|
rebuild(false);
|
||||||
}
|
}
|
||||||
|
mTab.updateStorageUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
@@ -825,24 +849,24 @@ public class ManageApplications extends Fragment implements
|
|||||||
mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
|
mInvalidSizeStr = getActivity().getText(R.string.invalid_size_value);
|
||||||
mComputingSizeStr = getActivity().getText(R.string.computing_size);
|
mComputingSizeStr = getActivity().getText(R.string.computing_size);
|
||||||
|
|
||||||
TabInfo tab = new TabInfo(this, mApplicationsState, mContainerService,
|
TabInfo tab = new TabInfo(this, mApplicationsState,
|
||||||
getActivity().getString(R.string.filter_apps_third_party),
|
getActivity().getString(R.string.filter_apps_third_party),
|
||||||
LIST_TYPE_DOWNLOADED, this, savedInstanceState);
|
LIST_TYPE_DOWNLOADED, this, savedInstanceState);
|
||||||
mTabs.add(tab);
|
mTabs.add(tab);
|
||||||
|
|
||||||
if (!Environment.isExternalStorageEmulated()) {
|
if (!Environment.isExternalStorageEmulated()) {
|
||||||
tab = new TabInfo(this, mApplicationsState, mContainerService,
|
tab = new TabInfo(this, mApplicationsState,
|
||||||
getActivity().getString(R.string.filter_apps_onsdcard),
|
getActivity().getString(R.string.filter_apps_onsdcard),
|
||||||
LIST_TYPE_SDCARD, this, savedInstanceState);
|
LIST_TYPE_SDCARD, this, savedInstanceState);
|
||||||
mTabs.add(tab);
|
mTabs.add(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
tab = new TabInfo(this, mApplicationsState, mContainerService,
|
tab = new TabInfo(this, mApplicationsState,
|
||||||
getActivity().getString(R.string.filter_apps_running),
|
getActivity().getString(R.string.filter_apps_running),
|
||||||
LIST_TYPE_RUNNING, this, savedInstanceState);
|
LIST_TYPE_RUNNING, this, savedInstanceState);
|
||||||
mTabs.add(tab);
|
mTabs.add(tab);
|
||||||
|
|
||||||
tab = new TabInfo(this, mApplicationsState, mContainerService,
|
tab = new TabInfo(this, mApplicationsState,
|
||||||
getActivity().getString(R.string.filter_apps_all),
|
getActivity().getString(R.string.filter_apps_all),
|
||||||
LIST_TYPE_ALL, this, savedInstanceState);
|
LIST_TYPE_ALL, this, savedInstanceState);
|
||||||
mTabs.add(tab);
|
mTabs.add(tab);
|
||||||
@@ -866,6 +890,12 @@ public class ManageApplications extends Fragment implements
|
|||||||
PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
|
PagerTabStrip tabs = (PagerTabStrip) rootView.findViewById(R.id.tabs);
|
||||||
tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
|
tabs.setTabIndicatorColorResource(android.R.color.holo_blue_light);
|
||||||
|
|
||||||
|
// We have to do this now because PreferenceFrameLayout looks at it
|
||||||
|
// only when the view is added.
|
||||||
|
if (container instanceof PreferenceFrameLayout) {
|
||||||
|
((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
|
if (savedInstanceState != null && savedInstanceState.getBoolean(EXTRA_RESET_DIALOG)) {
|
||||||
buildResetDialog();
|
buildResetDialog();
|
||||||
}
|
}
|
||||||
@@ -918,6 +948,17 @@ public class ManageApplications extends Fragment implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
|
||||||
|
// We are going to keep the tab data structures around, but they
|
||||||
|
// are no longer attached to their view hierarchy.
|
||||||
|
for (int i=0; i<mTabs.size(); i++) {
|
||||||
|
mTabs.get(i).detachView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
|
if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {
|
||||||
@@ -1129,10 +1170,10 @@ public class ManageApplications extends Fragment implements
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position,
|
public void onItemClick(TabInfo tab, AdapterView<?> parent, View view, int position,
|
||||||
long id) {
|
long id) {
|
||||||
if (mCurTab != null && mCurTab.mApplications != null) {
|
if (tab.mApplications != null && tab.mApplications.getCount() > position) {
|
||||||
ApplicationsState.AppEntry entry = mCurTab.mApplications.getAppEntry(position);
|
ApplicationsState.AppEntry entry = tab.mApplications.getAppEntry(position);
|
||||||
mCurrentPkgName = entry.info.packageName;
|
mCurrentPkgName = entry.info.packageName;
|
||||||
startApplicationDetailsActivity();
|
startApplicationDetailsActivity();
|
||||||
}
|
}
|
||||||
@@ -1170,8 +1211,8 @@ public class ManageApplications extends Fragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
mContainerService = IMediaContainerService.Stub.asInterface(service);
|
mContainerService = IMediaContainerService.Stub.asInterface(service);
|
||||||
if (mCurTab != null) {
|
for (int i=0; i<mTabs.size(); i++) {
|
||||||
mCurTab.updateStorageUsage();
|
mTabs.get(i).setContainerService(mContainerService);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user