mirror of
https://github.com/topjohnwu/libsu.git
synced 2025-02-18 19:17:46 +00:00
Introduce DefaultContainer
This commit is contained in:
parent
92a1538ad8
commit
9f15a6d879
@ -18,27 +18,8 @@ package com.topjohnwu.superuser;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A subclass of {@link Application} with a {@link Shell.Container} injected.
|
||||
* @deprecated
|
||||
*/
|
||||
public class ContainerApp extends Application implements Shell.Container {
|
||||
|
||||
private volatile Shell mShell;
|
||||
|
||||
public ContainerApp() {
|
||||
Shell.Config.setContainer(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Shell getShell() {
|
||||
return mShell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShell(@Nullable Shell shell) {
|
||||
mShell = shell;
|
||||
}
|
||||
}
|
||||
@Deprecated
|
||||
public class ContainerApp extends Application {}
|
||||
|
@ -18,6 +18,7 @@ package com.topjohnwu.superuser;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.topjohnwu.superuser.internal.DefaultContainer;
|
||||
import com.topjohnwu.superuser.internal.Factory;
|
||||
import com.topjohnwu.superuser.internal.InternalUtils;
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler;
|
||||
@ -42,24 +43,17 @@ import androidx.annotation.Nullable;
|
||||
/**
|
||||
* A class providing an API to an interactive (root) shell.
|
||||
* <p>
|
||||
* Sharing shells means that the {@code Shell} instance would need to be stored somewhere.
|
||||
* Generally, most developers would want to have the {@code Shell} instance shared globally
|
||||
* across the application. In that case, the developer can directly use or subclass the the readily
|
||||
* available {@link com.topjohnwu.superuser.ContainerApp} and the setup is all done. If you already
|
||||
* overridden {@link android.app.Application}, and it is impossible to change the base class,
|
||||
* or for some reason one would want to store the {@code Shell} instance somewhere else, check the
|
||||
* documentation of {@link Container} for more info. Once a global {@link Container} is registered,
|
||||
* use {@link #getShell()} or {@link #getShell(GetShellCallback)} to get/construct {@code Shell}.
|
||||
* <p>
|
||||
* However in most cases, developers do not need to deal with a {@code Shell} instance.
|
||||
* Use these high level APIs:
|
||||
* In most cases, developers do not need to directly access a {@code Shell} instance.
|
||||
* Use these high level APIs instead:
|
||||
* <ul>
|
||||
* <li>{@link #sh(String...)}</li>
|
||||
* <li>{@link #su(String...)}</li>
|
||||
* <li>{@link #sh(InputStream)}</li>
|
||||
* <li>{@link #su(InputStream)}</li>
|
||||
* </ul>
|
||||
* These methods uses the global shell and are more convenient to use.
|
||||
* These methods not only uses the global shell instance but are also more convenient to use.
|
||||
* The global shell instance is constructed on-demand and cached.
|
||||
* To get the instance directly, call {@link #getShell()} or {@link #getShell(GetShellCallback)}.
|
||||
* <p>
|
||||
* Developers can check the example that came along with the library, it demonstrates many features
|
||||
* the library has to offer.
|
||||
@ -182,6 +176,12 @@ public abstract class Shell implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Container getContainer() {
|
||||
Container container = weakContainer.get();
|
||||
return container == null ? DefaultContainer.CONTAINER : container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@code Shell} instance from the global container, return {@code null} if no active
|
||||
* shell is stored in the container or no container is assigned.
|
||||
@ -190,24 +190,17 @@ public abstract class Shell implements Closeable {
|
||||
*/
|
||||
@Nullable
|
||||
public static Shell getCachedShell() {
|
||||
Shell shell = null;
|
||||
Container container = weakContainer.get();
|
||||
|
||||
if (container != null)
|
||||
shell = container.getShell();
|
||||
|
||||
Shell shell = getContainer().getShell();
|
||||
if (shell != null && !shell.isAlive())
|
||||
shell = null;
|
||||
|
||||
return shell;
|
||||
}
|
||||
|
||||
static void setCachedShell(Shell shell) {
|
||||
private static void setCachedShell(Shell shell) {
|
||||
if (isInitGlobal) {
|
||||
// Set the global shell
|
||||
Container container = weakContainer.get();
|
||||
if (container != null)
|
||||
container.setShell(shell);
|
||||
getContainer().setShell(shell);
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,17 +451,10 @@ public abstract class Shell implements Closeable {
|
||||
private Config() {}
|
||||
|
||||
/**
|
||||
* Set the container to store the global {@code Shell} instance.
|
||||
* <p>
|
||||
* Future shell commands using static method APIs will automatically obtain a {@code Shell}
|
||||
* from the container with {@link #getShell()} or {@link #getShell(GetShellCallback)}.
|
||||
* <p>
|
||||
* A {@link WeakReference} of the registered container would be saved statically
|
||||
* so the container could be garbage collected to prevent memory leak if you decide to
|
||||
* store {@code Shell} in places like {@link android.app.Activity}.
|
||||
* @param container the container to store the global {@code Shell} instance.
|
||||
* @deprecated
|
||||
*/
|
||||
public static void setContainer(@Nullable Container container) {
|
||||
@Deprecated
|
||||
public static void setContainer(@NonNull Container container) {
|
||||
weakContainer = new WeakReference<>(container);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.topjohnwu.superuser.internal;
|
||||
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class DefaultContainer implements Shell.Container {
|
||||
|
||||
public static final DefaultContainer CONTAINER = new DefaultContainer();
|
||||
|
||||
private volatile Shell shell;
|
||||
|
||||
private DefaultContainer() {}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Shell getShell() {
|
||||
return shell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShell(@Nullable Shell s) {
|
||||
shell = s;
|
||||
}
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.topjohnwu.libsuexample">
|
||||
|
||||
<application
|
||||
android:name=".ExampleApp"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name=".MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -1,34 +0,0 @@
|
||||
package com.topjohnwu.libsuexample;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.topjohnwu.superuser.BusyBoxInstaller;
|
||||
import com.topjohnwu.superuser.ContainerApp;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class ExampleApp extends ContainerApp {
|
||||
|
||||
public static final String TAG = "EXAMPLE";
|
||||
|
||||
static {
|
||||
// Use internal busybox
|
||||
Shell.Config.addInitializers(BusyBoxInstaller.class);
|
||||
// Configuration
|
||||
Shell.Config.setFlags(Shell.FLAG_REDIRECT_STDERR);
|
||||
Shell.Config.verboseLogging(BuildConfig.DEBUG);
|
||||
Shell.Config.addInitializers(ExampleInitializer.class);
|
||||
}
|
||||
|
||||
// Demonstrate Shell.Initializer
|
||||
private static class ExampleInitializer extends Shell.Initializer {
|
||||
|
||||
@Override
|
||||
public boolean onInit(Context context, @NonNull Shell shell) {
|
||||
Log.d(TAG, "onInit");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.topjohnwu.libsuexample;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
@ -9,19 +10,42 @@ import android.widget.EditText;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.superuser.BusyBoxInstaller;
|
||||
import com.topjohnwu.superuser.CallbackList;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
public static final String TAG = "EXAMPLE";
|
||||
|
||||
private TextView console;
|
||||
private EditText input;
|
||||
private ScrollView sv;
|
||||
private List<String> consoleList;
|
||||
|
||||
static {
|
||||
// Configuration
|
||||
Shell.Config.setFlags(Shell.FLAG_REDIRECT_STDERR);
|
||||
Shell.Config.verboseLogging(BuildConfig.DEBUG);
|
||||
// Use internal busybox
|
||||
Shell.Config.addInitializers(BusyBoxInstaller.class, ExampleInitializer.class);
|
||||
}
|
||||
|
||||
// Demonstrate Shell.Initializer
|
||||
static class ExampleInitializer extends Shell.Initializer {
|
||||
|
||||
@Override
|
||||
public boolean onInit(Context context, @NonNull Shell shell) {
|
||||
Log.d(TAG, "onInit");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -48,7 +72,7 @@ public class MainActivity extends Activity {
|
||||
async_cmd.setOnClickListener(v -> {
|
||||
Shell.sh(input.getText().toString())
|
||||
.to(consoleList)
|
||||
.submit(out -> Log.d(ExampleApp.TAG, "async_cmd_result: " + out.getCode()));
|
||||
.submit(out -> Log.d(TAG, "async_cmd_result: " + out.getCode()));
|
||||
input.setText("");
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user