feat(android): add libshell and list devices

This commit is contained in:
John Zhao
2019-01-16 10:41:12 +08:00
parent 5105b5ea82
commit d531112075
22 changed files with 2764 additions and 23 deletions

View File

@@ -37,6 +37,7 @@ dependencies {
annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0'
implementation project(':libmynteye')
implementation project(':libshell')
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'

View File

@@ -3,6 +3,10 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.slightech.mynteye.demo">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="false"
android:label="@string/app_name"
@@ -10,7 +14,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".MainActivity">
<activity android:name=".ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>

View File

@@ -1,20 +0,0 @@
package com.slightech.mynteye.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.slightech.mynteye.Device;
import com.slightech.mynteye.DeviceUsbInfo;
import timber.log.Timber;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (DeviceUsbInfo info : Device.query()) {
Timber.i(info.toString());
}
}
}

View File

@@ -0,0 +1,63 @@
package com.slightech.mynteye.demo.ui;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
@SuppressLint("Registered")
public class BaseActivity extends AppCompatActivity {
private final int REQ_PERMISSIONS = 1;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestPermissions();
}
private void requestPermissions() {
final String[] permissions = new String[]{WRITE_EXTERNAL_STORAGE, CAMERA};
boolean granted = true;
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
granted = false;
}
}
if (granted) return;
ActivityCompat.requestPermissions(this, permissions, REQ_PERMISSIONS);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQ_PERMISSIONS) {
boolean granted = true;
if (grantResults.length < 1) {
granted = false;
} else {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
granted = false;
}
}
}
if (!granted) {
Toast.makeText(this, "Permission denied :(", Toast.LENGTH_LONG).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}

View File

@@ -0,0 +1,105 @@
package com.slightech.mynteye.demo.ui;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import butterknife.ButterKnife;
import com.slightech.mynteye.Device;
import com.slightech.mynteye.DeviceUsbInfo;
import com.slightech.mynteye.demo.R;
import com.slightech.mynteye.demo.util.RootUtils;
import java.util.ArrayList;
import java.util.Locale;
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
MenuItem item = menu.findItem(R.id.action_open);
if (item != null) {
item.setEnabled(false);
actionOpen(() -> item.setEnabled(true));
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_open:
item.setEnabled(false);
actionOpen(() -> item.setEnabled(true));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void actionOpen(final Runnable completeEvent) {
if (!RootUtils.isRooted()) {
alert("Warning", "Root denied :(");
return;
}
RootUtils.requestAccessible(ok -> {
if (completeEvent != null) completeEvent.run();
if (ok) {
toast("Root granted :)");
showDevices();
} else {
alert("Warning", "There are no devices accessible.");
}
});
}
private void showDevices() {
ArrayList<DeviceUsbInfo> infos = Device.query();
if (infos.isEmpty()) {
alert("Warning", "There are no devices :(");
} else {
ArrayList<String> items = new ArrayList<>();
for (DeviceUsbInfo info : infos) {
items.add(String.format(Locale.getDefault(), "%d, %s, SN: %s",
info.getIndex(), info.getName(), info.getSn()));
}
AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle("Devices")
.create();
ListView listView = new ListView(this);
listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));
listView.setOnItemClickListener((parent, view, position, id) -> {
dialog.dismiss();
openDevice(infos.get(position));
});
dialog.setView(listView);
dialog.show();
}
}
private void openDevice(DeviceUsbInfo info) {
}
private void toast(CharSequence text) {
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
}
private void alert(CharSequence title, CharSequence message) {
new AlertDialog.Builder(this)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.ok, null)
.show();
}
}

View File

@@ -0,0 +1,76 @@
package com.slightech.mynteye.demo.util;
import com.stericson.RootShell.RootShell;
import com.stericson.RootShell.exceptions.RootDeniedException;
import com.stericson.RootShell.execution.Command;
import com.stericson.RootShell.execution.Shell;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import timber.log.Timber;
public final class RootUtils {
public interface OnRequestAccessibleListener {
void onRequestAccessible(boolean ok);
}
public static boolean isRooted() {
if (!RootShell.isRootAvailable()) {
Timber.e("Root not found");
return false;
}
try {
RootShell.getShell(true);
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (TimeoutException e) {
Timber.e("TIMEOUT EXCEPTION!");
e.printStackTrace();
return false;
} catch (RootDeniedException e) {
Timber.e("ROOT DENIED EXCEPTION!");
e.printStackTrace();
return false;
}
try {
if (!RootShell.isAccessGiven()) {
Timber.e("ERROR: No root access to this device.");
return false;
}
} catch (Exception e) {
Timber.e("ERROR: could not determine root access to this device.");
return false;
}
return true;
}
public static void requestAccessible(OnRequestAccessibleListener l) {
try {
Shell sh = RootShell.getShell(true);
sh.add(new Command(1, "chmod 666 /dev/video*") {
@Override
public void commandOutput(int id, String line) {
Timber.d("commandOutput: %s", line);
super.commandOutput(id, line);
}
@Override
public void commandTerminated(int id, String reason) {
Timber.d("commandTerminated: %s", reason);
}
@Override
public void commandCompleted(int id, int exitcode) {
Timber.d("commandCompleted: %s", ((exitcode == 0) ? "ok" : "fail"));
if (l != null) l.onRequestAccessible(exitcode == 0);
}
});
sh.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -5,10 +5,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:context=".ui.MainActivity"
>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_open"
android:orderInCategory="0"
android:title="@string/open"
app:showAsAction="ifRoom|withText" />
</menu>

View File

@@ -1,3 +1,5 @@
<resources>
<string name="app_name">mynteye</string>
<string name="open">Open</string>
</resources>