#29: Clean out and remove the framework module

This commit is contained in:
Joshua Ott 2017-08-14 19:12:31 +02:00
parent 51c1fc4d26
commit 4f1e5e681d
67 changed files with 576 additions and 2065 deletions

3
.gitignore vendored
View file

@ -86,6 +86,7 @@ out/
# Gradle files
.gradle/
build.gradle
build/
# Local configuration file (sdk path, etc)
@ -108,4 +109,4 @@ captures/
# Keystore files
*.jks
gradle/wrapper/gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.properties

View file

@ -3,15 +3,14 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="LOCAL" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.14.1" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/framework" />
<option value="$PROJECT_DIR$/playmusicexporter" />
<option value="$PROJECT_DIR$/playmusiclib" />
<option value="$PROJECT_DIR$/superuser" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />

View file

@ -3,9 +3,9 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/PlayMusicExporter.iml" filepath="$PROJECT_DIR$/PlayMusicExporter.iml" />
<module fileurl="file://$PROJECT_DIR$/framework/framework.iml" filepath="$PROJECT_DIR$/framework/framework.iml" />
<module fileurl="file://$PROJECT_DIR$/playmusicexporter/playmusicexporter.iml" filepath="$PROJECT_DIR$/playmusicexporter/playmusicexporter.iml" />
<module fileurl="file://$PROJECT_DIR$/playmusiclib/playmusiclib.iml" filepath="$PROJECT_DIR$/playmusiclib/playmusiclib.iml" />
<module fileurl="file://$PROJECT_DIR$/superuser/superuser.iml" filepath="$PROJECT_DIR$/superuser/superuser.iml" />
</modules>
</component>
</project>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="" vcs="Git" />
</component>
</project>

View file

@ -27,7 +27,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.4.0-alpha6'
classpath 'com.android.tools.build:gradle:3.0.0-beta2'
}
}

View file

@ -1 +0,0 @@
/build

View file

@ -1,46 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 11
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.3.1'
}

View file

@ -1,35 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View file

@ -1,36 +0,0 @@
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.arcus.framework">
<application android:allowBackup="true" >
<activity
android:name=".activities.CrashActivity"
android:launchMode="singleInstance" >
</activity>
<activity
android:name="de.arcus.framework.activities.DirectoryBrowserActivity"
android:launchMode="singleInstance" >
</activity>
</application>
</manifest>

View file

@ -1,184 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.activities;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.v4.app.ShareCompat;
import android.support.v7.app.ActionBar;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.R;
public class CrashActivity extends AppCompatActivity {
// Extra flags
public static final String EXTRA_FLAG_CRASH_MESSAGE = "CRASH_TITLE";
public static final String EXTRA_FLAG_CRASH_LOG = "CRASH_LOG";
/**
* StackTrace of the exception
*/
private String mCrashMessage;
/**
* Log of the exception
*/
private String mCrashLog;
/**
* The name of the app
*/
private String mAppName;
/**
* The intent to start the app (for restart the app)
*/
private Intent mLaunchIntent;
/**
* Email address to send the crash log to
* Set this in AndroidManifest.xml: <meta-data android:name="crashhandler.email" android:value="..." />
*/
private String mMetaDataEmail;
/**
* URL of a bugtracker or a support homepage
* Set this in AndroidManifest.xml: <meta-data android:name="crashhandler.supporturl" android:value="..." />
*/
private String mMetaDataSupportURL;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash);
// Reads the crash information
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
if (bundle.containsKey(EXTRA_FLAG_CRASH_MESSAGE))
mCrashMessage = bundle.getString(EXTRA_FLAG_CRASH_MESSAGE);
if (bundle.containsKey(EXTRA_FLAG_CRASH_LOG))
mCrashLog = bundle.getString(EXTRA_FLAG_CRASH_LOG);
} else {
// No information; close activity
finish();
return;
}
try {
// Get the PackageManager to load information about the app
PackageManager packageManager = getPackageManager();
// Loads the ApplicationInfo with meta data
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
if (applicationInfo.metaData != null) {
// Reads the crash handler settings from meta data
if (applicationInfo.metaData.containsKey("crashhandler.email"))
mMetaDataEmail = applicationInfo.metaData.getString("crashhandler.email");
if (applicationInfo.metaData.containsKey("crashhandler.supporturl"))
mMetaDataSupportURL = applicationInfo.metaData.getString("crashhandler.supporturl");
}
// Gets the app name
mAppName = packageManager.getApplicationLabel(applicationInfo).toString();
// Gets the launch intent for the restart
mLaunchIntent = packageManager.getLaunchIntentForPackage(getPackageName());
} catch (PackageManager.NameNotFoundException ex) {
// If this occurs then god must be already dead
Logger.getInstance().logError("CrashHandler", ex.toString());
}
// Set the action bar title
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(getString(R.string.crashhandler_app_has_stopped_working, mAppName));
}
// Set the message
TextView textViewMessage = (TextView) findViewById(R.id.text_view_crash_message);
if (textViewMessage != null) {
textViewMessage.setText(mCrashLog);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_crash, menu);
// Hide the email button if there is no crashhandler.email in AndroidManifest.xml
menu.findItem(R.id.action_email).setVisible(!TextUtils.isEmpty(mMetaDataEmail));
// Hide the homepage if there is no crashhandler.supporturl in AndroidManifest.xml
menu.findItem(R.id.action_support).setVisible(!TextUtils.isEmpty(mMetaDataSupportURL));
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_restart) {
// Close this window
finish();
// Restart the app
startActivity(mLaunchIntent);
} else if (id == R.id.action_email) {
// Send email
ShareCompat.IntentBuilder builder = ShareCompat.IntentBuilder.from(this);
builder.setType("message/rfc822");
builder.addEmailTo(mMetaDataEmail);
builder.setSubject("Crash log for " + mAppName);
builder.setChooserTitle(R.string.crashhandler_choose_email_title);
builder.setText(mCrashLog);
builder.startChooser();
} else if (id == R.id.action_support) {
// Open Homepage
Intent intentUrl = new Intent(Intent.ACTION_VIEW, Uri.parse(mMetaDataSupportURL));
startActivity(intentUrl);
} else if (id == R.id.action_close_dialog) {
// Close this window
finish();
} else { // Other
return super.onOptionsItemSelected(item);
}
// One of our items was selected
return true;
}
}

View file

