it.readbeyond.minstrel.commander.Commander.java Source code

Java tutorial

Introduction

Here is the source code for it.readbeyond.minstrel.commander.Commander.java

Source

//
//            _           _            _ 
//           (_)         | |          | |
//  _ __ ___  _ _ __  ___| |_ _ __ ___| |
// | '_ ` _ \| | '_ \/ __| __| '__/ _ \ |
// | | | | | | | | | \__ \ |_| | |  __/ |
// |_| |_| |_|_|_| |_|___/\__|_|  \___|_|
//
// Author:      Alberto Pettarin (www.albertopettarin.it)
// Copyright:   Copyright 2013-2015, ReadBeyond Srl (www.readbeyond.it)
// License:     MIT
// Email:       minstrel@readbeyond.it
// Web:         http://www.readbeyond.it/minstrel/
// Status:      Production
//

package it.readbeyond.minstrel.commander;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager;
import android.widget.Toast;

import java.io.File;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.io.FileWriter;
import java.io.IOException;

import java.util.ArrayList;
import java.util.List;

public class Commander extends CordovaPlugin {

    // plugin action
    public static final String ACTION_COMMANDER = "commander";

    // argument names
    public static final String ARGUMENT_COMMAND = "command";
    public static final String ARGUMENT_OPTION = "option";

    // command values
    public static final String COMMAND_TOAST = "toast";
    public static final String COMMAND_DIM = "dim";
    public static final String COMMAND_SET_BRIGHTNESS = "setbrightness";
    public static final String COMMAND_GET_BRIGHTNESS = "getbrightness";
    public static final String COMMAND_ORIENT = "orient";
    public static final String COMMAND_OPEN_EXTERNAL_URL = "openExternalURL";
    public static final String COMMAND_FILESYSTEM_INFO = "filesystemInfo";
    public static final String COMMAND_CHECK_FILE_EXISTS = "checkFileExists";
    public static final String COMMAND_DELETE_RELATIVE = "deleteRelative";
    public static final String COMMAND_DELETE_ABSOLUTE = "deleteAbsolute";
    public static final String COMMAND_WRITE_TO_FILE = "writeToFile";
    public static final String COMMAND_COPY = "copy";
    public static final String COMMAND_MOVE = "move";
    //public static final String COMMAND_LIST_DIRECTORY        = "listDirectory";
    public static final String COMMAND_LIST_SUBDIRECTORIES = "listSubdirectories";
    public static final String COMMAND_COPY_FROM_ASSETS_WWW = "copyFromAssetsWWW";
    //public static final String COMMAND_GET_STORAGE_ROOTS     = "getStorageRoots";
    //public static final String COMMAND_CREATE_DIRECTORY      = "createDirectory";

    // orient options 
    public static final String ORIENT_OPTION_AUTO = "auto";
    public static final String ORIENT_OPTION_LANDSCAPE = "landscape";
    public static final String ORIENT_OPTION_PORTRAIT = "portrait";

    // return messages
    public static final String MESSAGE_REFRESH = "refresh";
    public static final String MESSAGE_NO_REFRESH = "norefresh";
    public static final String MESSAGE_FILE_EXISTS = "fileexists";
    public static final String MESSAGE_FILE_DOES_NOT_EXIST = "filedoesnotexist";
    public static final String MESSAGE_FILE_WRITTEN = "filewritten";
    public static final String MESSAGE_FILE_NOT_WRITTEN = "filenotwritten";
    public static final String MESSAGE_FILE_COPIED = "filecopied";
    public static final String MESSAGE_FILE_MOVED = "filemoved";
    public static final String MESSAGE_DIRECTORY_CREATED = "directorycreated";
    public static final String MESSAGE_DIRECTORY_NOT_CREATED = "directorynotcreated";
    public static final String MESSAGE_ERROR_WHILE_COPYING = "errorwhilecopying";

