Android Open Source - SystemAppMover App Click Listener






From Project

Back to project page SystemAppMover.

License

The source code is released under:

Apache License

If you think the Android project SystemAppMover listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2014 Thomas Hoffmann//ww w .  java 2s  . co  m
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.j4velin.systemappmover;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;

import com.stericson.RootTools.RootTools;

import java.io.File;
import java.util.List;

public class AppClickListener implements OnItemClickListener {

    private final AppPicker ap;

    public AppClickListener(final AppPicker a) {
        ap = a;
    }

    public void onItemClick(final AdapterView<?> parent, final View view, final int position, long id) {
        if (position >= ap.apps.size()) return;

        if ("MOVED".equals(view.getTag())) {
            ap.activity.showErrorDialog("Please reboot before moving this app again");
            return;
        }

        ApplicationInfo tmp = ap.apps.get(position);
        boolean tmpAlreadySys = (tmp.flags & ApplicationInfo.FLAG_SYSTEM) == 1;

        // update necessary?
        if ((tmpAlreadySys && tmp.sourceDir.contains("/data/app/")) ||
                (!tmpAlreadySys && tmp.sourceDir.contains(MoverActivity.SYSTEM_APP_FOLDER))) {
            try {
                tmp = ap.pm.getApplicationInfo(tmp.packageName, 0);
            } catch (NameNotFoundException e1) {
                ap.activity.showErrorDialog("App not found");
                if (BuildConfig.DEBUG) Logger.log(e1);
                return;
            }
        }

        final ApplicationInfo app = tmp;
        final String appName = (String) app.loadLabel(ap.pm);
        final boolean alreadySys = (app.flags & ApplicationInfo.FLAG_SYSTEM) == 1;

        if (BuildConfig.DEBUG) Logger.log("Trying to move " + appName + " - " + app.packageName);

        if (app.packageName.equals(ap.activity.getPackageName())) {
            ap.activity.showErrorDialog("Can not move myself");
            if (BuildConfig.DEBUG) Logger.log("Can not move myself");
            return;
        }

        if (alreadySys && app.sourceDir.contains("/data/app/")) {
            if (BuildConfig.DEBUG) Logger.log("Need to remove updates first");
            AlertDialog.Builder builder = new AlertDialog.Builder(ap.activity);
            builder.setTitle("Error")
                    .setMessage("Can not move " + appName + ": Remove installed updates first.")
                    .setPositiveButton("Remove updates", new DialogInterface.OnClickListener() {
                        public void onClick(final DialogInterface dialog, int id) {
                            try {
                                ap.activity.startActivity(new Intent(Intent.ACTION_DELETE,
                                        Uri.parse("package:" + app.packageName)));
                                dialog.dismiss();
                            } catch (Exception e) {
                            }
                        }
                    }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(final DialogInterface dialog, int id) {
                    try {
                        dialog.dismiss();
                    } catch (Exception e) {
                    }
                }
            });
            builder.create().show();
            return;
        } else if (!alreadySys && tmp.sourceDir.contains(MoverActivity.SYSTEM_APP_FOLDER)) {
            ap.activity.showErrorDialog("Can not move " + appName +
                    ": Undefined app status. You might need to reboot once.");
            if (BuildConfig.DEBUG) Logger.log(
                    "Undefined app status: IsSystem = " + alreadySys + " path = " + tmp.sourceDir);
            return;
        }

        if (!alreadySys && app.sourceDir.endsWith("pkg.apk")) {
            if (app.sourceDir.contains("asec")) {
                if (BuildConfig.DEBUG) Logger.log("Paid app? Path = " + app.sourceDir);
                ap.activity.showErrorDialog(appName +
                        " seems to be a paid app and therefore can not be converted to system app due to limitations by the Android system");
            } else {
                if (BuildConfig.DEBUG) Logger.log("SD card? " + app.sourceDir);
                ap.activity.showErrorDialog(appName +
                        " is currently installed on SD card. Please move to internal memory before moving to /system/app/");
            }
            return;
        }