@ -1,161 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.activities;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import java.io.File;
import de.arcus.framework.R;
/**
* Activity to browse for a directory
*/
public class DirectoryBrowserActivity extends AppCompatActivity {
// The intent extra names
public final static String EXTRA_PATH = "path";
public final static String EXTRA_TITLE = "title";
/**
* The title
*/
private String mTitle = "";
/**
* The current path
*/
private File mPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set the layout
setContentView(R.layout.activity_directory_browser);
// Gets the bundle data
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
// Reads the title
if (bundle.containsKey(EXTRA_TITLE))
mTitle = bundle.getString(EXTRA_TITLE);
// Reads the start path
if (bundle.containsKey(EXTRA_PATH)) {
String path = bundle.getString(EXTRA_PATH);
if (path != null) {
mPath = new File(path);
// Default directory
if (!mPath.exists()) {
mPath = Environment.getExternalStorageDirectory();
}
}
}
}
// Setup the actionbar
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Set the title
actionBar.setTitle(mTitle);
actionBar.setSubtitle(mPath.getAbsolutePath());
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_directory_browser, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_accept) {
// Result the path
getIntent().setData(Uri.fromFile(mPath));
setResult(RESULT_OK, getIntent());
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Opens the directory browser (use the Lollipop API if it's available)
* @param context The Context
* @param defaultPath The default path
* @param title The title
*/
public static Intent openDirectoryBrowser(Context context, Uri defaultPath, String title) {
return openDirectoryBrowser(context, defaultPath, title, false);
}
/**
* Opens the directory browser (use the Lollipop API if it's available)
* @param context The Context
* @param defaultPath The default path
* @param title The title
* @param forceBuildInBrowser Set this to true to use the build-in browser even for Lollipop
*/
public static Intent openDirectoryBrowser(Context context, Uri defaultPath, String title, boolean forceBuildInBrowser) {
Intent intent;
// Check for Lollipop
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !forceBuildInBrowser) {
// Opens the Lollipop directory browser
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
} else {
// Opens the build-in directory browser
intent = new Intent(context, DirectoryBrowserActivity.class);
// The current path
intent.putExtra(DirectoryBrowserActivity.EXTRA_PATH, defaultPath.getPath());
intent.putExtra(DirectoryBrowserActivity.EXTRA_TITLE, title);
}
return intent;
}
}

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.adapter;
import android.content.Context;
import android.widget.ArrayAdapter;
import de.arcus.framework.R;
import de.arcus.framework.items.FileSystemItem;
/**
* Adapter for directories
*/
public class DirectoryAdapter extends ArrayAdapter<FileSystemItem> {
/**
* The context of the app
*/
private Context mContext;
/**
* Create a new directory adapter
* @param context The app context
*/
public DirectoryAdapter(Context context) {
super(context, R.layout.adapter_directory);
mContext = context;
}
}

View file

@ -1,127 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.crashhandler;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import de.arcus.framework.BuildConfig;
import de.arcus.framework.activities.CrashActivity;
import de.arcus.framework.logger.Logger;
/**
* Handles crashes of activities and shows a nice dialog with
* options to send the developer an email with the crash log
*
* Use in onCreate in every activity:
* CrashHandler.addCrashHandler(this);
*
* Created by ds on 22.01.2015.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
/**
* Activity of the app
*/
private Activity mActivity;
/**
* The default crash handler
*/
private Thread.UncaughtExceptionHandler mDefaultHandler;
/**
* Addes a crash handler to the app context
* @param activity The activity of the app
*/
public static void addCrashHandler(Activity activity)
{
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(activity));
}
public CrashHandler(Activity activity)
{
mActivity = activity;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
// Log crash
Logger.getInstance().logError("CrashHandler", ex.toString());
StringBuilder logBuilder = new StringBuilder();
//Device Information
logBuilder.append("---------- Device Information -----------\n");
logBuilder.append("Manufacturer: ").append(Build.MANUFACTURER).append("\n");
logBuilder.append("Model: ").append(Build.MODEL).append("\n");
logBuilder.append("Device API: ").append(Build.VERSION.RELEASE).append("\n");
logBuilder.append("Product: ").append(Build.PRODUCT).append("\n");
logBuilder.append("Build Number: ").append(Build.DISPLAY).append("\n");
logBuilder.append("Build Tags: ").append(Build.TAGS).append("\n");
logBuilder.append("\n");
// Information
logBuilder.append("---------- App Information -----------\n");
logBuilder.append("PackageName: ").append(mActivity.getPackageName()).append("\n");
logBuilder.append("Crashed activity: ").append(mActivity.getLocalClassName()).append("\n");
logBuilder.append("Version number: ").append(BuildConfig.VERSION_NAME).append("\n");
logBuilder.append("Version code: ").append(BuildConfig.VERSION_CODE).append("\n");
logBuilder.append("\n");
logBuilder.append("----------- Exception ------------\n");
logBuilder.append(ex.getMessage()).append("\n");
logBuilder.append(ex.getClass().getCanonicalName()).append(" at \n");
// Log stack trace
for (StackTraceElement stackTraceElement : ex.getStackTrace())
{
logBuilder.append("\t").append(stackTraceElement.toString()).append("\n");
}
// Log Caused by
if (ex.getCause() != null) {
logBuilder.append("----------- Caused by ------------\n");
logBuilder.append(ex.getCause().getMessage()).append("\n");
// Log stack trace
for (StackTraceElement stackTraceElement : ex.getCause().getStackTrace())
{
logBuilder.append("\t").append(stackTraceElement.toString()).append("\n");
}
}
// Opens a crash window
Intent intendCrash = new Intent(mActivity, CrashActivity.class);
intendCrash.putExtra(CrashActivity.EXTRA_FLAG_CRASH_MESSAGE, ex.getMessage());
intendCrash.putExtra(CrashActivity.EXTRA_FLAG_CRASH_LOG, logBuilder.toString());
intendCrash.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
mActivity.startActivity(intendCrash);
// Close this app
System.exit(0);
}
}

View file

@ -1,47 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.items;
/**
* Item for directory adapter
*/
public class FileSystemItem {
/**
* File system types (directory or file)
*/
public enum FileSystemType { File, Directory }
/**
* The type of the entry
*/
private FileSystemType mFileType;
/**
* @return Gets the file system type
*/
public FileSystemType getFileType() {
return mFileType;
}
}

View file

