实现热点列表

main
Matthew 12 months ago
parent 68e81438dd
commit dcb0a180b2

@ -9,8 +9,8 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowBackup="true"
@ -24,12 +24,18 @@
android:theme="@style/Theme.MpRemote"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_settings"
android:exported="false" />
<activity
android:name=".DeviceActivity"
android:label="@string/title_activity_device"
android:exported="false" />
<activity
android:name=".VideoActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_video"
android:exported="false" />
<activity
android:name=".WifiScanActivity"
@ -47,8 +53,7 @@
android:name=".ImageActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="false"
android:label="@string/title_activity_image"
/>
android:label="@string/title_activity_image" />
</application>
</manifest>

@ -5,6 +5,7 @@ import androidx.appcompat.app.AppCompatActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.wifi.WifiManager;
@ -82,6 +83,7 @@ public class DeviceActivity extends AppCompatActivity {
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
// actionBar.setTitle(R.string.title_activity_device);
Intent intent = getIntent();
mDeviceIp = intent.getStringExtra("deviceIp");
@ -117,8 +119,13 @@ public class DeviceActivity extends AppCompatActivity {
ex.printStackTrace();
}
mHandler.post(new Runnable() {
@Override
public void run() {
mProgressDialog.dismiss();
}
});
}
private void runImpl() {
Dadb adb = Dadb.discover(mDeviceIp, mAdbKeyPair);
@ -167,6 +174,7 @@ public class DeviceActivity extends AppCompatActivity {
if (pos != -1) {
String val = line.substring(pos + 12);
mProps.put(KEY_APP_MP_VERSION, val);
break;
}
}
}
@ -256,9 +264,14 @@ public class DeviceActivity extends AppCompatActivity {
}
});
mProgressDialog = ProgressDialog.show(context, "", "连接中", true);
mProgressDialog = ProgressDialog.show(this, "", "连接中", true, true);
mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
DeviceActivity.this.finish();
}
});
}
protected boolean pullFile(Dadb adb, String remoteFilePath, File localFilePath) {
if (localFilePath.exists()) {
@ -427,8 +440,9 @@ public class DeviceActivity extends AppCompatActivity {
}
private void showPhoto(final String filePath) {
Intent intent = new Intent(DeviceActivity.this, ImageActivity.class);
Intent intent = new Intent(this, ImageActivity.class);
intent.putExtra("path", filePath);
intent.putExtra("cmdid", TextUtils.isEmpty(mAppConfig.cmdid) ? "" : mAppConfig.cmdid);
// intent.putExtra("info", info);
startActivity(intent);
}

@ -1,37 +1,54 @@
package com.xypower.mpremote;
import androidx.appcompat.app.ActionBar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkSpecifier;
import android.net.wifi.WifiNetworkSuggestion;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.os.Parcelable;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import com.xypower.common.FileUtils;
import com.xypower.common.MicroPhotoContext;
import com.xypower.mpremote.databinding.ActivityMainBinding;
import java.io.File;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import dadb.AdbKeyPair;
import dadb.AdbShellResponse;
import dadb.Dadb;
public class MainActivity extends AppCompatActivity {
// Used to load the 'mpremote' library on application startup.
@ -41,473 +58,505 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = "ADB";
private static final boolean DEBUG = false;
private static final String PACKAGE_NAME_MP = "com.xypower.mpapp";
private static final String REMOTE_PATH_ROOT = "/sdcard/" + PACKAGE_NAME_MP + "/";
private static final String REMOTE_PATH_DATA = REMOTE_PATH_ROOT + "data/";
private static final String REMOTE_PATH_PHOTOS = REMOTE_PATH_ROOT + "photos/";
private static final String REMOTE_PATH_TMP = REMOTE_PATH_ROOT + "tmp/";
private static final boolean DEBUG = true;
private static final String KEY_APP_BV = "app.bv";
private static final String KEY_APP_BCV = "app.bcv";
private static final String KEY_RO_SERIALNO = "ro.serialno";
public static final int RSSI_LEVELS = 5;
private static final String KEY_APP_MP_VERSION = "mpapp.version";
private static final String DEFAULT_PRE_SHARED_KEY = SettingsActivity.DEFAULT_PRE_SHARED_KEY;
private static final int ADB_SERVER_PORT = 5555;
private static final int REQUEST_CODE_PERMISSIONS = 1025;
private static final int REQUEST_CODE_SETTINGS = SettingsActivity.REQUEST_CODE_SETTINGS;
private static final String WIFI_IP_PREFIX = "192.168.";
// private static final String WIFI_IP_DEVIDE = "192.168.50.1";
private static final String WIFI_IP_DEVICE = "192.168.50.137";
// [vendor.ril.nw.signalstrength.lte.1]: [-85,27]
//[vendor.ril.nw.signalstrength.lte.2]: [-86,27]
private static final String WIFI_IP_DEVICE = "192.168.50.92";
private ActivityMainBinding binding;
private Handler mHandler;
private Dadb mAdb;
private Map<String, String> mProps = new HashMap<>();
private MicroPhotoContext.AppConfig mAppConfig;
private int mBatteryVoltage = -1;
private int mBatteryChargingVoltage = -1;
private List<ScanResult> mScanResults = null;
private ScanResult mCurrentScanResult;
private String mPassword = DEFAULT_PRE_SHARED_KEY;
private WifiAdaper mAdapter;
private List<Map<String, Object>> mItems = new ArrayList<Map<String, Object>>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
private ConnectivityManager mConnectivityManager;
private NetworkConnectChangedReceiver mNetworkConnectChangedReceiver;
private ConnectivityManager.NetworkCallback mNetworkCallback;
mHandler = new Handler();
public class WifiAdaper extends SimpleAdapter{
public WifiAdaper(Context context, List<Map<String, Object>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
File file = new File(getFilesDir(), ".keypair");
if (!file.exists()) {
file.mkdirs();
}
public View getView(int position, View convertView, ViewGroup parent){
convertView = super.getView(position, convertView, parent);
final File pubKeyFile = new File(file, "pub.key");
final File priKeyFile = new File(file, "pri.key");
if (!priKeyFile.exists() || !pubKeyFile.exists()) {
AdbKeyPair.generate(priKeyFile, pubKeyFile);
}
TextView textView = (TextView)convertView.findViewById(R.id.id_text);
final File fileTmp = new File(getFilesDir(), "tmp");
if (!fileTmp.exists()) {
fileTmp.mkdirs();
ScanResult scanResult = mScanResults.get(position);
// if (scanResult.)
String text = (String)mItems.get(position).get("text");
if (text.startsWith("XY") || text.startsWith("xy")) {
textView.setTextColor(Color.RED);
textView.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
} else {
textView.setTextColor(Color.BLACK);
textView.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL));
}
final AdbKeyPair adbKeyPair = AdbKeyPair.read(priKeyFile, pubKeyFile);
final Context context = getApplicationContext();
return convertView;
}
}
(new Thread(new Runnable() {
@Override
public void run() {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
String ipAddressByWifi = null;
if (wifiManager != null) {
ipAddressByWifi = Formatter.formatIpAddress(wifiManager.getDhcpInfo().ipAddress);
}
loadSettings();
mHandler = new Handler();
if (ipAddressByWifi.contains(WIFI_IP_PREFIX)) {
mConnectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
binding.listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
String deviceIP = Formatter.formatIpAddress(wifiManager.getDhcpInfo().gateway);
if (DEBUG) {
deviceIP = WIFI_IP_DEVICE;
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
Socket mSocket = null;
try {
mSocket = new Socket(deviceIP, ADB_SERVER_PORT);
if (mSocket.isConnected()) {
mSocket.close();
mCurrentScanResult = mScanResults.get(position);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String s1 = normalizeSSID(mCurrentScanResult.SSID);
String s2 = normalizeSSID(wifiInfo.getSSID());
if (TextUtils.equals(s1, s2)) {
openDeviceActivity();
} else {
startActivity(new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS));
}
} catch (Exception ex) {
ex.printStackTrace();
// connectWifi(mCurrentScanResult.SSID, mCurrentScanResult.BSSID, mPassword);
}
});
Dadb adb = Dadb.discover(deviceIP, adbKeyPair);
if (adb != null) {
mAdb = adb;
AdbShellResponse adbShellResponse = null;
try {
adbShellResponse = mAdb.shell("getprop");
} catch (Exception ex) {
ex.printStackTrace();
if (applyForPermissions()) {
scanWifi();
}
if (adbShellResponse.getExitCode() == 0) {
String[] lines = FileUtils.splitLines(adbShellResponse.getAllOutput());
for (String line : lines) {
int pos = line.indexOf("]: [");
if (pos != -1) {
String key = line.substring(1, pos);
String val = line.substring(pos + 4, line.length() - 1);
mProps.put(key, val);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mConnectivityManager != null && mNetworkCallback != null) {
mConnectivityManager.bindProcessToNetwork(null);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
}
// adb shell pm dump com.xypower.mpremote | grep "versionName"
adbShellResponse = null;
try {
adbShellResponse = mAdb.shell("pm dump " + PACKAGE_NAME_MP + " | grep \"versionName\"");
} catch (Exception ex) {
ex.printStackTrace();
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_activity_actions, menu);
return true;
}
if (adbShellResponse.getExitCode() == 0) {
String[] lines = FileUtils.splitLines(adbShellResponse.getAllOutput());
for (String line : lines) {
int pos = line.indexOf("versionName=");
if (pos != -1) {
String val = line.substring(pos + 12);
mProps.put(KEY_APP_MP_VERSION, val);
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//当点击不同的menu item 是执行不同的操作
switch (id) {
case R.id.action_refresh:
scanWifi();
break;
case R.id.action_settings: {
Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);
startActivityForResult(intent, REQUEST_CODE_SETTINGS);
}
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
String remoteFilePath = REMOTE_PATH_TMP + "bv.txt";
String cmd = "am start -n " + PACKAGE_NAME_MP + "/" + PACKAGE_NAME_MP + ".BridgeActivity --es action \"query_bv\" --es path \"" + remoteFilePath + "\"";
adbShellResponse = null;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
try {
adbShellResponse = mAdb.shell(cmd);
} catch (Exception ex) {
ex.printStackTrace();
ArrayList<String> requestList = new ArrayList<>();//允许询问列表
ArrayList<String> banList = new ArrayList<>();//禁止列表
for(int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.i(TAG,"【"+permissions[i]+"】权限授权成功");
} else {
//判断是否允许重新申请该权限
boolean nRet = ActivityCompat.shouldShowRequestPermissionRationale(this,permissions[i]);
Log.i(TAG,"shouldShowRequestPermissionRationale nRet="+nRet);
if (nRet) {//允许重新申请
requestList.add(permissions[i]);
} else {//禁止申请
banList.add(permissions[i]);
}
}
if (adbShellResponse.getExitCode() == 0) {
File localFilePath = new File(fileTmp, "bv.txt");
if (localFilePath.exists()) {
localFilePath.delete();
}
for (int idx = 0; idx < 10; idx++) {
boolean res = pullFile(mAdb, remoteFilePath, localFilePath);
if (res) {
String content = FileUtils.readTextFile(localFilePath.getAbsolutePath());
if (!TextUtils.isEmpty(content)) {
int pos = content.indexOf(" ");
if (pos != -1) {
String bv = content.substring(0, pos);
String bcv = content.substring(pos + 1);
if (!TextUtils.isEmpty(bv)) {
mBatteryVoltage = Integer.parseInt(bv);
//优先对禁止列表进行判断
if (banList.size() > 0) {
//告知该权限作用,要求手动授予权限
showFinishedDialog();
}
if (!TextUtils.isEmpty(bcv)) {
mBatteryChargingVoltage = Integer.parseInt(bcv);
else if (requestList.size() > 0) {
//告知权限的作用,并重新申请
showTipDialog(requestList);
} else {
// showToast("权限授权成功");
scanWifi();
}
} catch (Exception e) {
e.printStackTrace();
// showToast("权限申请回调中发生异常");
}
}
localFilePath.delete();
break;
public void showFinishedDialog() {
AlertDialog dialog = new AlertDialog.Builder(getApplicationContext())
.setTitle("警告")
.setMessage("请前往设置中打开相关权限,否则功能无法正常运行!")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 一般情况下如果用户不授权的话,功能是无法运行的,做退出处理
finish();
}
})
.create();
dialog.show();
}
try {
Thread.sleep(1000);
} catch (Exception ex) {
ex.printStackTrace();
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SETTINGS) {
loadSettings();
}
}
try {
mAdb.shell("rm " + remoteFilePath);
} catch (Exception ex) {
ex.printStackTrace();
public void showTipDialog(ArrayList<String> pmList){
AlertDialog dialog = new AlertDialog.Builder(getApplicationContext())
.setTitle("提示")
.setMessage("【"+pmList.toString()+"】权限为应用必要权限,请授权")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String[] sList=pmList.toArray(new String[0]);
//重新申请该权限
ActivityCompat.requestPermissions(MainActivity.this, sList, REQUEST_CODE_PERMISSIONS);
}
})
.create();
dialog.show();
}
File appConfigFile = new File(fileTmp, "App.json");
boolean res = pullFile(adb, REMOTE_PATH_DATA + "App.json", appConfigFile);
if (res) {
final MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(context, appConfigFile.getAbsolutePath());
mAppConfig = appConfig;
protected void scanWifi() {
MainActivity.this.mHandler.post(new Runnable() {
mScanResults = null;
(new Thread(new Runnable() {
@Override
public void run() {
MainActivity.this.showAppInfo();
}
});
}
} else {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
wifiManager.startScan();
mScanResults = wifiManager.getScanResults();
// mAdapter = new ArrayAdapter<>()
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, R.string.err_dev_not_found, Toast.LENGTH_LONG).show();
refreshListView();
}
});
}
}
// Dadb dadb = Dadb.create("localhost", 5555, adbKeyPair);
// Dadb.discover();
}
})).start();
binding.takePhoto1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
takePhoto(1, 255, true);
}
});
binding.takeVideo1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
takeVideo(1, 255, false);
}
});
private void connectWifi(String ssid, String bssid, String pwd) {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
}
// Android 10
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
WifiNetworkSuggestion suggestion =
new WifiNetworkSuggestion.Builder()
.setSsid(ssid)
.setWpa2Passphrase((pwd))
.setIsAppInteractionRequired(true)
.build();
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_activity_actions, menu);
return true;
}
List<WifiNetworkSuggestion> suggestionsList = new ArrayList<>();
suggestionsList.add(suggestion);
wifiManager.removeNetworkSuggestions(suggestionsList);
protected boolean pullFile(Dadb adb, String remoteFilePath, File localFilePath) {
if (localFilePath.exists()) {
localFilePath.delete();
}
int status = wifiManager.addNetworkSuggestions(suggestionsList);
// step2
if ((status == WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) || (status == WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE)) {
WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier.Builder()
.setSsid(ssid)
.setWpa2Passphrase(pwd)
.build();
Log.i(TAG, "PULL: " + remoteFilePath);
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setNetworkSpecifier(wifiNetworkSpecifier)
.build();
boolean res = false;
try {
adb.pull(localFilePath, remoteFilePath);
res = true;
} catch (Exception ex) {
ex.printStackTrace();
}
return res && localFilePath.exists();
}
mNetworkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull Network network) {
super.onAvailable(network);
NetworkInfo networkInfo = mConnectivityManager.getNetworkInfo(network);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String s1 = normalizeSSID(wifiInfo.getSSID());
String s2 = normalizeSSID(mCurrentScanResult.SSID);
if (TextUtils.equals(s1, s2)) {
protected void takePhotoImpl(final String cmd, final int channel, final int preset, final String localFileName, final String remoteFilePath, final boolean photoOrVideo, long sleepTime) {
Thread th = new Thread(new Runnable() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (Exception ex) {
// requires android.permission.INTERNET
mConnectivityManager.bindProcessToNetwork(network);
openDeviceActivity();
}
});
}
AdbShellResponse adbShellResponse = null;
try {
adbShellResponse = mAdb.shell(cmd);
} catch (Exception ex) {
ex.printStackTrace();
}
if (adbShellResponse != null) {
if (adbShellResponse.getExitCode() == 0) {
File localFilePath = new File(getFilesDir(), localFileName);
for (int idx = 0; idx < 10; idx++) {
boolean res = pullFile(mAdb, remoteFilePath, localFilePath);
if (res) {
@Override
public void onUnavailable() {
super.onUnavailable();
mHandler.post(new Runnable() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (photoOrVideo) {
showPhoto(localFilePath.getAbsolutePath());
} else {
showVideo(localFilePath.getAbsolutePath());
}
mConnectivityManager.bindProcessToNetwork(null);
}
});
break;
}
};
try {
Thread.sleep(1000);
} catch (Exception ex) {
ex.printStackTrace();
}
mConnectivityManager.requestNetwork(request, mNetworkCallback);
} else {
}
} else {
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = "\"" + ssid + "\"";
wifiConfiguration.BSSID = "\"" + bssid + "\"";
wifiConfiguration.preSharedKey = "\"" + pwd + "\"";
int nerworkId = wifiManager.addNetwork(wifiConfiguration);
try {
// mAdb.shell("rm " + remoteFilePath);
wifiManager.disconnect();
} catch (Exception ex) {
ex.printStackTrace();
}
/*
if (mNetworkConnectChangedReceiver != null) {
unregisterReceiver(mNetworkConnectChangedReceiver);
mNetworkConnectChangedReceiver = null;
registerNetworkConnectChangeReceiver();
}
*/
wifiManager.enableNetwork(nerworkId, true);
wifiManager.reconnect();
}
}
});
th.start();
}
private void refreshListView() {
mAdapter = new WifiAdaper(this, getData(), R.layout.list_item, new String[] { "img", "text" },
new int[] { R.id.id_img, R.id.id_text });
protected long takePhoto(int channel, int preset, final boolean photoOrVideo) {
if (mAdb == null) {
return 0;
}
binding.listView.setAdapter(mAdapter);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
Date dt = new Date();
int cameraId = channel - 1;
}
final String fileName = "IMG-" + Integer.toString(channel) + "-" + simpleDateFormat.format(dt) + (photoOrVideo ? ".jpg" : ".mp4");
final String remoteFilePath = REMOTE_PATH_TMP + fileName;
private List<Map<String, Object>> getData() {
mItems.clear();
for (ScanResult scanResult : mScanResults) {
Map map = new HashMap<String, Object>();
String leftTopOsd = "";
if (mAppConfig != null) {
leftTopOsd += mAppConfig.cmdid + " ";
int signalLevel = WifiManager.calculateSignalLevel(scanResult.level, RSSI_LEVELS);
int drawableId = R.drawable.ic_wifi_signal_0;
switch (signalLevel) {
case 1:
drawableId = R.drawable.ic_wifi_signal_1;
break;
case 2:
drawableId = R.drawable.ic_wifi_signal_2;
break;
case 3:
drawableId = R.drawable.ic_wifi_signal_3;
break;
case 4:
drawableId = R.drawable.ic_wifi_signal_4;
break;
default:
drawableId = R.drawable.ic_wifi_signal_0;
break;
}
map.put("img", drawableId);
map.put("text", scanResult.SSID);
mItems.add(map);
}
return mItems;
}
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
leftTopOsd += simpleDateFormat2.format(dt) + " ";
leftTopOsd += "CH:" + Integer.toString(channel) + " ";
String usb = (channel == 4) ? "true" : "false";
final String cmd = "am start -n " + PACKAGE_NAME_MP + "/" + PACKAGE_NAME_MP + ".BridgeActivity --es action \"take_photo\" --es path \""
+ remoteFilePath + "\" --ez usb " + usb + " --ei cameraId " + Integer.toString(cameraId) + " --ei channel "
+ Integer.toString(channel) + " --ei preset " + Integer.toString(preset) + " --es leftTopOsd \"" + leftTopOsd + "\"";
// adbShellResponse = null;
class NetworkConnectChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Bundle extras = intent.getExtras();
takePhotoImpl(cmd, channel, preset, fileName, remoteFilePath, photoOrVideo, 0);
// 这个监听wifi的连接状态即是否连上了一个有效无线路由当上边广播的状态是WifiManager.WIFI_STATE_DISABLING和WIFI_STATE_DISABLED的时候根本不会接到这个广播。
// 在上边广播接到广播是WifiManager.WIFI_STATE_ENABLED状态的同时也会接到这个广播当然刚打开wifi肯定还没有连接到有效的无线
if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
Parcelable parcelableExtra = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
String bssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
return 0;
if (null == parcelableExtra) {
return;
}
protected long takeVideo(int channel, int preset, final boolean photoOrVideo) {
if (mAdb == null) {
return 0;
if (mCurrentScanResult != null) {
return;
}
NetworkInfo networkInfo = (NetworkInfo) parcelableExtra;
NetworkInfo.State state = networkInfo.getState();
// Log.e("NetWork Sate Change:"+state+" connectedBssid:" + connectedBssid);
if(state == NetworkInfo.State.CONNECTED) {
String ssid = wifiInfo.getSSID();
String addSSID = mCurrentScanResult.SSID;
if (!(mCurrentScanResult.SSID.startsWith("\"") && mCurrentScanResult.SSID.endsWith("\""))) {
addSSID = "\"" + addSSID + "\"";
}
// Log.i(ssid + "***>" + mCurrentScanResult.SSID);
// Log.i("总共耗时:"+((System.currentTimeMillis()-start)/1000.0));
if (ssid.equals(addSSID)) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
Date dt = new Date();
int cameraId = channel - 1;
int duration = 5;
unregisterReceiver(mNetworkConnectChangedReceiver);
mNetworkConnectChangedReceiver = null;
String leftTopOsd = "";
if (mAppConfig != null) {
leftTopOsd += mAppConfig.cmdid + " ";
}
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
leftTopOsd += simpleDateFormat2.format(dt) + " ";
leftTopOsd += "CH:" + Integer.toString(channel) + " ";
final String fileName = "IMG-" + Integer.toString(channel) + "-" + simpleDateFormat.format(dt) + (photoOrVideo ? ".jpg" : ".mp4");
final String remoteFilePath = REMOTE_PATH_TMP + fileName;
}
}
// int quality = intent.getIntExtra("quality", 0);
// int width = intent.getIntExtra("width", 1280);
// int height = intent.getIntExtra("height", 720);
// int duration = intent.getIntExtra("duration", 15);
// int orientation = intent.getIntExtra("orientation", 0);
// long videoId = System.currentTimeMillis() / 1000;
//
// String leftTopOsd = intent.getStringExtra("leftTopOsd");
// String rightTopOsd = intent.getStringExtra("rightTopOsd");
// String rightBottomOsd = intent.getStringExtra("rightBottomOsd");
// String leftBottomOsd = intent.getStringExtra("leftBottomOsd");
}
}
}
String usb = (channel == 4) ? "true" : "false";
final String cmd = "am start -n " + PACKAGE_NAME_MP + "/" + PACKAGE_NAME_MP + ".BridgeActivity --es action \"recording\" --es path \""
+ remoteFilePath + "\" --ez usb " + usb + " --ei cameraId " + Integer.toString(cameraId) + " --ei channel "
+ Integer.toString(channel) + " --ei preset " + Integer.toString(preset) + " --ei duration " + Integer.toString(duration)
+ " --el videoId " + Long.toString(dt.getTime() / 1000) + " --es leftTopOsd \"" + leftTopOsd + "\"";
// adbShellResponse = null;
private void registerNetworkConnectChangeReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mNetworkConnectChangedReceiver = new NetworkConnectChangedReceiver();
registerReceiver(mNetworkConnectChangedReceiver, filter);
}
Log.d(TAG, cmd);
public boolean applyForPermissions() {
takePhotoImpl(cmd, channel, preset, fileName, remoteFilePath, photoOrVideo, duration * 1000);
String[] PM_MULTIPLE = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CHANGE_NETWORK_STATE,
Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.ACCESS_FINE_LOCATION
};
return 0;
try {
ArrayList<String> pmList = new ArrayList<>();
//获取当前未授权的权限列表
for(String permission:PM_MULTIPLE) {
int nRet = ContextCompat.checkSelfPermission(this,permission);
if(nRet != PackageManager.PERMISSION_GRANTED) {
pmList.add(permission);
}
private void showPhoto(final String filePath) {
Intent intent = new Intent(MainActivity.this, ImageActivity.class);
intent.putExtra("path", filePath);
// intent.putExtra("info", info);
startActivity(intent);
}
private void showVideo(final String filePath) {
Intent intent = new Intent(MainActivity.this, VideoActivity.class);
intent.putExtra("path", filePath);
// intent.putExtra("info", info);
startActivity(intent);
if (pmList.size() > 0) {
// Log.i(TAG,"进行权限申请...");
String[] sList = pmList.toArray(new String[0]);
ActivityCompat.requestPermissions(this, sList,REQUEST_CODE_PERMISSIONS);
return false;
}
} catch(Exception e){
e.printStackTrace();
}
private void showAppInfo() {
ActionBar actionBar = getSupportActionBar();
// 视频浏览,拍照,设备信息及状态查询(编号版本双SIM卡状态电池及太阳能电压等),可以参考东视
Resources resources = getResources();
// String buildTime = BuildConfig.BUILD_
// Date date = new Date(BuildConfig.BUILD_TIMESTAMP);
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String title = resources.getString(R.string.app_name);
if (!TextUtils.isEmpty(mAppConfig.cmdid)) {
title += " - " + mAppConfig.cmdid;
return true;
}
actionBar.setTitle(title);
StringBuilder stringBuilder = new StringBuilder();
protected void loadSettings() {
SharedPreferences preferences = getSharedPreferences("mpremote", MODE_PRIVATE);
if (mProps.containsKey(KEY_RO_SERIALNO)) {
String val = (String)mProps.get(KEY_RO_SERIALNO);
appendKeyValue(stringBuilder, "序列号", val);
mPassword = preferences.getString("password", DEFAULT_PRE_SHARED_KEY);
}
appendKeyValue(stringBuilder, "CMDID", mAppConfig.cmdid);
protected void openDeviceActivity() {
String ipAddressByWifi = null;
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
ipAddressByWifi = Formatter.formatIpAddress(wifiManager.getDhcpInfo().ipAddress);
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
appendKeyValue(stringBuilder, "主站", mAppConfig.server + ":" + Integer.toString(mAppConfig.port));
if (ipAddressByWifi.contains(WIFI_IP_PREFIX)) {
appendKeyValue(stringBuilder, "通道数", Integer.toString(mAppConfig.channels));
String deviceIP = Formatter.formatIpAddress(wifiManager.getDhcpInfo().gateway);
if (DEBUG) {
deviceIP = WIFI_IP_DEVICE;
}
if (mProps.containsKey(KEY_APP_MP_VERSION)) {
String val = (String)mProps.get(KEY_APP_MP_VERSION);
appendKeyValue(stringBuilder, "APP版本", val);
Intent intent = new Intent(MainActivity.this, DeviceActivity.class);
// intent1.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("deviceIp", deviceIP);
intent.putExtra("SSID", mCurrentScanResult.SSID);
startActivity(intent);
}
if (mBatteryVoltage != -1) {
appendKeyValue(stringBuilder, "电池电压", Integer.toString(mBatteryVoltage / 1000) + "." + Integer.toString((mBatteryVoltage % 1000) / 100));
}
if (mBatteryChargingVoltage != -1) {
appendKeyValue(stringBuilder, "充电电压", Integer.toString(mBatteryChargingVoltage / 1000) + "." + Integer.toString((mBatteryChargingVoltage % 1000) / 100));
}
binding.deviceInfo.setText(Html.fromHtml(stringBuilder.toString()));
private String normalizeSSID(String ssid) {
if (TextUtils.isEmpty(ssid)) {
return ssid;
}
if (!(ssid.startsWith("\"") && ssid.endsWith("\""))) {
return "\"" + ssid + "\"";
}
private void appendKeyValue(StringBuilder stringBuilder, String key, String val) {
stringBuilder.append(key + "<font color=\"red\"><b>" + val + "</b></font>");
stringBuilder.append("<br>");
return ssid;
}
/**

@ -0,0 +1,59 @@
package com.xypower.mpremote;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.MenuItem;
import com.xypower.mpremote.databinding.ActivitySettingsBinding;
public class SettingsActivity extends AppCompatActivity {
public static final int REQUEST_CODE_SETTINGS = 13;
public static final String DEFAULT_PRE_SHARED_KEY = "12345678";
private ActivitySettingsBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
SharedPreferences preferences = getSharedPreferences("mpremote", MODE_PRIVATE);
String pwd = preferences.getString("password", null);
if (pwd != null) {
binding.editViewPassword.setText(pwd);
}
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
@Override
protected void onDestroy() {
super.onDestroy();
SharedPreferences preferences = getSharedPreferences("mpremote", MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("password", binding.editViewPassword.getText().toString());
editor.commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
setResult(0);
finish();
return false;
default:
return super.onOptionsItemSelected(item);
}
}
}

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#0000FF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
</vector>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#0000FF">
<path
android:fillColor="@android:color/white"
android:pathData="M12,4c3.42,0,6.73,1.27,9.3,3.53L12,18.85L2.7,7.53C5.27,5.27,8.58,4,12,4 M12,2C7.25,2,2.97,4.08,0,7.39L12,22L24,7.39 C21.03,4.08,16.75,2,12,2L12,2z" />
</vector>

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#0000FF">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2.01c-4.75,0-9.03,2.08-12,5.39L12,22L24,7.4C21.03,4.09,16.75,2.01,12,2.01z M12,18.86L2.7,7.54 C5.27,5.28,8.58,4.01,12,4.01s6.73,1.27,9.3,3.53L12,18.86z" />
<path
android:fillColor="@android:color/white"
android:pathData="M16.42,16.63L12,22l-4.42-5.37c0.15-0.74,0.48-1.43,0.95-1.99C9.35,13.64,10.6,13,12,13s2.65,0.64,3.47,1.64 C15.94,15.2,16.27,15.89,16.42,16.63z" />
</vector>

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#0000FF">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C7.25,2,2.97,4.08,0,7.39L12,22L24,7.39C21.03,4.08,16.75,2,12,2z M12,18.85L2.7,7.53C5.27,5.27,8.58,4,12,4 s6.73,1.27,9.3,3.53L12,18.85z" />
<path
android:fillColor="@android:color/white"
android:pathData="M18.61,13.95L12,22l-6.61-8.05c0.33-0.61,0.74-1.17,1.22-1.66c1.36-1.42,3.27-2.3,5.39-2.3s4.03,0.88,5.39,2.3 C17.87,12.78,18.28,13.34,18.61,13.95z" />
</vector>

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#0000FF">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C7.25,2,2.97,4.08,0,7.39L12,22L24,7.39C21.03,4.08,16.75,2,12,2z M12,18.85L2.7,7.53C5.27,5.27,8.58,4,12,4 s6.73,1.27,9.3,3.53L12,18.85z" />
<path
android:fillColor="@android:color/white"
android:pathData="M20.7,11.41L12,22L3.3,11.41c0.38-0.52,0.8-0.99,1.26-1.43C6.49,8.13,9.1,6.99,12,6.99s5.51,1.13,7.44,2.99 C19.9,10.41,20.33,10.89,20.7,11.41z" />
</vector>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#0000FF">
<path
android:fillColor="@android:color/white"
android:pathData="M24,7.39L12,22L0,7.39C2.97,4.08,7.25,2,12,2S21.03,4.08,24,7.39z" />
</vector>

@ -7,36 +7,24 @@
tools:context=".MainActivity">
<TextView
android:id="@+id/deviceInfo"
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:singleLine="false"
android:lineSpacingMultiplier="1.25"
android:textSize="16sp"
android:text=""
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="请先连接到设备的热点"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="@+id/takePhoto1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginBottom="8dp"
android:text="通道1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/takeVideo1" />
<Button
android:id="@+id/takeVideo1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginBottom="24dp"
android:text="视频1"
android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintBottom_toBottomOf="parent" />

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SettingsActivity">
<TextView
android:id="@+id/textViewPwd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="32dp"
android:text="密码:"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editViewPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:ems="10"
android:inputType="textVisiblePassword"
android:text=""
app:layout_constraintStart_toEndOf="@id/textViewPwd"
app:layout_constraintTop_toTopOf="@id/textViewPwd"
app:layout_constraintBottom_toBottomOf="@id/textViewPwd" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:orientation="horizontal" >
<ImageView
android:id="@+id/id_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_wifi" />
<TextView
android:id="@+id/id_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="2dp"
android:text="" />
</LinearLayout>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_search"
<item android:id="@+id/action_refresh"
android:icon="@drawable/ic_action_refresh"
android:title="@string/action_refresh"
app:showAsAction="always" />

@ -2,7 +2,10 @@
<string name="app_name">欣影微拍遥控</string>
<string name="err_dev_not_found">未发现微拍设备</string>
<string name="err_dev_failed_to_connect">连接设备失败</string>
<string name="title_activity_image"></string>
<string name="title_activity_image">照片</string>
<string name="title_activity_settings">设置</string>
<string name="title_activity_video">视频</string>
<string name="title_activity_device">微拍设备</string>
<string name="action_refresh">刷新</string>
<string name="action_settings">设置</string>
</resources>
Loading…
Cancel
Save