diff --git a/libsuperuser_example/.classpath b/libsuperuser_example/.classpath new file mode 100644 index 0000000..a4f1e40 --- /dev/null +++ b/libsuperuser_example/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/libsuperuser_example/.project b/libsuperuser_example/.project new file mode 100644 index 0000000..62792e3 --- /dev/null +++ b/libsuperuser_example/.project @@ -0,0 +1,33 @@ + + + libsuperuser_example + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/libsuperuser_example/AndroidManifest.xml b/libsuperuser_example/AndroidManifest.xml new file mode 100644 index 0000000..01c7ab7 --- /dev/null +++ b/libsuperuser_example/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + " + + + \ No newline at end of file diff --git a/libsuperuser_example/proguard-project.txt b/libsuperuser_example/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/libsuperuser_example/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/libsuperuser_example/project.properties b/libsuperuser_example/project.properties new file mode 100644 index 0000000..e0f8539 --- /dev/null +++ b/libsuperuser_example/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-4 +android.library.reference.1=../libsuperuser diff --git a/libsuperuser_example/res/drawable-hdpi/ic_launcher.png b/libsuperuser_example/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000..96a442e Binary files /dev/null and b/libsuperuser_example/res/drawable-hdpi/ic_launcher.png differ diff --git a/libsuperuser_example/res/drawable-mdpi/ic_launcher.png b/libsuperuser_example/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 0000000..359047d Binary files /dev/null and b/libsuperuser_example/res/drawable-mdpi/ic_launcher.png differ diff --git a/libsuperuser_example/res/drawable-xhdpi/ic_launcher.png b/libsuperuser_example/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 0000000..71c6d76 Binary files /dev/null and b/libsuperuser_example/res/drawable-xhdpi/ic_launcher.png differ diff --git a/libsuperuser_example/res/layout/activity_main.xml b/libsuperuser_example/res/layout/activity_main.xml new file mode 100644 index 0000000..e05ab21 --- /dev/null +++ b/libsuperuser_example/res/layout/activity_main.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/libsuperuser_example/res/values/strings.xml b/libsuperuser_example/res/values/strings.xml new file mode 100644 index 0000000..342b90e --- /dev/null +++ b/libsuperuser_example/res/values/strings.xml @@ -0,0 +1,3 @@ + + libsuperuser_example + \ No newline at end of file diff --git a/libsuperuser_example/src/eu/chainfire/libsuperuser_example/BackgroundIntentService.java b/libsuperuser_example/src/eu/chainfire/libsuperuser_example/BackgroundIntentService.java new file mode 100644 index 0000000..4cafcca --- /dev/null +++ b/libsuperuser_example/src/eu/chainfire/libsuperuser_example/BackgroundIntentService.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Jorrit "Chainfire" Jongma + * + * 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 eu.chainfire.libsuperuser_example; + +import eu.chainfire.libsuperuser.Application; +import eu.chainfire.libsuperuser.Shell; +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +/** + * Example IntentService based class, to execute tasks in a background + * thread. This would typically be used by BroadcastReceivers and other + * fire-and-forget type calls. + * + * For most background calls that would occur when the UI is visible, in + * response to some user action and/or something you are waiting for, + * you would typically use an AsyncTask instead of a service like this. + * (See MainActivity.java for that example) + * + * Note that the IntentService's onHandleIntent call runs in a background + * thread, while a normal service's calls would run in the main thread, + * unless you put in the extra work. This is an important distinction + * that is often overlooked by beginners. + * + * This service starts running when needed, and stops running when the + * task is done, automagically. + * + * Please also see BootCompleteReceiver.java, and AndroidManifest.xml for + * how and when this service is instantiated. + * + * This code leaves some room for extension - if you really wanted to + * respond only to a single event that always does the same, this code + * could have been a lot shorter. + */ +public class BackgroundIntentService extends IntentService { + // you could provide more options here, should you need them + public static final String ACTION_BOOT_COMPLETE = "boot_complete"; + + public static void performAction(Context context, String action) { + performAction(context, action, null); + } + + public static void performAction(Context context, String action, Bundle extras) { + // this is utility call to easy starting the service and performing a task + // pass parameters in an bundle to be added to the intent as extras + // See BootCompleteReceiver.java + + if ((context == null) || (action == null) || action.equals("")) return; + + Intent svc = new Intent(context, BackgroundIntentService.class); + svc.setAction(action); + if (extras != null) svc.putExtras(extras); + context.startService(svc); + } + + public BackgroundIntentService() { + // If you forget this one, the app will crash + super("BackgroundIntentService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + String action = intent.getAction(); + if ((action == null) || (action.equals(""))) return; + + if (action.equals(ACTION_BOOT_COMPLETE)) { + onBootComplete(); + } + // you can define more options here... pass parameters through the "extra" values + } + + protected void onBootComplete() { + // We are running in a background thread here! + + // This would crash (when debugging) if it was called from the main thread: + Shell.SU.run("ls -l /"); + + // Let's toast that we're done, using the work-arounds and utility function in + // out Application class. Without those modifications there would be a very high + // chance of crashing the app in various Android versions. The modifications are + // simple and easily ported to your own Application class, if you can't use the + // one from libsuperuser. + Application.toast(this, "This toast will self-destruct in five seconds"); + } +} diff --git a/libsuperuser_example/src/eu/chainfire/libsuperuser_example/BootCompleteReceiver.java b/libsuperuser_example/src/eu/chainfire/libsuperuser_example/BootCompleteReceiver.java new file mode 100644 index 0000000..f85a159 --- /dev/null +++ b/libsuperuser_example/src/eu/chainfire/libsuperuser_example/BootCompleteReceiver.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 Jorrit "Chainfire" Jongma + * + * 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 eu.chainfire.libsuperuser_example; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +/** + * Example BootCompleteReceiver that starts MyIntentService + * (please see MyIntentService.java) to handle the task + * in a background thread + */ +public class BootCompleteReceiver extends BroadcastReceiver{ + @Override + public void onReceive(Context context, Intent intent) { + // What many beginners don't realize is that BroadcastReceivers like these + // usually run in the application's main thread, and can thus generate + // ANRs. This is increasingly likely with the BOOT_COMPLETED receiver, as + // the system is likely very busy when this receiver is called. + + // In this example we are starting our MyIntentService to actually do the + // work we want to happen, not only because "su" should specifically NEVER + // be called from a BroadcastReceiver, but also because you should be doing + // this even if you aren't calling "su". It's a good practise, and using + // IntentService is really easy. + + BackgroundIntentService.performAction(context, BackgroundIntentService.ACTION_BOOT_COMPLETE); + } +} \ No newline at end of file diff --git a/libsuperuser_example/src/eu/chainfire/libsuperuser_example/MainActivity.java b/libsuperuser_example/src/eu/chainfire/libsuperuser_example/MainActivity.java new file mode 100644 index 0000000..666bba5 --- /dev/null +++ b/libsuperuser_example/src/eu/chainfire/libsuperuser_example/MainActivity.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 Jorrit "Chainfire" Jongma + * + * 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 eu.chainfire.libsuperuser_example; + +import java.util.List; + +import eu.chainfire.libsuperuser.Shell; + +import android.os.AsyncTask; +import android.os.Bundle; +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.widget.EditText; + +public class MainActivity extends Activity { + private class Startup extends AsyncTask { + private ProgressDialog dialog = null; + private Context context = null; + private boolean suAvailable = false; + private String suVersion = null; + private String suVersionInternal = null; + private List suResult = null; + + public Startup setContext(Context context) { + this.context = context; + return this; + } + + @Override + protected void onPreExecute() { + // We're creating a progress dialog here because we want the user to wait. + // If in your app your user can just continue on with clicking other things, + // don't do the dialog thing. + + dialog = new ProgressDialog(context); + dialog.setTitle("Some title"); + dialog.setMessage("Doing something interesting ..."); + dialog.setIndeterminate(true); + dialog.setCancelable(false); + dialog.show(); + } + + @Override + protected Void doInBackground(Void... params) { + // Let's do some SU stuff + suAvailable = Shell.SU.available(); + if (suAvailable) { + suVersion = Shell.SU.version(false); + suVersionInternal = Shell.SU.version(true); + suResult = Shell.SU.run(new String[] { + "id", + "ls -l /" + }); + } + + // This is just so you see we had a progress dialog, + // don't do this in production code + try { Thread.sleep(5000); } catch(Exception e) { } + + return null; + } + + @Override + protected void onPostExecute(Void result) { + dialog.dismiss(); + + // output + StringBuilder sb = (new StringBuilder()). + append("Root? ").append(suAvailable ? "Yes" : "No").append((char)10). + append("Version: ").append(suVersion == null ? "N/A" : suVersion).append((char)10). + append("Version (internal): ").append(suVersionInternal == null ? "N/A" : suVersionInternal).append((char)10). + append((char)10); + if (suResult != null) { + for (String line : suResult) { + sb.append(line).append((char)10); + } + } + ((EditText)findViewById(R.id.text)).setText(sb.toString()); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Let's do some background stuff + (new Startup()).setContext(this).execute(); + } +}