@ -1,229 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.logger;
import android.util.Log;
import java.util.LinkedList;
import java.util.Queue;
/**
* Helper class to write into a log file and to logcat
*/
public class Logger {
/**
* Type of the log entry
*/
public enum LogEntryType { Verbose, Debug, Info, Warning, Error }
/**
* Instance of the logger
*/
private static Logger instance;
/**
* Get the active instance of the Logger
* Creates an instance if not exists
* @return Gets the logger
*/
public static Logger getInstance() {
// Create new Instance
if (instance == null)
instance = new Logger();
return instance;
}
/**
* List of all entries
*/
private Queue<LogEntry> mEntryList = new LinkedList<>();
/**
* @return Gets the entry list
*/
public Queue<LogEntry> getEntryList() {
return mEntryList;
}
/**
* The minimum level to log messages
*/
private LogEntryType mLogLevel = LogEntryType.Debug;
/**
* @return Gets the log level
*/
public LogEntryType getLogLevel() {
return mLogLevel;
}
/**
* Sets the log level
* @param type The minimal log level to log messages
*/
public void setLogLevel(LogEntryType type) {
mLogLevel = type;
}
/**
* Adds a verbose entry to the log
* @param tag Tag of the log entry (function or section)
* @param message Message of the log entry
*/
public void logVerbose(String tag, String message) {
log(LogEntryType.Verbose, tag, message);
}
/**
* Adds a debug entry to the log
* @param tag Tag of the log entry (function or section)
* @param message Message of the log entry
*/
public void logDebug(String tag, String message) {
log(LogEntryType.Debug, tag, message);
}
/**
* Adds a info entry to the log
* @param tag Tag of the log entry (function or section)
* @param message Message of the log entry
*/
public void logInfo(String tag, String message) {
log(LogEntryType.Info, tag, message);
}
/**
* Adds a warning entry to the log
* @param tag Tag of the log entry (function or section)
* @param message Message of the log entry
*/
public void logWarning(String tag, String message) {
log(LogEntryType.Warning, tag, message);
}
/**
* Adds a error entry to the log
* @param tag Tag of the log entry (function or section)
* @param message Message of the log entry
*/
public void logError(String tag, String message) {
log(LogEntryType.Error, tag, message);
}
/**
* Adds a entry to the log
* @param type Entry type (Debug, Info, Warning, Error)
* @param tag Tag of the log entry (function or section)
* @param message Message of the log entry
*/
private void log(LogEntryType type, String tag, String message) {
// Entry type will be logged
if (type.ordinal() >= mLogLevel.ordinal())
{
LogEntry logEntry = new LogEntry(type, tag, message);
// LogCat
logEntry.writeToLogCat();
// Push entry to list
mEntryList.add(logEntry);
}
}
/**
* A single log entry
*/
public class LogEntry {
/**
* Type of the log entry
*/
private LogEntryType mType;
/**
* Tag of the log entry
*/
private String mTag;
/**
* Message of the log entry
*/
private String mMessage;
/**
* @return Gets the Type of the log entry
*/
public LogEntryType getType() {
return mType;
}
/**
* @return Gets the tag of the log entry
*/
public String getTag() {
return mTag;
}
/**
* @return Gets the message of the log entry
*/
public String getMessage() {
return mMessage;
}
/**
* Creates a log entry
* @param type Entry type (Debug, Info, Warning, Error)
* @param tag Tag of the log entry (function or section)
* @param message Message of the log entry
*/
public LogEntry(LogEntryType type, String tag, String message) {
mType = type;
mTag = tag;
mMessage = message;
}
/**
* Writes the entry to logcat
*/
public void writeToLogCat() {
switch (mType) {
case Verbose:
Log.v(mTag, mMessage);
break;
case Debug:
Log.d(mTag, mMessage);
break;
case Info:
Log.i(mTag, mMessage);
break;
case Warning:
Log.w(mTag, mMessage);
break;
case Error:
Log.e(mTag, mMessage);
break;
}
}
}
}

View file

@ -1,68 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.utils;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.net.Uri;
/**
* A media scanner which adds files to the android media system
*/
public class MediaScanner implements MediaScannerConnection.MediaScannerConnectionClient {
/**
* Connection to the media scanner
*/
private MediaScannerConnection mMediaScanner;
/**
* File to scan
*/
private String mFile;
/**
* Adds a file to the android media system
* @param context The context of the app
* @param string Path to the file
*/
public MediaScanner(Context context, String string) {
mFile = string;
// Connect the media scanner
mMediaScanner = new MediaScannerConnection(context, this);
mMediaScanner.connect();
}
@Override
public void onMediaScannerConnected() {
// Is connected
mMediaScanner.scanFile(mFile, null);
}
@Override
public void onScanCompleted(String path, Uri uri) {
// Done; close the connection
mMediaScanner.disconnect();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 401 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

View file

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="de.arcus.framework.activities.CrashActivity">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/scrollView">
<TextView android:text="@string/crashhandler_log" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text_view_crash_message"
android:textIsSelectable="true"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:typeface="monospace" />
</ScrollView>
</RelativeLayout>

View file

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView" />
</LinearLayout>

View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<menu 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" tools:context="de.arcus.framework.activities.CrashActivity">
<item android:id="@+id/action_restart" android:title="@string/crashhandler_action_restart"
android:orderInCategory="100" app:showAsAction="never" />
<item android:id="@+id/action_email" android:title="@string/crashhandler_action_email_log"
android:orderInCategory="101" app:showAsAction="never" />
<item android:id="@+id/action_support" android:title="@string/crashhandler_action_support_homepage"
android:orderInCategory="102" app:showAsAction="never" />
<item android:id="@+id/action_close_dialog" android:title="@string/crashhandler_action_close_dialog"
android:orderInCategory="103" app:showAsAction="never" />
</menu>

View file

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/action_move_up"
android:title="@string/directory_browser_action_move_up"
android:icon="@drawable/ic_action_back"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_accept"
android:title="@string/directory_browser_action_accept"
android:icon="@drawable/ic_action_accept"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_cancel"
android:title="@string/directory_browser_action_cancel"
android:icon="@drawable/ic_action_cancel"
app:showAsAction="ifRoom" />
</menu>

View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<resources>
<string name="crashhandler_app_has_stopped_working">%1$s funktioniert nicht mehr!</string>
<string name="crashhandler_log">Bericht</string>
<string name="crashhandler_choose_email_title">Absturzbericht senden</string>
<string name="crashhandler_action_restart">App neustarten</string>
<string name="crashhandler_action_email_log">Bereicht per E-Mail senden</string>
<string name="crashhandler_action_support_homepage">Support-Homepage öffnen</string>
<string name="crashhandler_action_close_dialog">Schließen</string>
</resources>

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<resources>
<string name="directory_browser_action_move_up">Zurück</string>
<string name="directory_browser_action_accept">Bestätigen</string>
<string name="directory_browser_action_cancel">Abbrechen</string>
</resources>

View file

@ -1,28 +0,0 @@
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View file

@ -1,27 +0,0 @@
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View file

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<resources>
<string name="crashhandler_app_has_stopped_working">%1$s has stopped working!</string>
<string name="crashhandler_log">Log</string>
<string name="crashhandler_choose_email_title">Send crash log</string>
<string name="crashhandler_action_restart">Restart app</string>
<string name="crashhandler_action_email_log">Send log via email</string>
<string name="crashhandler_action_support_homepage">Open support homepage</string>
<string name="crashhandler_action_close_dialog">Close</string>
</resources>

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
~ of this software and associated documentation files (the "Software"), to deal
~ in the Software without restriction, including without limitation the rights
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ copies of the Software, and to permit persons to whom the Software is
~ furnished to do so, subject to the following conditions:
~
~ The above copyright notice and this permission notice shall be included in
~ all copies or substantial portions of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
~ THE SOFTWARE.
-->
<resources>
<string name="directory_browser_action_move_up">Move up</string>
<string name="directory_browser_action_accept">Accept</string>
<string name="directory_browser_action_cancel">Cancel</string>
</resources>

View file

@ -1,6 +1,6 @@
#Tue Mar 28 12:22:37 CEST 2017
#Sun Aug 13 12:29:14 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip

View file

@ -1 +0,0 @@
/build

View file

@ -51,7 +51,7 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':framework')
compile project(':superuser')
compile project(':playmusiclib')
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:support-v4:25.3.1'

View file

@ -1,35 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package re.jcg.playmusicexporter;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View file

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!--
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy
@ -61,13 +62,6 @@
android:name=".services.ExportAllJob"
android:permission="android.permission.BIND_JOB_SERVICE" />
<meta-data
android:name="crashhandler.email"
android:value="mail@janchristiangruenhage.de" />
<meta-data
android:name="crashhandler.supporturl"
android:value="https://jcg.re/" />
<activity
android:name=".activities.SettingsActivity"
android:label="@string/title_settings"

View file

@ -18,7 +18,7 @@ import com.github.paolorotolo.appintro.AppIntroFragment;
import java.util.Optional;
import de.arcus.framework.superuser.SuperUser;
import rc.jcg.superuser.SuperUser;
import re.jcg.playmusicexporter.R;
import re.jcg.playmusicexporter.settings.PlayMusicExporterPreferences;

View file

@ -42,7 +42,6 @@ import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
import de.arcus.framework.logger.Logger;
import de.arcus.playmusiclib.exceptions.CouldNotOpenDatabaseException;
import de.arcus.playmusiclib.exceptions.NoSuperUserException;
import ly.count.android.sdk.Countly;
@ -119,9 +118,6 @@ public class MusicContainerListActivity extends AppCompatActivity
}
setContentView(R.layout.activity_track_list);
Logger.getInstance().logVerbose("Activity", "onCreate(" + this.getLocalClassName() + ")");
// Setup ActionBar
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
@ -221,7 +217,7 @@ public class MusicContainerListActivity extends AppCompatActivity
mPlayMusicManager.setID3ArtworkMaximumSize(PlayMusicExporterPreferences.getAlbumArtSize());
} catch (Exception e) {
Logger.getInstance().logError("SetupPlayMusicExporter", e.toString());
// Failed
}
}

