ftp 文件夹
This commit is contained in:
@ -25,11 +25,6 @@ import com.arialyy.aria.orm.OneToOne;
|
||||
*/
|
||||
public class DownloadTaskEntity extends AbsTaskEntity<DownloadEntity> {
|
||||
|
||||
/**
|
||||
* 账号和密码
|
||||
*/
|
||||
@Ignore public String userName, userPw, account;
|
||||
|
||||
@OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity;
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.arialyy.aria.core.download;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
|
||||
@ -24,7 +25,8 @@ import com.arialyy.aria.orm.DbEntity;
|
||||
* ftp文件夹下载
|
||||
*/
|
||||
public class FtpDirDownloadTarget
|
||||
extends BaseGroupTarget<FtpDownloadTarget, DownloadGroupTaskEntity> {
|
||||
extends BaseGroupTarget<FtpDirDownloadTarget, DownloadGroupTaskEntity> {
|
||||
private final String TAG = "FtpDirDownloadTarget";
|
||||
private String serverIp, remotePath, mGroupName;
|
||||
private int port;
|
||||
|
||||
@ -58,4 +60,44 @@ public class FtpDirDownloadTarget
|
||||
}
|
||||
mEntity = mTaskEntity.entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置字符编码
|
||||
*/
|
||||
public FtpDirDownloadTarget charSet(String charSet) {
|
||||
if (TextUtils.isEmpty(charSet)) return this;
|
||||
mTaskEntity.charSet = charSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ftp 用户登录信息
|
||||
*
|
||||
* @param userName ftp用户名
|
||||
* @param password ftp用户密码
|
||||
*/
|
||||
public FtpDirDownloadTarget login(String userName, String password) {
|
||||
return login(userName, password, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* ftp 用户登录信息
|
||||
*
|
||||
* @param userName ftp用户名
|
||||
* @param password ftp用户密码
|
||||
* @param account ftp账号
|
||||
*/
|
||||
public FtpDirDownloadTarget login(String userName, String password, String account) {
|
||||
if (TextUtils.isEmpty(userName)) {
|
||||
Log.e(TAG, "用户名不能为null");
|
||||
return this;
|
||||
} else if (TextUtils.isEmpty(password)) {
|
||||
Log.e(TAG, "密码不能为null");
|
||||
return this;
|
||||
}
|
||||
mTaskEntity.userName = userName;
|
||||
mTaskEntity.userPw = password;
|
||||
mTaskEntity.account = account;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.download.downloader;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.inf.AbsEntity;
|
||||
import com.arialyy.aria.core.inf.AbsGroupEntity;
|
||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.IOException;
|
||||
import org.apache.commons.net.ftp.FTP;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
import org.apache.commons.net.ftp.FTPReply;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/7/25.
|
||||
* 获取ftp文件夹信息
|
||||
*/
|
||||
abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
|
||||
implements Runnable {
|
||||
|
||||
private final String TAG = "HttpFileInfoThread";
|
||||
private ENTITY mEntity;
|
||||
private TASK_ENTITY mTaskEntity;
|
||||
private int mConnectTimeOut;
|
||||
private OnFileInfoCallback mCallback;
|
||||
private boolean isDir = false;
|
||||
|
||||
AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
|
||||
mTaskEntity = taskEntity;
|
||||
mEntity = taskEntity.getEntity();
|
||||
mConnectTimeOut =
|
||||
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
|
||||
mCallback = callback;
|
||||
isDir = mEntity instanceof AbsGroupEntity;
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
FTPClient client = null;
|
||||
try {
|
||||
client = new FTPClient();
|
||||
String[] pp = mEntity.getKey().split("/")[2].split(":");
|
||||
String fileName = mTaskEntity.remotePath;
|
||||
client.connect(pp[0], Integer.parseInt(pp[1]));
|
||||
if (!TextUtils.isEmpty(mTaskEntity.account)) {
|
||||
client.login(mTaskEntity.userName, mTaskEntity.userPw);
|
||||
} else {
|
||||
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
|
||||
}
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
client.disconnect();
|
||||
failDownload("无法连接到ftp服务器,错误码为:" + reply);
|
||||
return;
|
||||
}
|
||||
client.setDataTimeout(mConnectTimeOut);
|
||||
client.enterLocalPassiveMode();
|
||||
client.setFileType(FTP.BINARY_FILE_TYPE);
|
||||
FTPFile[] files =
|
||||
client.listFiles(CommonUtil.strCharSetConvert(fileName, mTaskEntity.charSet));
|
||||
long size = getFileSize(files, client, fileName);
|
||||
mEntity.setFileSize(size);
|
||||
mTaskEntity.code = reply;
|
||||
mEntity.update();
|
||||
mTaskEntity.update();
|
||||
mCallback.onComplete(mEntity.getKey(), reply);
|
||||
} catch (IOException e) {
|
||||
failDownload(e.getMessage());
|
||||
} finally {
|
||||
if (client != null) {
|
||||
try {
|
||||
client.logout();
|
||||
client.disconnect();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历FTP服务器上对应文件或文件夹大小
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
|
||||
long size = 0;
|
||||
String path = dirName + "/";
|
||||
for (FTPFile file : files) {
|
||||
if (file.isFile()) {
|
||||
size += file.getSize();
|
||||
} else {
|
||||
size += getFileSize(client.listFiles(
|
||||
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
|
||||
path + file.getName());
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理FTP文件信息
|
||||
*
|
||||
* @param remotePath ftp服务器文件夹路径
|
||||
* @param ftpFile ftp服务器上对应的文件
|
||||
*/
|
||||
void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
}
|
||||
|
||||
private void failDownload(String errorMsg) {
|
||||
Log.e(TAG, errorMsg);
|
||||
if (mCallback != null) {
|
||||
mCallback.onFail(mEntity.getKey(), errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.aria.core.download.downloader;
|
||||
|
||||
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/7/25.
|
||||
* 获取ftp文件夹信息
|
||||
*/
|
||||
class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGroupTaskEntity> {
|
||||
|
||||
FtpDirInfoThread(DownloadGroupTaskEntity taskEntity, OnFileInfoCallback callback) {
|
||||
super(taskEntity, callback);
|
||||
}
|
||||
|
||||
@Override void handleFile(String remotePath, FTPFile ftpFile) {
|
||||
super.handleFile(remotePath, ftpFile);
|
||||
}
|
||||
}
|
@ -15,105 +15,16 @@
|
||||
*/
|
||||
package com.arialyy.aria.core.download.downloader;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.AriaManager;
|
||||
import com.arialyy.aria.core.download.DownloadEntity;
|
||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.IOException;
|
||||
import org.apache.commons.net.ftp.FTP;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
import org.apache.commons.net.ftp.FTPReply;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/7/25.
|
||||
* 获取ftp文件信息
|
||||
*/
|
||||
class FtpFileInfoThread implements Runnable {
|
||||
|
||||
private final String TAG = "HttpFileInfoThread";
|
||||
private DownloadEntity mEntity;
|
||||
private DownloadTaskEntity mTaskEntity;
|
||||
private int mConnectTimeOut;
|
||||
private OnFileInfoCallback mCallback;
|
||||
class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEntity> {
|
||||
|
||||
FtpFileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
|
||||
this.mTaskEntity = taskEntity;
|
||||
mEntity = taskEntity.getEntity();
|
||||
mConnectTimeOut =
|
||||
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
FTPClient client = null;
|
||||
try {
|
||||
client = new FTPClient();
|
||||
String[] pp = mEntity.getDownloadUrl().split("/")[2].split(":");
|
||||
String fileName = mTaskEntity.remotePath;
|
||||
client.connect(pp[0], Integer.parseInt(pp[1]));
|
||||
if (!TextUtils.isEmpty(mTaskEntity.account)) {
|
||||
client.login(mTaskEntity.userName, mTaskEntity.userPw);
|
||||
} else {
|
||||
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
|
||||
}
|
||||
int reply = client.getReplyCode();
|
||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||
client.disconnect();
|
||||
failDownload("无法连接到ftp服务器,错误码为:" + reply);
|
||||
return;
|
||||
}
|
||||
client.setDataTimeout(mConnectTimeOut);
|
||||
client.enterLocalPassiveMode();
|
||||
client.setFileType(FTP.BINARY_FILE_TYPE);
|
||||
FTPFile[] files =
|
||||
client.listFiles(CommonUtil.strCharSetConvert(fileName, mTaskEntity.charSet));
|
||||
long size = getFileSize(files, client, fileName);
|
||||
mEntity.setFileSize(size);
|
||||
mTaskEntity.code = reply;
|
||||
mEntity.update();
|
||||
mTaskEntity.update();
|
||||
mCallback.onComplete(mEntity.getDownloadUrl(), reply);
|
||||
} catch (IOException e) {
|
||||
failDownload(e.getMessage());
|
||||
} finally {
|
||||
if (client != null) {
|
||||
try {
|
||||
client.logout();
|
||||
client.disconnect();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历FTP服务器上对应文件或文件夹大小
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
|
||||
long size = 0;
|
||||
String path = dirName + "/";
|
||||
for (FTPFile file : files) {
|
||||
if (file.isFile()) {
|
||||
size += file.getSize();
|
||||
} else {
|
||||
size += getFileSize(client.listFiles(
|
||||
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
|
||||
path + file.getName());
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
private void failDownload(String errorMsg) {
|
||||
Log.e(TAG, errorMsg);
|
||||
if (mCallback != null) {
|
||||
mCallback.onFail(mEntity.getDownloadUrl(), errorMsg);
|
||||
}
|
||||
super(taskEntity, callback);
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,11 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
|
||||
*/
|
||||
public String remotePath;
|
||||
|
||||
/**
|
||||
* 账号和密码
|
||||
*/
|
||||
@Ignore public String userName, userPw, account;
|
||||
|
||||
/**
|
||||
* 请求类型
|
||||
* {@link AbsTaskEntity#HTTP}、{@link AbsTaskEntity#FTP}
|
||||
|
@ -33,6 +33,7 @@
|
||||
<activity android:name=".test.TestMutilTaskSysDownload"/>
|
||||
<activity android:name=".download.group.DownloadGroupActivity"/>
|
||||
<activity android:name=".download.FtpDownloadActivity"/>
|
||||
<activity android:name=".download.group.FTPDirDownloadActivity"/>
|
||||
|
||||
<service android:name=".download.service_download.DownloadService"/>
|
||||
</application>
|
||||
|
@ -25,6 +25,7 @@ import com.arialyy.simple.databinding.ActivityMainBinding;
|
||||
import com.arialyy.simple.download.DownloadActivity;
|
||||
import com.arialyy.simple.download.FtpDownloadActivity;
|
||||
import com.arialyy.simple.download.group.DownloadGroupActivity;
|
||||
import com.arialyy.simple.download.group.FTPDirDownloadActivity;
|
||||
import com.arialyy.simple.test.TestMutilTaskSysDownload;
|
||||
import com.arialyy.simple.upload.UploadActivity;
|
||||
|
||||
@ -44,8 +45,7 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
|
||||
return R.layout.activity_main;
|
||||
}
|
||||
|
||||
|
||||
@OnClick({R.id.download, R.id.upload, R.id.download_task_group, R.id.ftp})
|
||||
@OnClick({ R.id.download, R.id.upload, R.id.download_task_group, R.id.ftp, R.id.ftp_dir })
|
||||
public void funcation(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.download:
|
||||
@ -60,7 +60,9 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
|
||||
case R.id.ftp:
|
||||
startActivity(new Intent(this, FtpDownloadActivity.class));
|
||||
break;
|
||||
}
|
||||
|
||||
case R.id.ftp_dir:
|
||||
startActivity(new Intent(this, FTPDirDownloadActivity.class));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.arialyy.simple.download.group;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.view.View;
|
||||
import butterknife.Bind;
|
||||
import com.arialyy.annotations.DownloadGroup;
|
||||
import com.arialyy.aria.core.Aria;
|
||||
import com.arialyy.aria.core.download.DownloadGroupTask;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
import com.arialyy.frame.util.show.T;
|
||||
import com.arialyy.simple.R;
|
||||
import com.arialyy.simple.base.BaseActivity;
|
||||
import com.arialyy.simple.databinding.ActivityDownloadGroupBinding;
|
||||
import com.arialyy.simple.widget.SubStateLinearLayout;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/7/6.
|
||||
*/
|
||||
public class FTPDirDownloadActivity extends BaseActivity<ActivityDownloadGroupBinding> {
|
||||
private static final String dir = "ftp://172.18.104.129:21/haha/";
|
||||
|
||||
@Bind(R.id.child_list) SubStateLinearLayout mChildList;
|
||||
|
||||
@Override protected void init(Bundle savedInstanceState) {
|
||||
super.init(savedInstanceState);
|
||||
Aria.download(this).register();
|
||||
setTitle("FTP文件夹下载");
|
||||
//mUrls = getModule(GroupModule.class).getUrls();
|
||||
//DownloadGroupTaskEntity entity = Aria.download(this).getDownloadGroupTask(mUrls);
|
||||
//if (entity != null && entity.getEntity() != null) {
|
||||
// DownloadGroupEntity groupEntity = entity.getEntity();
|
||||
// mChildList.addData(groupEntity.getSubTask());
|
||||
// getBinding().setFileSize(groupEntity.getConvertFileSize());
|
||||
// if (groupEntity.getFileSize() == 0) {
|
||||
// getBinding().setProgress(0);
|
||||
// } else {
|
||||
// getBinding().setProgress(groupEntity.isComplete() ? 100
|
||||
// : (int) (groupEntity.getCurrentProgress() * 100 / groupEntity.getFileSize()));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
@Override protected int setLayoutId() {
|
||||
return R.layout.activity_download_group;
|
||||
}
|
||||
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.start:
|
||||
Aria.download(this)
|
||||
.loadFtpDir(dir)
|
||||
.setDownloadDirPath(
|
||||
Environment.getExternalStorageDirectory().getPath() + "/Download/ftp_dir")
|
||||
.setGroupAlias("ftp文件夹下载")
|
||||
//.setSubTaskFileName(getModule(GroupModule.class).getSubName())
|
||||
.login("lao", "123456")
|
||||
.start();
|
||||
break;
|
||||
case R.id.stop:
|
||||
Aria.download(this).loadFtpDir(dir).stop();
|
||||
break;
|
||||
case R.id.cancel:
|
||||
Aria.download(this).loadFtpDir(dir).cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@DownloadGroup.onPre() protected void onPre(DownloadGroupTask task) {
|
||||
L.d(TAG, "group pre");
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskPre() protected void onTaskPre(DownloadGroupTask task) {
|
||||
if (mChildList.getSubData().size() <= 0) {
|
||||
mChildList.addData(task.getEntity().getSubTask());
|
||||
}
|
||||
L.d(TAG, "group task pre");
|
||||
getBinding().setFileSize(task.getConvertFileSize());
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskStart() void taskStart(DownloadGroupTask task) {
|
||||
L.d(TAG, "group task start");
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskRunning() protected void running(DownloadGroupTask task) {
|
||||
getBinding().setProgress(task.getPercent());
|
||||
getBinding().setSpeed(task.getConvertSpeed());
|
||||
mChildList.updateChildProgress(task.getEntity().getSubTask());
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskResume() void taskResume(DownloadGroupTask task) {
|
||||
L.d(TAG, "group task resume");
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskStop() void taskStop(DownloadGroupTask task) {
|
||||
L.d(TAG, "group task stop");
|
||||
getBinding().setSpeed("");
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskCancel() void taskCancel(DownloadGroupTask task) {
|
||||
getBinding().setSpeed("");
|
||||
getBinding().setProgress(0);
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskFail() void taskFail(DownloadGroupTask task) {
|
||||
L.d(TAG, "group task fail");
|
||||
}
|
||||
|
||||
@DownloadGroup.onTaskComplete() void taskComplete(DownloadGroupTask task) {
|
||||
getBinding().setProgress(100);
|
||||
mChildList.updateChildProgress(task.getEntity().getSubTask());
|
||||
T.showShort(this, "任务组下载完成");
|
||||
L.d(TAG, "任务组下载完成");
|
||||
}
|
||||
}
|
@ -41,5 +41,13 @@
|
||||
style="?buttonBarButtonStyle"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/ftp_dir"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="FTP 文件夹下载"
|
||||
style="?buttonBarButtonStyle"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
|
Reference in New Issue
Block a user