    @Override
    public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext)
            throws JSONException {
        if (ACTION_COMMANDER.equals(action)) {

            cordova.getThreadPool().execute(new Runnable() {
                public void run() {

                    try {

                        JSONObject argsJSONObject = args.getJSONObject(0);
                        String commandName = argsJSONObject.getString(ARGUMENT_COMMAND);
                        JSONObject parameters = new JSONObject(argsJSONObject.getString(ARGUMENT_OPTION));

                        // show toast
                        if (commandName.equals(COMMAND_TOAST)) {
                            toast(parameters.optString("message", ""), callbackContext);
                        }

                        // dim/undim home/back/settings bar
                        if (commandName.equals(COMMAND_DIM)) {
                            dim(parameters.optBoolean("dim", false), callbackContext);
                        }

                        // set screen brightness
                        if (commandName.equals(COMMAND_SET_BRIGHTNESS)) {
                            setBrightness(parameters.optString("value", "1.0"), callbackContext);
                        }

                        // get screen brightness
                        if (commandName.equals(COMMAND_GET_BRIGHTNESS)) {
                            getBrightness(callbackContext);
                        }

                        // set screen orientation
                        if (commandName.equals(COMMAND_ORIENT)) {
                            orient(parameters.optString("value", ORIENT_OPTION_AUTO), callbackContext);
                        }

                        // open external URL
                        if (commandName.equals(COMMAND_OPEN_EXTERNAL_URL)) {
                            openExternalURL(parameters.optString("url", "http://www.readbeyond.it/"),
                                    callbackContext);
                        }

                        // get filesystem info
                        if (commandName.equals(COMMAND_FILESYSTEM_INFO)) {
                            callbackContext.success(getFilesystemInfoJSONString());
                        }

                        // check whether the given file exists
                        if (commandName.equals(COMMAND_CHECK_FILE_EXISTS)) {
                            if (doesFileExist(parameters.optString("path", null))) {
                                callbackContext.success(MESSAGE_FILE_EXISTS);
                            }
                            callbackContext.success(MESSAGE_FILE_DOES_NOT_EXIST);
                        }

                        // delete file or directory, where option is the path relative to external storage 
                        if (commandName.equals(COMMAND_DELETE_RELATIVE)) {
                            delete(new File(Environment.getExternalStorageDirectory(),
                                    parameters.optString("path", null)), callbackContext);
                        }

                        // delete file or directory, where option is the absolute path in the file system
                        if (commandName.equals(COMMAND_DELETE_ABSOLUTE)) {
                            delete(new File(parameters.optString("path", null)), callbackContext);
                        }

                        // copy file option into option2
                        if (commandName.equals(COMMAND_COPY)) {
                            copyFile(parameters.optString("source", null),
                                    parameters.optString("destination", null), callbackContext);
                        }

                        // copy file option from assets/www/ into option2
                        if (commandName.equals(COMMAND_COPY_FROM_ASSETS_WWW)) {
                            copyFileFromAssetsWWW(parameters.optString("source", null),
                                    parameters.optString("destination", null), callbackContext);
                        }

                        // move file option into option2
                        if (commandName.equals(COMMAND_MOVE)) {
                            moveFile(parameters.optString("source", null),
                                    parameters.optString("destination", null), callbackContext);
                        }

                        // write string option2 to file option
                        if (commandName.equals(COMMAND_WRITE_TO_FILE)) {
                            callbackContext.success(writeStringToFile(parameters.optString("destination", null),
                                    parameters.optString("string", null)));
                        }

                        // list the subdirectories of the directory option, ignoring hidden subdirectories if option2 is true
                        if (commandName.equals(COMMAND_LIST_SUBDIRECTORIES)) {
                            callbackContext.success(getDirectoryListingJSONString(
                                    parameters.optString("path", null), parameters.optBoolean("recursive", false),
                                    parameters.optBoolean("ignoreHidden", true), true));
                        }

                        // call success 
                        callbackContext.success("");

                    } catch (Exception e) {

                        // call error
                        callbackContext.error("Exception " + e);

                    }
                }
            });
            return true;
        }
        callbackContext.error("Invalid action");
        return false;
    }

    private void copyFileFromAssetsWWW(String sourcePath, String destinationPath,
            final CallbackContext callbackContext) {
        String source = "www" + File.separator + sourcePath;
        String destination = this.normalizePath(destinationPath);
        try {
            File d = new File(destination);

            // create parent directory, if not existing
            File destinationParent = d.getParentFile();
            destinationParent.mkdirs();

            // TODO check for write permission?
            // copy in chunks of 4 KB
            final int BUFFER = 4096;
            BufferedInputStream is = new BufferedInputStream(
                    cordova.getActivity().getApplicationContext().getAssets().open(source));
            int numberOfBytesRead;
            byte data[] = new byte[BUFFER];
            FileOutputStream fos = new FileOutputStream(d);
            BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
            while ((numberOfBytesRead = is.read(data, 0, BUFFER)) > -1) {
                dest.write(data, 0, numberOfBytesRead);
            }
            dest.flush();
            dest.close();
            is.close();
            fos.close();
            callbackContext.success(MESSAGE_FILE_COPIED);

        } catch (Exception e) {
            callbackContext.success(MESSAGE_ERROR_WHILE_COPYING);
        }
    }

    private void copyFile(String sourcePath, String destinationPath, final CallbackContext callbackContext) {
        String source = this.normalizePath(sourcePath);
        String destination = this.normalizePath(destinationPath);
        try {
            File f = new File(source);
            if (f.exists()) {
                File d = new File(destination);

                // create parent directory, if not existing
                File destinationParent = d.getParentFile();
                destinationParent.mkdirs();

                // TODO check for write permission?
                // copy file
                FileInputStream inStream = new FileInputStream(f);
                FileOutputStream outStream = new FileOutputStream(d);
                FileChannel inChannel = inStream.getChannel();
                FileChannel outChannel = outStream.getChannel();
                inChannel.transferTo(0, inChannel.size(), outChannel);
                inStream.close();
                outStream.close();
                callbackContext.success(MESSAGE_FILE_COPIED);

            } else {
                callbackContext.success(MESSAGE_FILE_DOES_NOT_EXIST);
            }
        } catch (Exception e) {
            callbackContext.success(MESSAGE_ERROR_WHILE_COPYING);
        }
    }

    private void moveFile(String sourcePath, String destinationPath, final CallbackContext callbackContext) {
        String source = this.normalizePath(sourcePath);
        String destination = this.normalizePath(destinationPath);
        try {
            File f = new File(source);
            if (f.exists()) {
                File d = new File(destination);

                // create parent directory, if not existing
                File destinationParent = d.getParentFile();
                destinationParent.mkdirs();

                // TODO check for write permission?
                // move file
                f.renameTo(d);
                callbackContext.success(MESSAGE_FILE_MOVED);

            } else {
                callbackContext.success(MESSAGE_FILE_DOES_NOT_EXIST);
            }
        } catch (Exception e) {
            callbackContext.success(MESSAGE_ERROR_WHILE_COPYING);
        }
    }

    private String[] getStoragePaths() {
        String[] storagePaths = Storage.getStoragePaths();
        if ((storagePaths == null) || (storagePaths.length < 1)) {
            storagePaths = new String[1];
            storagePaths[0] = Environment.getExternalStorageDirectory().getAbsolutePath();
        }
        return storagePaths;
    }

    private JSONArray getStorageRootsJSONArray() {
        String[] storagePaths = this.getStoragePaths();
        JSONArray arr = new JSONArray();
        for (String s : storagePaths) {
            arr.put(s);
        }
        return arr;
    }

    private String getFilesystemInfoJSONString() throws JSONException {
        JSONObject obj = new JSONObject();
        obj.put("root", Environment.getExternalStorageDirectory().getAbsolutePath());
        obj.put("separator", File.separator);
        obj.put("documentsDir", ""); // TODO
        obj.put("cacheDir", ""); // TODO
        obj.put("storageRoots", this.getStorageRootsJSONArray());
        return obj.toString();
    }

    private boolean doesFileExist(String path) {
        try {
            File f = new File(this.normalizePath(path));
            if (f.exists()) {
                return true;
            }
        } catch (Exception e) {
            // nop
        }
        return false;
    }

    private String writeStringToFile(String path, String contents) {
        try {
            // TODO check for write permission?
            File f = new File(this.normalizePath(path));
            FileWriter out = new FileWriter(f);
            out.write(contents);
            out.flush();
            out.close();
            return MESSAGE_FILE_WRITTEN;
        } catch (Exception e) {
            // nop
        }
        return MESSAGE_FILE_NOT_WRITTEN;
    }

    private String getDirectoryListingJSONString(String path, boolean recursive, boolean ignoreHidden,
            boolean directoriesOnly) throws JSONException {
        JSONObject obj = new JSONObject();
        if ((path == null) || (path.equals(""))) {
            List<StorageInfo> storagePathsInfo = Storage.getStoragePathsInfo();
            for (int i = 0; i < storagePathsInfo.size(); i++) {
                StorageInfo si = storagePathsInfo.get(i);
                JSONObject sp = new JSONObject();
                sp.put("internal", !si.removable);
                sp.put("subdirectories",
                        this.getDirectoryListingJSONArray(si.path, recursive, ignoreHidden, directoriesOnly));
                obj.put(si.path, sp);
            }
        } else {
            JSONObject sp = new JSONObject();
            sp.put("internal", true); // dummy
            sp.put("subdirectories",
                    this.getDirectoryListingJSONArray(path, recursive, ignoreHidden, directoriesOnly));
            obj.put(path, sp);
        }
        return obj.toString();
    }

    private JSONArray getDirectoryListingJSONArray(String path, boolean recursive, boolean ignoreHidden,
            boolean directoriesOnly) throws JSONException {
        List<String> acc = new ArrayList<String>();
        try {
            listRecursively(new File(this.normalizePath(path)), recursive, ignoreHidden, directoriesOnly, acc);
        } catch (Exception e) {
            // nothing
        }
        JSONArray arr = new JSONArray();
        for (String s : acc) {
            arr.put(s);
        }
        return arr;
    }

    private void listRecursively(File path, boolean recursive, boolean ignoreHidden, boolean directoriesOnly,
            List<String> acc) {
        File[] files = path.listFiles();
        for (File f : files) {
            if ((f.canRead()) && (!f.isHidden())) {
                String n = f.getName();
                if (!((n.startsWith(".")) && (ignoreHidden))) {
                    if (f.isDirectory()) {
                        if (directoriesOnly) {
                            acc.add(f.getAbsolutePath());
                        }
                        if (recursive) {
                            listRecursively(f, recursive, ignoreHidden, directoriesOnly, acc);
                        }
                    } else {
                        if (!directoriesOnly) {
                            acc.add(f.getAbsolutePath());
                        }
                    }
                }
            }
        }
    }

    // normalize path
    private String normalizePath(String path) {
        return this.normalizePath(path, Environment.getExternalStorageDirectory().getAbsolutePath());
    }

    private String normalizePath(String path, String base) {
        if ((path.length() > 0) && (path.startsWith(File.separator))) {
            // path is an absolute path, like /sdcard0/minstrel/foo => return it
            return path;
        } else if ((path.length() > 7) && (path.startsWith("file://"))) {
            // path is a prefixed path, like file:///sdcard0/minstrel/foo => strip file://
            return path.substring(7);
        } else {
            // path is relative => returns base/path
            return base + File.separator + path;
        }
    }

    // escape double quotes
    private String escape(String unescaped) {
        if (unescaped == null) {
            return "";
        }
        return unescaped.replace("\"", "\\\"");
    }

    // delete
    private void delete(File f, final CallbackContext callbackContext) {
        try {
            deleteRecursively(f);
            callbackContext.success("");
        } catch (Exception e) {
            // nop
            callbackContext.error("Exception " + e);
        }
    }

    // delete recursively
    private void deleteRecursively(File f) {
        if (f.isDirectory()) {
            for (File child : f.listFiles()) {
                deleteRecursively(child);
            }
        }
        f.delete();
    }

    private void toast(final String msg, final CallbackContext callbackContext) {
        cordova.getActivity().runOnUiThread(new Runnable() {
            public void run() {
                Toast toast = Toast.makeText(cordova.getActivity().getApplicationContext(), msg, Toast.LENGTH_LONG);
                toast.show();
                callbackContext.success("");
            }
        });
    }

    private void dim(final boolean dim, final CallbackContext callbackContext) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            cordova.getActivity().runOnUiThread(new Runnable() {
                public void run() {
                    try {
                        // getRootView is really necessary here!!! 
                        View rootView = cordova.getActivity().getWindow().getDecorView().getRootView();
                        if (rootView != null) {
                            if (dim) {
                                rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
                            } else {
                                rootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
                            }
                        }
                        callbackContext.success("");
                    } catch (Exception e) {
                        callbackContext.error("Exception " + e);
                    }
                }
            });
        }
    }

    private void setBrightness(final String option, final CallbackContext callbackContext) {
        final float brightness = (float) Double.parseDouble(option);
        final int ibrightness = (int) (brightness * 255);
        try {
            cordova.getActivity().runOnUiThread(new Runnable() {
                public void run() {
                    //
                    // this changes the system brightness
                    //
                    // android.provider.Settings.System.putInt(cordova.getActivity().getApplicationContext().getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE, android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
                    // android.provider.Settings.System.putInt(cordova.getActivity().getApplicationContext().getContentResolver(), android.provider.Settings.System.SCREEN_BRIGHTNESS, ibrightness);     
                    //

                    //
                    // this changes the brightness only for the app
                    //
                    WindowManager.LayoutParams layoutParams = cordova.getActivity().getWindow().getAttributes();
                    layoutParams.screenBrightness = brightness;
                    cordova.getActivity().getWindow().setAttributes(layoutParams);
                    callbackContext.success("");
                }
            });
        } catch (Exception e) {
            // nop
            callbackContext.error("Exception " + e);
        }
    }

    private void getBrightness(final CallbackContext callbackContext) {
        try {
            //cordova.getActivity().runOnUiThread(new Runnable() {
            //    public void run() {
            WindowManager.LayoutParams layoutParams = cordova.getActivity().getWindow().getAttributes();
            callbackContext.success("" + layoutParams.screenBrightness);
            //    }
            //});
        } catch (Exception e) {
            // nop
            callbackContext.error("Exception " + e);
        }
    }

    private void orient(final String option, final CallbackContext callbackContext) {
        try {
            Activity activity = cordova.getActivity();
            if (option.equals(ORIENT_OPTION_PORTRAIT)) {
                // portrait or reverse portrait
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
            } else if (option.equals(ORIENT_OPTION_LANDSCAPE)) {
                // landscape or reverse portrait
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
            } else if (option.equals(ORIENT_OPTION_AUTO)) {
                // unlock orientation
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
            } else {
                // default: unlock orientation
                activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
            }
            callbackContext.success("");
        } catch (Exception e) {
            // nop
            callbackContext.error("Exception " + e);
        }
    }

    private void openExternalURL(final String url, final CallbackContext callbackContext) {
        try {
            Intent intent = null;
            intent = new Intent(Intent.ACTION_VIEW);
            Uri uri = Uri.parse(url);
            /*
            if ("file".equals(uri.getScheme())) {
            intent.setDataAndType(uri, webView.getResourceApi().getMimeType(uri));
            } else {
            intent.setData(uri);
            }
            */
            intent.setData(uri);
            cordova.getActivity().startActivity(intent);
            callbackContext.success("");
        } catch (Exception e) {
            // nop
            callbackContext.error("Exception " + e);
        }
    }
}