feat(android): add libshell and list devices
This commit is contained in:
@@ -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'
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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!"
|
||||
|
||||
@@ -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>
|
||||
@@ -1,3 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">mynteye</string>
|
||||
|
||||
<string name="open">Open</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user