        AlertDialog.Builder b = new AlertDialog.Builder(ap.activity);
        b.setMessage("Convert " + appName + " to " + (alreadySys ? "normal" : "system") + " app?");
        b.setPositiveButton(android.R.string.yes, new OnClickListener() {
            @SuppressWarnings("deprecation")
            @Override
            public void onClick(DialogInterface dialog, int which) {
                if (RootTools.remount("/system", "rw")) {
                    try {

                        if (BuildConfig.DEBUG) Logger.log("process name: " + app.processName);

                        ActivityManager activityManager = (ActivityManager) ap.activity
                                .getSystemService(Context.ACTIVITY_SERVICE);
                        List<RunningAppProcessInfo> runningProcInfo =
                                activityManager.getRunningAppProcesses();
                        String[] pkgList;
                        for (RunningAppProcessInfo p : runningProcInfo) {
                            pkgList = p.pkgList;
                            for (String pkg : pkgList) {
                                if (pkg.equals(app.processName)) {
                                    if (BuildConfig.DEBUG) Logger.log("killing: " + p.processName);
                                    RootTools.killProcess(p.processName);
                                    break;
                                }
                            }
                        }

                        if (BuildConfig.DEBUG) Logger.log("source: " + app.sourceDir);
                        if (!new File(app.sourceDir).exists()) {
                            if (BuildConfig.DEBUG) Logger.log("source does not exist?!?");
                            ap.activity.showErrorDialog("Can not access source file");
                            return;
                        }


                        String mvcmd, newFile;
                        List<String> output;
                        if (!alreadySys) {
                            if (app.sourceDir.endsWith("/pkg.apk")) {
                                newFile = MoverActivity.SYSTEM_APP_FOLDER + app.packageName +
                                        "-asec.apk";
                                if (!RootTools.remount("/mnt", "rw")) {
                                    if (BuildConfig.DEBUG) Logger.log("Can not remount /mnt");
                                    ap.activity.showErrorDialog("Can not remount /mnt/asec");
                                    return;
                                }
                                if (BuildConfig.DEBUG)
                                    Logger.log("source ends with /pkg.apk -> paid app");
                            } else if (app.sourceDir.endsWith("/base.apk")) {
                                String appNameWithoutSpaces = appName.replace(" ","");
                                newFile =
                                        MoverActivity.SYSTEM_APP_FOLDER + appNameWithoutSpaces +
                                                ".apk";
                            } else {
                                newFile = app.sourceDir
                                        .replace("/data/app/", MoverActivity.SYSTEM_APP_FOLDER);
                            }
                            mvcmd = "busybox mv " + app.sourceDir + " " +
                                    newFile;
                        } else {
                            if (app.sourceDir.endsWith("/pkg.apk")) {
                                newFile = "/data/app/" + app.packageName + ".apk";
                                mvcmd = "busybox mv " + app.sourceDir + " " + newFile;
                            } else {
                                newFile = app.sourceDir
                                        .replace(MoverActivity.SYSTEM_APP_FOLDER, "/data/app/");
                                mvcmd = "busybox mv " + app.sourceDir + " /data/app/";
                            }
                        }
                        if (BuildConfig.DEBUG) Logger.log("command: " + mvcmd);

                        output = RootTools.sendShell(mvcmd, 10000);

                        if (output.size() > 1) {
                            String error = "Error: ";
                            for (String str : output) {
                                if (str.length() > 1) {
                                    error += "\n" + str;
                                }
                            }
                            if (BuildConfig.DEBUG) Logger.log(error);
                            ap.activity.showErrorDialog(error);
                        } else {

                            File f = new File(newFile);

                            for (int i = 0; f.length() < 1 && i < 20; i++) {
                                Thread.sleep(100);
                            }

                            if (BuildConfig.DEBUG)
                                Logger.log("file " + f.getAbsolutePath() + " size: " + f.length());

                            if (f.length() > 1) {

                                if (!alreadySys) {
                                    output = RootTools
                                            .sendShell("busybox chmod 644 " + newFile, 5000);
                                    if (BuildConfig.DEBUG) {
                                        for (String str : output) {
                                            Logger.log(str);
                                        }
                                    }
                                }

                                view.setVisibility(View.GONE);
                                view.setTag("MOVED");
                                AlertDialog.Builder b2 = new AlertDialog.Builder(ap.activity);
                                b2.setMessage(appName +
                                        " successfully moved, you need to reboot your device.\nReboot now?");
                                if (BuildConfig.DEBUG) Logger.log("successfully moved");
                                b2.setPositiveButton(android.R.string.yes, new OnClickListener() {
                                    @Override
                                    public void onClick(final DialogInterface dialog, int which) {
                                        if (BuildConfig.DEBUG) Logger.log("reboot now");
                                        ap.activity.sendBroadcast(
                                                new Intent("de.j4velin.ACTION_SHUTDOWN"));
                                        try {
                                            dialog.dismiss();
                                        } catch (Exception e) {
                                        }
                                        try {
                                            RootTools.sendShell(
                                                    "am broadcast -a android.intent.action.ACTION_SHUTDOWN",
                                                    5000);
                                            try {
                                                Thread.sleep(1000);
                                            } catch (InterruptedException e) {
                                            }
                                            RootTools.sendShell("reboot", 5000);
                                        } catch (Exception e) {
                                        }
                                    }
                                });
                                b2.setNegativeButton(android.R.string.no, new OnClickListener() {
                                    @Override
                                    public void onClick(final DialogInterface dialog, int which) {
                                        if (BuildConfig.DEBUG) Logger.log("no reboot");
                                        try {
                                            dialog.dismiss();
                                        } catch (Exception e) {
                                        }
                                    }
                                });
                                b2.create().show();
                            } else {
                                ap.activity.showErrorDialog(appName + " could not be moved");
                            }
                        }
                    } catch (Exception e) {
                        ap.activity.showErrorDialog(e.getClass().getName() + " " + e.getMessage());
                        e.printStackTrace();
                        if (BuildConfig.DEBUG) Logger.log(e);
                    } finally {
                        RootTools.remount("/system", "ro");
                        RootTools.remount("/mnt", "ro");
                    }
                } else {
                    if (BuildConfig.DEBUG) Logger.log("can not remount /system");
                    ap.activity.showErrorDialog("Could not remount /system");
                }
            }
        });
        b.setNegativeButton(android.R.string.no, new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                try {
                    dialog.dismiss();
                } catch (Exception e) {
                }
            }
        });
        b.create().show();
    }
}




Java Source Code List

de.j4velin.systemappmover.AppClickListener.java
de.j4velin.systemappmover.AppPicker.java
de.j4velin.systemappmover.EfficientAdapter.java
de.j4velin.systemappmover.Logger.java
de.j4velin.systemappmover.MoverActivity.java