View file

@ -29,7 +29,6 @@ import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import de.arcus.framework.crashhandler.CrashHandler;
import re.jcg.playmusicexporter.R;
import re.jcg.playmusicexporter.fragments.MusicTrackListFragment;
import re.jcg.playmusicexporter.items.SelectedTrackList;
@ -53,9 +52,6 @@ public class MusicTrackListActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_track_detail);
// Adds the crash handler to this class
CrashHandler.addCrashHandler(this);
// Show the Up button in the action bar.
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {

View file

@ -25,7 +25,7 @@ package re.jcg.playmusicexporter.items;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import de.arcus.framework.utils.SelectionList;
import re.jcg.playmusicexporter.utils.SelectionList;
import re.jcg.playmusicexporter.R;
import re.jcg.playmusicexporter.actionmode.ActionModeTitle;

View file

@ -30,7 +30,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import de.arcus.framework.logger.Logger;
import ly.count.android.sdk.Countly;
import re.jcg.playmusicexporter.R;
import de.arcus.playmusiclib.PlayMusicManager;
@ -97,8 +96,6 @@ public class ExportService extends IntentService {
public void onCreate() {
super.onCreate();
Logger.getInstance().logDebug("ExportService", "Start");
// Creates a notification builder
mNotificationBuilder = new NotificationCompat.Builder(this);
}
@ -108,7 +105,6 @@ public class ExportService extends IntentService {
super.onDestroy();
// Finish
Logger.getInstance().logDebug("ExportService", "End");
mFinished = true;
updateNotification();

View file

@ -24,7 +24,6 @@ package re.jcg.playmusicexporter.utils;
import android.text.TextUtils;
import de.arcus.framework.logger.Logger;
import de.arcus.playmusiclib.items.MusicTrack;
/**
@ -120,7 +119,6 @@ public class MusicPathBuilder {
break;
default:
// Unknown tag
Logger.getInstance().logWarning("MusicPathBuilder", "Unknown tag '" + name + "'");
break;
}
@ -146,9 +144,6 @@ public class MusicPathBuilder {
// Adds the rest of the format to the value
value = format.substring(0, posInsertStart) + value + format.substring(posInsertEnd);
} else {
// Missing insert sign
Logger.getInstance().logWarning("MusicPathBuilder", "Cloud not find replace symbol ('$') of format attribute in tag '" + name + "'");
}
}
@ -159,7 +154,6 @@ public class MusicPathBuilder {
} else {
path += "{";
pos = posStart + 1;
Logger.getInstance().logWarning("MusicPathBuilder", "Cloud not find end symbol ('}') of the tag in patter '" + patter + "'");
}
}

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.framework.utils;
package re.jcg.playmusicexporter.utils;
import android.support.annotation.ColorRes;
import android.support.v4.content.ContextCompat;

View file

@ -1 +0,0 @@
/build

View file

@ -41,6 +41,6 @@ android {
}
dependencies {
compile project(':framework')
compile project(':superuser')
compile 'com.mpatric:mp3agic:0.9.0'
}

View file

@ -1,35 +0,0 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.playmusiclib;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View file

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2015 David Schulte
~
@ -20,11 +21,5 @@
~ THE SOFTWARE.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.arcus.playmusiclib">
<application android:allowBackup="true">
</application>
<manifest package="de.arcus.playmusiclib">
</manifest>

View file

@ -29,9 +29,8 @@ import android.text.TextUtils;
import java.net.URL;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.superuser.SuperUserTools;
import de.arcus.framework.utils.ImageTools;
import rc.jcg.superuser.SuperUserTools;
import de.arcus.playmusiclib.utils.ImageTools;
import de.arcus.playmusiclib.items.ArtworkEntry;
/**
@ -59,7 +58,6 @@ public class ArtworkLoader {
bitmap = ImageTools.decodeByteArraySubsampled(bitmapData, artworkSize, artworkSize);
} catch (Exception e) {
// Error
Logger.getInstance().logError("LoadArtwork", e.toString());
}
}
@ -69,16 +67,12 @@ public class ArtworkLoader {
if (!TextUtils.isEmpty(artworkUrl)) {
// Tries to load the artwork via internet
try {
if (artworkUrl.contains("mediastore")) {
Logger.getInstance().logError("LoadArtwork", "mediastore artwork");
//TODO handle mediastore album art using ContentResolver
} else {
URL url = new URL(artworkUrl);
bitmap = BitmapFactory.decodeStream(url.openStream());
}
if (!artworkUrl.contains("mediastore")) {
URL url = new URL(artworkUrl);
bitmap = BitmapFactory.decodeStream(url.openStream());
}
} catch (Exception e) {
// Error
Logger.getInstance().logError("LoadArtwork", e.toString());
}
}
}

View file

@ -56,10 +56,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.superuser.SuperUser;
import de.arcus.framework.superuser.SuperUserTools;
import de.arcus.framework.utils.FileTools;
import rc.jcg.superuser.SuperUser;
import rc.jcg.superuser.SuperUserTools;
import de.arcus.playmusiclib.utils.FileTools;
import de.arcus.playmusiclib.enums.ID3v2Version;
import de.arcus.playmusiclib.exceptions.CouldNotOpenDatabaseException;
import de.arcus.playmusiclib.exceptions.NoSuperUserException;
@ -532,8 +531,6 @@ public class PlayMusicManager {
// New tmp file
fileTmp = fileTmpCrypt;
} else {
Logger.getInstance().logWarning("ExportMusicTrack", "Encrypting failed! Continue with decrypted file.");
}
}
@ -583,9 +580,6 @@ public class PlayMusicManager {
if (subDocument.isFile()) {
if (filename != null && subDocument.getName().equalsIgnoreCase(filename)) {
// Delete the file
if (forceOverwrite) {
Logger.getInstance().logWarning("ExportMusicTrack", "(forceOverwrite) Deleting original file: " + filename);
}
subDocument.delete();
break;
}
@ -604,12 +598,8 @@ public class PlayMusicManager {
if (mID3Enable) {
// Adds the meta data
if (!trackWriteID3(musicTrack, fileTmp, dest)) {
Logger.getInstance().logWarning("ExportMusicTrack", "ID3 writer failed! Continue without ID3 tags.");
// Failed, moving without meta data
if (!FileTools.fileMove(fileTmp, dest)) {
Logger.getInstance().logError("ExportMusicTrack", "Moving the raw file failed!");
// Could not copy the file
return false;
}
@ -617,8 +607,6 @@ public class PlayMusicManager {
} else {
// Moving the file
if (!FileTools.fileMove(fileTmp, dest)) {
Logger.getInstance().logError("ExportMusicTrack", "Moving the raw file failed!");
// Could not copy the file
return false;
}
@ -647,13 +635,9 @@ public class PlayMusicManager {
parcelFileDescriptor.close();
} catch (FileNotFoundException e) {
Logger.getInstance().logError("ExportMusicTrack", "File not found!");
// Could not copy the file
return false;
} catch (IOException e) {
Logger.getInstance().logError("ExportMusicTrack", "Failed to write the document: " + e.toString());
// Could not copy the file
return false;
}
@ -662,12 +646,6 @@ public class PlayMusicManager {
// Delete temp files
cleanUp(uniqueID);
// Adds the file to the media system
//new MediaScanner(mContext, dest);
} else {
Logger.getInstance().logInfo("exportMusicTrack", path + " already exists, skipping.");
}
// Done
@ -691,13 +669,7 @@ public class PlayMusicManager {
for (String lDisplayName : pPath.split("/")) {
if (lDocumentFile.findFile(lDisplayName) != null) {
lDocumentFile = lDocumentFile.findFile(lDisplayName);
if (lDocumentFile.length() == 0) {
if (!lDocumentFile.isDirectory()) {
Logger.getInstance().logInfo("isAlreadyThere", pPath + " File exists, but is 0 bytes in size.");
}
}
} else {
Logger.getInstance().logInfo("isAlreadyThere", pPath + " does not exist yet.");
return false;
}
}
@ -779,7 +751,7 @@ public class PlayMusicManager {
// Maybe the genre is not supported
tagID3v2.setGenreDescription(musicTrack.getGenre());
} catch (IllegalArgumentException e) {
Logger.getInstance().logWarning("TrackWriteID3", e.getMessage());
// Failed
}
}
@ -827,14 +799,13 @@ public class PlayMusicManager {
// Checks the magic number
if (!allAccessExporter.hasValidMagicNumber()) {
Logger.getInstance().logError("TrackEncrypt", "Invalid magic number! This is not an AllAccess file");
return false;
}
// Saves the file
return allAccessExporter.save(dest);
} catch (Exception e) {
Logger.getInstance().logError("TrackEncrypt", e.toString());
// Failed
}
// Failed

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.framework.utils;
package de.arcus.playmusiclib.utils;
import android.os.Environment;
@ -35,8 +35,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import de.arcus.framework.logger.Logger;
/**
* Help function for files
*/
@ -57,22 +55,15 @@ public class FileTools {
File fileDirectory = new File(dir);
try {
if (!fileDirectory.exists()) {
Logger.getInstance().logVerbose("DirectoryCreate", "Create directory: " + dir);
// Creates the directory
if (fileDirectory.mkdirs())
return true;
else
Logger.getInstance().logWarning("DirectoryCreate", "MkDir failed");
} else {
// Directory exists
Logger.getInstance().logDebug("DirectoryCreate", "Directory already exists");
return true;
}
} catch (Exception e) {
// Failed
Logger.getInstance().logError("DirectoryCreate", "Failed: " + e.getMessage());
}
return false;
}
@ -97,15 +88,10 @@ public class FileTools {
* @return Returns true if the file was successfully created
*/
public static boolean fileCreate(String file) {
Logger.getInstance().logVerbose("FileCreate", "File: " + file);
try {
// Create the file
return (new File(file)).createNewFile();
} catch (IOException e) {
// Failed
Logger.getInstance().logError("FileCreate", "Could not create file: " + e.getMessage());
return false;
}
}
@ -118,8 +104,6 @@ public class FileTools {
* @return Return whether the moving was successful
*/
public static boolean fileMove(String src, String dest) {
Logger.getInstance().logVerbose("FileMove", "From " + src + " to " + dest);
File fileSrc = new File(src);
File fileDest = new File(dest);
@ -139,7 +123,7 @@ public class FileTools {
final int BUFFER_SIZE = 1024;
// Will be set on true if the file was copied correctly
boolean success = false;
boolean success;
try {
// The copy buffer
@ -152,10 +136,10 @@ public class FileTools {
}
// Copy was successful
success = true;
success = true;
} catch (IOException ex) {
// Failed
Logger.getInstance().logError("FileCopy", "Failed: " + ex.toString());
success = false;
}
return success;
@ -169,10 +153,8 @@ public class FileTools {
* @return Return whether the file was copied successful
*/
public static boolean fileCopy(String src, String dest) {
Logger.getInstance().logVerbose("FileCopy", "From " + src + " to " + dest);
// Will be set on true if the file was copied correctly
boolean success = false;
boolean success;
InputStream inputStream = null;
OutputStream outputStream = null;
@ -185,7 +167,7 @@ public class FileTools {
success = fileCopy(inputStream, outputStream);
} catch (IOException ex) {
// Failed
Logger.getInstance().logError("FileCopy", "Failed: " + ex.toString());
success = false;
}
try {
@ -196,7 +178,7 @@ public class FileTools {
outputStream.close();
} catch (IOException ex) {
// Failed
Logger.getInstance().logError("FileCopy", "Failed: " + ex.toString());
success = false;
}
return success;

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.framework.utils;
package de.arcus.playmusiclib.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

View file

@ -22,4 +22,4 @@
include ':playmusicexporter', ':framework', ':playmusiclib'
include ':playmusicexporter', ':superuser', ':playmusiclib'

View file

@ -21,8 +21,5 @@
~ THE SOFTWARE.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
<manifest package="re.icg.superuser">
</manifest>

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.framework.utils;
package rc.jcg.superuser;
import java.util.ArrayList;
import java.util.List;

View file

@ -1,151 +1,148 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.superuser;
import android.os.AsyncTask;
import java.io.IOException;
import de.arcus.framework.logger.Logger;
/**
* The superuser managers
*
* This static class handles the superuser session.
* Start the session with {@link #askForPermissions() askForPermissions}.
* To run a command create an instance of {@link SuperUserCommand SuperUserCommand} and {@link SuperUserCommand#execute() execute} it.
*/
public class SuperUser {
/**
* The su process
*/
private static Process mProcess;
/**
* Gets the active su process
* @return Process
*/
static Process getProcess() {
return mProcess;
}
/**
* Starts the superuser session
* To start the session in your app use {@link #askForPermissions()}
*/
private static boolean sessionStart() {
// Starts the su process
try {
mProcess = Runtime.getRuntime().exec("su");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Stops the superuser session
*/
public static void sessionStop() {
if (mProcess == null) return;
// End the process
mProcess.destroy();
mProcess = null;
}
/**
* Gets whether the su session is running
* @return Return whether the su session is running
*/
public static boolean sessionIsRunning() {
if (mProcess == null) return false;
// Hack to see if the process is running
// This is not nice, but there is no other way to check this
try {
mProcess.exitValue();
return false;
} catch(IllegalThreadStateException ex) {
// Could not get the return value => process is running
return true;
}
}
/**
* Checks whether superuser permissions were granted
* @return Return whether superuser permissions were granted
*/
public static boolean hasPermissions() {
// Just check whether the session is running
return sessionIsRunning();
}
/**
* This is like hasPermissions() but asks for the superuser permissions
* and give the user a change to grant it now.
* Use this to start you session
* @return Return whether superuser permissions were granted
*/
public static boolean askForPermissions() {
// We already have superuser permissions
if (hasPermissions()) return true;
// Starts the process
if (sessionStart()) {
// Test for superuser
SuperUserCommand superUserCommand = new SuperUserCommand("echo 'root'");
Logger.getInstance().logInfo("SuperUser", "askForPermissions");
if (superUserCommand.execute()) {
// Gets the whoami username
String[] output = superUserCommand.getStandardOutput();
if (output.length >= 1 && output[0].equals("root")) {
// We are root
return true;
}
}
}
// We don't have superuser permissions; abort session
sessionStop();
return false;
}
public static void askForPermissionInBackground(final SuperUserPermissionRequestListener listener) {
new AsyncTask<Void, Void, Void>() {
boolean hasPermissions;
@Override
protected Void doInBackground(Void... params) {
hasPermissions = askForPermissions();
return null;
}
@Override
protected void onPostExecute(Void result) {
listener.superUserGranted(hasPermissions);
}
}.execute();
}
}
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package rc.jcg.superuser;
import android.os.AsyncTask;
import java.io.IOException;
/**
* The superuser managers
*
* This static class handles the superuser session.
* Start the session with {@link #askForPermissions() askForPermissions}.
* To run a command create an instance of {@link SuperUserCommand SuperUserCommand} and {@link SuperUserCommand#execute() execute} it.
*/
public class SuperUser {
/**
* The su process
*/
private static Process mProcess;
/**
* Gets the active su process
* @return Process
*/
static Process getProcess() {
return mProcess;
}
/**
* Starts the superuser session
* To start the session in your app use {@link #askForPermissions()}
*/
private static boolean sessionStart() {
// Starts the su process
try {
mProcess = Runtime.getRuntime().exec("su");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Stops the superuser session
*/
public static void sessionStop() {
if (mProcess == null) return;
// End the process
mProcess.destroy();
mProcess = null;
}
/**
* Gets whether the su session is running
* @return Return whether the su session is running
*/
public static boolean sessionIsRunning() {
if (mProcess == null) return false;
// Hack to see if the process is running
// This is not nice, but there is no other way to check this
try {
mProcess.exitValue();
return false;
} catch(IllegalThreadStateException ex) {
// Could not get the return value => process is running
return true;
}
}
/**
* Checks whether superuser permissions were granted
* @return Return whether superuser permissions were granted
*/
public static boolean hasPermissions() {
// Just check whether the session is running
return sessionIsRunning();
}
/**
* This is like hasPermissions() but asks for the superuser permissions
* and give the user a change to grant it now.
* Use this to start you session
* @return Return whether superuser permissions were granted
*/
public static boolean askForPermissions() {
// We already have superuser permissions
if (hasPermissions()) return true;
// Starts the process
if (sessionStart()) {
// Test for superuser
SuperUserCommand superUserCommand = new SuperUserCommand("echo 'root'");
if (superUserCommand.execute()) {
// Gets the whoami username
String[] output = superUserCommand.getStandardOutput();
if (output.length >= 1 && output[0].equals("root")) {
// We are root
return true;
}
}
}
// We don't have superuser permissions; abort session
sessionStop();
return false;
}
public static void askForPermissionInBackground(final SuperUserPermissionRequestListener listener) {
new AsyncTask<Void, Void, Void>() {
boolean hasPermissions;
@Override
protected Void doInBackground(Void... params) {
hasPermissions = askForPermissions();
return null;
}
@Override
protected void onPostExecute(Void result) {
listener.superUserGranted(hasPermissions);
}
}.execute();
}
}

View file

@ -1,394 +1,383 @@
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.arcus.framework.superuser;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import de.arcus.framework.logger.Logger;
import de.arcus.framework.utils.ByteBuffer;
/**
* This class executes superuser commands.
*/
public class SuperUserCommand {
/**
* The default timeout for each command in milliseconds
*/
private static final long DEFAULT_COMMAND_TIMEOUT = 30 * 1000; // 30 seconds
private String[] mCommands = new String[] {};
private String[] mOutputStandard = new String[] {};
private String[] mOutputError = new String[] {};
// If we want to get a binary return
private byte[] mOutputStandardBinary = new byte[] {};
/**
* Command failed?
*/
private boolean mSuperUserFailed;
/**
* If this value is set, the command will not store any input to the logger
*/
private boolean mHideInput = false;
/**
* If this value is set, the command will not store any standard output to the logger
*/
private boolean mHideStandardOutput = false;
/**
* If this value is set, the command will not store any error output to the logger
*/
private boolean mHideErrorOutput = false;
/**
* @return Gets whether the command hides the input log
*/
public boolean getHideInput() {
return mHideInput;
}
/**
* @param hideInput Set this to hide the input to the logger
*/
public void setHideInput(boolean hideInput) {
mHideInput = hideInput;
}
/**
* @return Gets whether the command hides the standard output log
*/
public boolean getHideStandardOutput() {
return mHideStandardOutput;
}
/**
* @param hideStandardOutput Set this to hide the standard output to the logger
*/
public void setHideStandardOutput(boolean hideStandardOutput) {
mHideStandardOutput = hideStandardOutput;
}
/**
* @return Gets whether the command hides the error output log
*/
public boolean getHideErrorOutput() {
return mHideErrorOutput;
}
/**
* @param hideErrorOutput Set this to hide the error output to the logger
*/
public void setHideErrorOutput(boolean hideErrorOutput) {
mHideErrorOutput = hideErrorOutput;
}
/**
* If this value is set the command will read the standard output as binary
*/
private boolean mBinaryStandardOutput = false;
/**
* @return Gets whether the output will be binary
*/
public boolean getBinaryStandardOutput() {
return mBinaryStandardOutput;
}
/**
* @param binaryStandardOutput Set this if you want a binary output
*/
public void setBinaryStandardOutput(boolean binaryStandardOutput) {
mBinaryStandardOutput = binaryStandardOutput;
}
/**
* The timeout for this command in milliseconds
*/
private long mTimeout;
/**
* @return Gets the timeout for this command in milliseconds
*/
public long getTimeout() {
return mTimeout;
}
/**
* Set the timeout for this command in milliseconds
* @param timeout Timeout
* @return Itself
*/
public SuperUserCommand setTimeout(long timeout) {
mTimeout = timeout;
return this;
}
/**
* @return Gets the executed commands
*/
public String[] getCommands() {
return mCommands;
}
/**
* @return Gets the standard output
*/
public String[] getStandardOutput() {
return mOutputStandard;
}
/**
* @return Gets the error output
*/
public String[] getErrorOutput() {
return mOutputError;
}
/**
* @return Gets the standard output as binary
*/
public byte[] getStandardOutputBinary() {
return mOutputStandardBinary;
}
/**
* @return Gets whether the command was executed without errors, even without error outputs from the command.
*/
public boolean commandWasSuccessful() {
return (!mSuperUserFailed && mOutputError.length == 0);
}
/**
* @return Gets whether the command was granted superuser permissions, but maybe has some error outputs.
*/
public boolean superuserWasSuccessful() {
return (!mSuperUserFailed);
}
/**
* The async execution thread
*/
private SuperUserCommandThread mThread;
/**
* The async callback
*/
private SuperUserCommandCallback mCallback;
/**
* Creates a command with one command line
* @param command The command
*/
public SuperUserCommand(String command) {
this(new String[] {command});
}
/**
* Creates a command with multiple command lines
* @param commands The command lines
*/
public SuperUserCommand(String[] commands) {
mCommands = commands;
// Default timeout
mTimeout = DEFAULT_COMMAND_TIMEOUT;
}
/**
* Execute the command asynchronously.
* Please notice that the commands will only executed one after another.
* The command will wait until the su process is free.
* @param callback The callback instance
*/
public void executeAsync(SuperUserCommandCallback callback) {
mCallback = callback;
// Thread is running
if (mThread != null) return;
// Create a new thread
mThread = new SuperUserCommandThread();
// Starts a thread
mThread.start();
}
/**
* Execute the command and return whether the command was executed.
* It will only return false if the app wasn't granted superuser permissions, like {@link #superuserWasSuccessful()}.
* It will also return true if the command itself returns error outputs. To check this case you should use {@link #commandWasSuccessful()} instead.
* Please consider to use {@link #executeAsync} instead of this and execute the command asynchronously.
* @return Gets whether the execution was successful.
*/
public boolean execute() {
String tmpLine;
List<String> tmpList = new ArrayList<>();
mSuperUserFailed = false;
// Opps, we don't have superuser permissions
// Did you run SuperUser.askForPermissions()?
if (!SuperUser.hasPermissions()) {
mSuperUserFailed = true;
return false;
}
// Thread safe
synchronized (SuperUser.getProcess()) {
try {
// Gets the streams
DataOutputStream dataOutputStream = new DataOutputStream(SuperUser.getProcess().getOutputStream());
BufferedReader bufferedInputReader = new BufferedReader(new InputStreamReader(SuperUser.getProcess().getInputStream()));
BufferedReader bufferedErrorReader = new BufferedReader(new InputStreamReader(SuperUser.getProcess().getErrorStream()));
// Sends the command
for (String command : mCommands) {
if (!mHideInput) // Check if we want to hide this
Logger.getInstance().logInfo("SuperUser", "< " + command);
dataOutputStream.writeBytes(command + "\n");
}
dataOutputStream.flush();
// TODO: This class cannot execute commands without any output (standard and error). These commands will run until the timeout will kill them!
// Start waiting
long timeStarted = System.currentTimeMillis();
// Wait for first data
while (!bufferedInputReader.ready() && !bufferedErrorReader.ready()) {
try {
// Waiting
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
long timeNow = System.currentTimeMillis();
// TimeOut
if (timeNow - timeStarted >= mTimeout) break;
}
// We want to read the data as binary
if (mBinaryStandardOutput) {
int len;
byte[] buffer = new byte[1024];
// Byte buffer
ByteBuffer byteBuffer = new ByteBuffer();
// Need the direct input stream
InputStream inputStream = SuperUser.getProcess().getInputStream();
do {
while (bufferedInputReader.ready()) {
// Read to buffer
len = inputStream.read(buffer);
// Write to buffer
byteBuffer.append(buffer, 0, len);
}
// Fix: Wait for the buffer and try again
try {
// Sometimes cat is to slow.
// If there is no data anymore we will wait 100ms and check again.
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (bufferedInputReader.ready());
mOutputStandardBinary = byteBuffer.toByteArray();
} else {
// Reads the standard output as text
tmpList.clear();
while (bufferedInputReader.ready()) {
tmpLine = bufferedInputReader.readLine();
// End of data
if (tmpLine == null) break;
if (!mHideStandardOutput)
Logger.getInstance().logInfo("SuperUser", "> " + tmpLine);
tmpList.add(tmpLine);
}
// Convert list to array
mOutputStandard = tmpList.toArray(new String[tmpList.size()]);
}
// Reads the error output
tmpList.clear();
while (bufferedErrorReader.ready()) {
tmpLine = bufferedErrorReader.readLine();
// End of data
if (tmpLine == null) break;
if (!mHideErrorOutput)
Logger.getInstance().logError("SuperUser", "> " + tmpLine);
tmpList.add(tmpLine);
}
// Convert list to array
mOutputError = tmpList.toArray(new String[tmpList.size()]);
// Done
return true;
} catch (IOException e) {
e.printStackTrace();
mSuperUserFailed = true;
// Command failed
return false;
}
}
}
/**
* Thread to executes the command asynchronously
*/
private class SuperUserCommandThread extends Thread {
@Override
public void run() {
super.run();
// Executes the command
execute();
if (mCallback != null)
mCallback.onFinished(SuperUserCommand.this);
}
}
}
/*
* Copyright (c) 2015 David Schulte
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package rc.jcg.superuser;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
/**
* This class executes superuser commands.
*/
public class SuperUserCommand {
/**
* The default timeout for each command in milliseconds
*/
private static final long DEFAULT_COMMAND_TIMEOUT = 30 * 1000; // 30 seconds
private String[] mCommands = new String[] {};
private String[] mOutputStandard = new String[] {};
private String[] mOutputError = new String[] {};
// If we want to get a binary return
private byte[] mOutputStandardBinary = new byte[] {};
/**
* Command failed?
*/
private boolean mSuperUserFailed;
/**
* If this value is set, the command will not store any input to the logger
*/
private boolean mHideInput = false;
/**
* If this value is set, the command will not store any standard output to the logger
*/
private boolean mHideStandardOutput = false;
/**
* If this value is set, the command will not store any error output to the logger
*/
private boolean mHideErrorOutput = false;
/**
* @return Gets whether the command hides the input log
*/
public boolean getHideInput() {
return mHideInput;
}
/**
* @param hideInput Set this to hide the input to the logger
*/
public void setHideInput(boolean hideInput) {
mHideInput = hideInput;
}
/**
* @return Gets whether the command hides the standard output log
*/
public boolean getHideStandardOutput() {
return mHideStandardOutput;
}
/**
* @param hideStandardOutput Set this to hide the standard output to the logger
*/
public void setHideStandardOutput(boolean hideStandardOutput) {
mHideStandardOutput = hideStandardOutput;
}
/**
* @return Gets whether the command hides the error output log
*/
public boolean getHideErrorOutput() {
return mHideErrorOutput;
}
/**
* @param hideErrorOutput Set this to hide the error output to the logger
*/
public void setHideErrorOutput(boolean hideErrorOutput) {
mHideErrorOutput = hideErrorOutput;
}
/**
* If this value is set the command will read the standard output as binary
*/
private boolean mBinaryStandardOutput = false;
/**
* @return Gets whether the output will be binary
*/
public boolean getBinaryStandardOutput() {
return mBinaryStandardOutput;
}
/**
* @param binaryStandardOutput Set this if you want a binary output
*/
public void setBinaryStandardOutput(boolean binaryStandardOutput) {
mBinaryStandardOutput = binaryStandardOutput;
}
/**
* The timeout for this command in milliseconds
*/
private long mTimeout;
/**
* @return Gets the timeout for this command in milliseconds
*/
public long getTimeout() {
return mTimeout;
}
/**
* Set the timeout for this command in milliseconds
* @param timeout Timeout
* @return Itself
*/
public SuperUserCommand setTimeout(long timeout) {
mTimeout = timeout;
return this;
}
/**
* @return Gets the executed commands
*/
public String[] getCommands() {
return mCommands;
}
/**
* @return Gets the standard output
*/
public String[] getStandardOutput() {
return mOutputStandard;
}
/**
* @return Gets the error output
*/
public String[] getErrorOutput() {
return mOutputError;
}
/**
* @return Gets the standard output as binary
*/
public byte[] getStandardOutputBinary() {
return mOutputStandardBinary;
}
/**
* @return Gets whether the command was executed without errors, even without error outputs from the command.
*/
public boolean commandWasSuccessful() {
return (!mSuperUserFailed && mOutputError.length == 0);
}
/**
* @return Gets whether the command was granted superuser permissions, but maybe has some error outputs.
*/
public boolean superuserWasSuccessful() {
return (!mSuperUserFailed);
}
/**
* The async execution thread
*/
private SuperUserCommandThread mThread;
/**
* The async callback
*/
private SuperUserCommandCallback mCallback;
/**
* Creates a command with one command line
* @param command The command
*/
public SuperUserCommand(String command) {
this(new String[] {command});
}
/**
* Creates a command with multiple command lines
* @param commands The command lines
*/
public SuperUserCommand(String[] commands) {
mCommands = commands;
// Default timeout
mTimeout = DEFAULT_COMMAND_TIMEOUT;
}
/**
* Execute the command asynchronously.
* Please notice that the commands will only executed one after another.
* The command will wait until the su process is free.
* @param callback The callback instance
*/
public void executeAsync(SuperUserCommandCallback callback) {
mCallback = callback;
// Thread is running
if (mThread != null) return;
// Create a new thread
mThread = new SuperUserCommandThread();
// Starts a thread
mThread.start();
}
/**
* Execute the command and return whether the command was executed.
* It will only return false if the app wasn't granted superuser permissions, like {@link #superuserWasSuccessful()}.
* It will also return true if the command itself returns error outputs. To check this case you should use {@link #commandWasSuccessful()} instead.
* Please consider to use {@link #executeAsync} instead of this and execute the command asynchronously.
* @return Gets whether the execution was successful.
*/
public boolean execute() {
String tmpLine;
List<String> tmpList = new ArrayList<>();
mSuperUserFailed = false;
// Opps, we don't have superuser permissions
// Did you run SuperUser.askForPermissions()?
if (!SuperUser.hasPermissions()) {
mSuperUserFailed = true;
return false;
}
// Thread safe
synchronized (SuperUser.getProcess()) {
try {
// Gets the streams
DataOutputStream dataOutputStream = new DataOutputStream(SuperUser.getProcess().getOutputStream());
BufferedReader bufferedInputReader = new BufferedReader(new InputStreamReader(SuperUser.getProcess().getInputStream()));
BufferedReader bufferedErrorReader = new BufferedReader(new InputStreamReader(SuperUser.getProcess().getErrorStream()));
// Sends the command
for (String command : mCommands) {
dataOutputStream.writeBytes(command + "\n");
}
dataOutputStream.flush();
// TODO: This class cannot execute commands without any output (standard and error). These commands will run until the timeout will kill them!
// Start waiting
long timeStarted = System.currentTimeMillis();
// Wait for first data
while (!bufferedInputReader.ready() && !bufferedErrorReader.ready()) {
try {
// Waiting
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
long timeNow = System.currentTimeMillis();
// TimeOut
if (timeNow - timeStarted >= mTimeout) break;
}
// We want to read the data as binary
if (mBinaryStandardOutput) {
int len;
byte[] buffer = new byte[1024];
// Byte buffer
ByteBuffer byteBuffer = new ByteBuffer();
// Need the direct input stream
InputStream inputStream = SuperUser.getProcess().getInputStream();
do {
while (bufferedInputReader.ready()) {
// Read to buffer
len = inputStream.read(buffer);
// Write to buffer
byteBuffer.append(buffer, 0, len);
}
// Fix: Wait for the buffer and try again
try {
// Sometimes cat is to slow.
// If there is no data anymore we will wait 100ms and check again.
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (bufferedInputReader.ready());
mOutputStandardBinary = byteBuffer.toByteArray();
} else {
// Reads the standard output as text
tmpList.clear();
while (bufferedInputReader.ready()) {
tmpLine = bufferedInputReader.readLine();
// End of data
if (tmpLine == null) break;
tmpList.add(tmpLine);
}
// Convert list to array
mOutputStandard = tmpList.toArray(new String[tmpList.size()]);
}
// Reads the error output
tmpList.clear();
while (bufferedErrorReader.ready()) {
tmpLine = bufferedErrorReader.readLine();
// End of data
if (tmpLine == null) break;
tmpList.add(tmpLine);
}
// Convert list to array
mOutputError = tmpList.toArray(new String[tmpList.size()]);
// Done
return true;
} catch (IOException e) {
e.printStackTrace();
mSuperUserFailed = true;
// Command failed
return false;
}
}
}
/**
* Thread to executes the command asynchronously
*/
private class SuperUserCommandThread extends Thread {
@Override
public void run() {
super.run();
// Executes the command
execute();
if (mCallback != null)
mCallback.onFinished(SuperUserCommand.this);
}
}
}

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.framework.superuser;
package rc.jcg.superuser;
/**
* Callback class if the async execution is finish

View file

@ -1,4 +1,4 @@
package de.arcus.framework.superuser;
package rc.jcg.superuser;
public interface SuperUserPermissionRequestListener {
void superUserGranted(boolean granted);

View file

@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
package de.arcus.framework.superuser;
package rc.jcg.superuser;
/**
* Tools for the superuser