Merge commit 'goog/cupcake'
This commit is contained in:
@@ -548,16 +548,6 @@ public class Term extends Activity {
|
||||
+ controlKey + " 6 ==> Control-^").
|
||||
show();
|
||||
}
|
||||
|
||||
private void print(String msg) {
|
||||
char[] chars = msg.toCharArray();
|
||||
int len = chars.length;
|
||||
byte[] bytes = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
bytes[i] = (byte) chars[i];
|
||||
}
|
||||
mEmulatorView.append(bytes, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2707,8 +2697,13 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hideStatusIcon() {
|
||||
return true;
|
||||
public boolean performEditorAction(int actionCode) {
|
||||
if(actionCode == EditorInfo.IME_ACTION_UNSPECIFIED) {
|
||||
// The "return" key has been pressed on the IME.
|
||||
sendText("\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean performContextMenuAction(int id) {
|
||||
@@ -2720,13 +2715,12 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener {
|
||||
}
|
||||
|
||||
public boolean sendKeyEvent(KeyEvent event) {
|
||||
switch(event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
sendChar('\r');
|
||||
break;
|
||||
case KeyEvent.KEYCODE_DEL:
|
||||
sendChar(127);
|
||||
break;
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
switch(event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_DEL:
|
||||
sendChar(127);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2739,10 +2733,6 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean showStatusIcon(String packageName, int resId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendChar(int c) {
|
||||
try {
|
||||
mTermOut.write(c);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Project properties (right click project in Package Explorer, then "Properties"), lets you edit project target.
|
||||
* New Launch configuration option to choose debug deployment target.
|
||||
- Ability to export multiple apk from one project, using resource filters. See the 'android' property for Android projects.
|
||||
- Support for running JUnit tests on a device/emulator from a new "Android JUnit tests" launch configuration.
|
||||
|
||||
0.8.1:
|
||||
|
||||
|
||||
@@ -45,16 +45,16 @@ Require-Bundle: com.android.ide.eclipse.ddms,
|
||||
org.eclipse.ltk.core.refactoring,
|
||||
org.eclipse.ltk.ui.refactoring
|
||||
Eclipse-LazyStart: true
|
||||
Export-Package: com.android.ide.eclipse.adt,
|
||||
Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.adt.build;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.adt.launch;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.adt.project;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.adt.project.internal;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.adt.sdk;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.adt.wizards.newproject;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.common,
|
||||
com.android.ide.eclipse.common.project,
|
||||
com.android.ide.eclipse.common.resources,
|
||||
com.android.ide.eclipse.common;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.common.project;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.common.resources;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.editors;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.editors.descriptors;x-friends:="com.android.ide.eclipse.tests",
|
||||
com.android.ide.eclipse.editors.layout;x-friends:="com.android.ide.eclipse.tests",
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.build;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtConstants;
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.project.ApkInstallManager;
|
||||
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||
import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
|
||||
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||
@@ -551,6 +552,9 @@ public class ApkBuilder extends BaseBuilder {
|
||||
// and store it
|
||||
saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
|
||||
|
||||
// reset the installation manager to force new installs of this project
|
||||
ApkInstallManager.getInstance().resetInstallationFor(project);
|
||||
|
||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(),
|
||||
"Build Success!");
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration.TargetMode;
|
||||
import com.android.ide.eclipse.adt.launch.DelayedLaunchInfo.InstallRetryMode;
|
||||
import com.android.ide.eclipse.adt.launch.DeviceChooserDialog.DeviceChooserResponse;
|
||||
import com.android.ide.eclipse.adt.project.ApkInstallManager;
|
||||
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||
import com.android.ide.eclipse.common.project.AndroidManifestParser;
|
||||
@@ -762,13 +763,46 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
|
||||
|
||||
/**
|
||||
* Syncs the application on the device/emulator.
|
||||
* If needed, syncs the application and all its dependencies on the device/emulator.
|
||||
*
|
||||
* @param launchInfo The Launch information object.
|
||||
* @param device the device on which to sync the application
|
||||
* @return true if the install succeeded.
|
||||
*/
|
||||
private boolean syncApp(DelayedLaunchInfo launchInfo, IDevice device) {
|
||||
boolean alreadyInstalled = ApkInstallManager.getInstance().isApplicationInstalled(
|
||||
launchInfo.getProject(), device);
|
||||
|
||||
if (alreadyInstalled) {
|
||||
AdtPlugin.printToConsole(launchInfo.getProject(),
|
||||
"Application already deployed. No need to reinstall.");
|
||||
} else {
|
||||
if (doSyncApp(launchInfo, device) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The app is now installed, now try the dependent projects
|
||||
for (DelayedLaunchInfo dependentLaunchInfo : getDependenciesLaunchInfo(launchInfo)) {
|
||||
String msg = String.format("Project dependency found, installing: %s",
|
||||
dependentLaunchInfo.getProject().getName());
|
||||
AdtPlugin.printToConsole(launchInfo.getProject(), msg);
|
||||
if (syncApp(dependentLaunchInfo, device) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs the application on the device/emulator.
|
||||
*
|
||||
* @param launchInfo The Launch information object.
|
||||
* @param device the device on which to sync the application
|
||||
* @return true if the install succeeded.
|
||||
*/
|
||||
private boolean doSyncApp(DelayedLaunchInfo launchInfo, IDevice device) {
|
||||
SyncService sync = device.getSyncService();
|
||||
if (sync != null) {
|
||||
IPath path = launchInfo.getPackageFile().getLocation();
|
||||
@@ -812,12 +846,10 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
return false;
|
||||
}
|
||||
|
||||
// The app is now installed, now try the dependent projects
|
||||
for (DelayedLaunchInfo dependentLaunchInfo : getDependenciesLaunchInfo(launchInfo)) {
|
||||
String msg = String.format("Project dependency found, syncing: %s",
|
||||
dependentLaunchInfo.getProject().getName());
|
||||
AdtPlugin.printToConsole(launchInfo.getProject(), msg);
|
||||
syncApp(dependentLaunchInfo, device);
|
||||
// if the installation succeeded, we register it.
|
||||
if (installResult) {
|
||||
ApkInstallManager.getInstance().registerInstallation(
|
||||
launchInfo.getProject(), device);
|
||||
}
|
||||
|
||||
return installResult;
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
|
||||
*
|
||||
* 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.ide.eclipse.adt.project;
|
||||
|
||||
import com.android.ddmlib.AndroidDebugBridge;
|
||||
import com.android.ddmlib.Device;
|
||||
import com.android.ddmlib.IDevice;
|
||||
import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener;
|
||||
import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
|
||||
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor;
|
||||
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Registers which apk was installed on which device.
|
||||
* <p/>
|
||||
* The goal of this class is to remember the installation of APKs on devices, and provide
|
||||
* information about whether a new APK should be installed on a device prior to running the
|
||||
* application from a launch configuration.
|
||||
* <p/>
|
||||
* The manager uses {@link IProject} and {@link IDevice} to identify the target device and the
|
||||
* (project generating the) APK. This ensures that disconnected and reconnected devices will
|
||||
* always receive new APKs (since the APK could be uninstalled manually).
|
||||
* <p/>
|
||||
* Manually uninstalling an APK from a connected device will still be a problem, but this should
|
||||
* be a limited use case.
|
||||
* <p/>
|
||||
* This is a singleton. To get the instance, use {@link #getInstance()}
|
||||
*/
|
||||
public class ApkInstallManager implements IDeviceChangeListener, IDebugBridgeChangeListener,
|
||||
IProjectListener {
|
||||
|
||||
private final static ApkInstallManager sThis = new ApkInstallManager();
|
||||
|
||||
/**
|
||||
* Internal struct to associate a project and a device.
|
||||
*/
|
||||
private static class ApkInstall {
|
||||
public ApkInstall(IProject project, IDevice device) {
|
||||
this.project = project;
|
||||
this.device = device;
|
||||
}
|
||||
IProject project;
|
||||
IDevice device;
|
||||
}
|
||||
|
||||
private final ArrayList<ApkInstall> mInstallList = new ArrayList<ApkInstall>();
|
||||
|
||||
public static ApkInstallManager getInstance() {
|
||||
return sThis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an installation of <var>project</var> onto <var>device</var>
|
||||
* @param project The project that was installed.
|
||||
* @param device The device that received the installation.
|
||||
*/
|
||||
public void registerInstallation(IProject project, IDevice device) {
|
||||
synchronized (mInstallList) {
|
||||
mInstallList.add(new ApkInstall(project, device));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a <var>project</var> was installed on the <var>device</var>.
|
||||
* @param project the project that may have been installed.
|
||||
* @param device the device that may have received the installation.
|
||||
* @return
|
||||
*/
|
||||
public boolean isApplicationInstalled(IProject project, IDevice device) {
|
||||
synchronized (mInstallList) {
|
||||
for (ApkInstall install : mInstallList) {
|
||||
if (project == install.project && device == install.device) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets registered installations for a specific {@link IProject}.
|
||||
* <p/>This ensures that {@link #isApplicationInstalled(IProject, IDevice)} will always return
|
||||
* <code>null</code> for this specified project, for any device.
|
||||
* @param project the project for which to reset all installations.
|
||||
*/
|
||||
public void resetInstallationFor(IProject project) {
|
||||
synchronized (mInstallList) {
|
||||
for (int i = 0 ; i < mInstallList.size() ;) {
|
||||
ApkInstall install = mInstallList.get(i);
|
||||
if (install.project == project) {
|
||||
mInstallList.remove(i);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ApkInstallManager() {
|
||||
AndroidDebugBridge.addDeviceChangeListener(this);
|
||||
AndroidDebugBridge.addDebugBridgeChangeListener(this);
|
||||
ResourceMonitor.getMonitor().addProjectListener(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Responds to a bridge change by clearing the full installation list.
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener#bridgeChanged(com.android.ddmlib.AndroidDebugBridge)
|
||||
*/
|
||||
public void bridgeChanged(AndroidDebugBridge bridge) {
|
||||
// the bridge changed, there is no way to know which IDevice will be which.
|
||||
// We reset everything
|
||||
synchronized (mInstallList) {
|
||||
mInstallList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Responds to a device being disconnected by removing all installations related to this device.
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceDisconnected(com.android.ddmlib.Device)
|
||||
*/
|
||||
public void deviceDisconnected(Device device) {
|
||||
synchronized (mInstallList) {
|
||||
for (int i = 0 ; i < mInstallList.size() ;) {
|
||||
ApkInstall install = mInstallList.get(i);
|
||||
if (install.device == device) {
|
||||
mInstallList.remove(i);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Responds to a close project by resetting all its installation.
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectClosed(org.eclipse.core.resources.IProject)
|
||||
*/
|
||||
public void projectClosed(IProject project) {
|
||||
resetInstallationFor(project);
|
||||
}
|
||||
|
||||
/*
|
||||
* Responds to a close project by resetting all its installation.
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectDeleted(org.eclipse.core.resources.IProject)
|
||||
*/
|
||||
public void projectDeleted(IProject project) {
|
||||
resetInstallationFor(project);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does nothing
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceChanged(com.android.ddmlib.Device, int)
|
||||
*/
|
||||
public void deviceChanged(Device device, int changeMask) {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
/*
|
||||
* Does nothing
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceConnected(com.android.ddmlib.Device)
|
||||
*/
|
||||
public void deviceConnected(Device device) {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
/*
|
||||
* Does nothing
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectOpened(org.eclipse.core.resources.IProject)
|
||||
*/
|
||||
public void projectOpened(IProject project) {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
/*
|
||||
* Does nothing
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectOpenedWithWorkspace(org.eclipse.core.resources.IProject)
|
||||
*/
|
||||
public void projectOpenedWithWorkspace(IProject project) {
|
||||
// nothing to do.
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.ide.eclipse.adt.wizards.actions;
|
||||
|
||||
import com.android.ide.eclipse.editors.wizards.NewXmlFileWizard;
|
||||
import com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileWizard;
|
||||
|
||||
import org.eclipse.jface.action.IAction;
|
||||
import org.eclipse.ui.IWorkbenchWizard;
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.ide.eclipse.adt.project;
|
||||
package com.android.ide.eclipse.adt.wizards.actions;
|
||||
|
||||
import com.android.ide.eclipse.editors.wizards.NewXmlFileWizard;
|
||||
import com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileWizard;
|
||||
|
||||
import org.eclipse.jface.action.IAction;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
|
||||
package com.android.ide.eclipse.editors.wizards;
|
||||
package com.android.ide.eclipse.adt.wizards.newxmlfile;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
|
||||
@@ -31,6 +31,7 @@ import com.android.ide.eclipse.editors.resources.configurations.FolderConfigurat
|
||||
import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier;
|
||||
import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors;
|
||||
import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType;
|
||||
import com.android.ide.eclipse.editors.wizards.ConfigurationSelector;
|
||||
import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.ConfigurationState;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
|
||||
|
||||
package com.android.ide.eclipse.editors.wizards;
|
||||
package com.android.ide.eclipse.adt.wizards.newxmlfile;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileCreationPage.TypeInfo;
|
||||
import com.android.ide.eclipse.editors.IconFactory;
|
||||
import com.android.ide.eclipse.editors.wizards.NewXmlFileCreationPage.TypeInfo;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
@@ -128,7 +128,8 @@ public class AndroidConstants {
|
||||
public final static String WS_ASSETS = WS_SEP + SdkConstants.FD_ASSETS;
|
||||
|
||||
/** Leaf of the javaDoc folder. Does not start with a separator. */
|
||||
public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/reference"; //$NON-NLS-1$
|
||||
public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/" +
|
||||
SdkConstants.FD_DOCS_REFERENCE; //$NON-NLS-1$
|
||||
|
||||
/** Path of the samples directory relative to the sdk folder.
|
||||
* This is an OS path, ending with a separator.
|
||||
|
||||
@@ -153,7 +153,8 @@ final class AddOnTarget implements IAndroidTarget {
|
||||
case SKINS:
|
||||
return mLocation + SdkConstants.OS_SKINS_FOLDER;
|
||||
case DOCS:
|
||||
return mLocation + SdkConstants.FD_DOCS + File.separator;
|
||||
return mLocation + SdkConstants.FD_DOCS + File.separator
|
||||
+ SdkConstants.FD_DOCS_REFERENCE;
|
||||
default :
|
||||
return mBasePlatform.getPath(pathId);
|
||||
}
|
||||
|
||||
@@ -143,6 +143,8 @@ public final class SdkConstants {
|
||||
public final static String FD_LIB = "lib";
|
||||
/** Name of the SDK docs folder. */
|
||||
public final static String FD_DOCS = "docs";
|
||||
/** Name of the doc folder containing API reference doc (javadoc) */
|
||||
public static final String FD_DOCS_REFERENCE = "reference";
|
||||
/** Name of the SDK images folder. */
|
||||
public final static String FD_IMAGES = "images";
|
||||
/** Name of the SDK skins folder. */
|
||||
|
||||
@@ -89,9 +89,9 @@ public final class AvdSelector {
|
||||
final TableColumn column1 = new TableColumn(mTable, SWT.NONE);
|
||||
column1.setText("Target Name");
|
||||
final TableColumn column2 = new TableColumn(mTable, SWT.NONE);
|
||||
column2.setText("API Level");
|
||||
column2.setText("SDK");
|
||||
final TableColumn column3 = new TableColumn(mTable, SWT.NONE);
|
||||
column3.setText("SDK");
|
||||
column3.setText("API Level");
|
||||
|
||||
adjustColumnsWidth(mTable, column0, column1, column2, column3);
|
||||
setupSelectionListener(mTable);
|
||||
@@ -235,8 +235,8 @@ public final class AvdSelector {
|
||||
Rectangle r = table.getClientArea();
|
||||
column0.setWidth(r.width * 30 / 100); // 30%
|
||||
column1.setWidth(r.width * 45 / 100); // 45%
|
||||
column2.setWidth(r.width * 15 / 100); // 15%
|
||||
column3.setWidth(r.width * 10 / 100); // 10%
|
||||
column2.setWidth(r.width * 10 / 100); // 10%
|
||||
column3.setWidth(r.width * 15 / 100); // 15%
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user