OSDN Git Service

Add MIPS support
[android-x86/external-koush-Superuser.git] / Superuser / src / com / koushikdutta / superuser / MainActivity.java
index 51f8b7e..dc14acd 100644 (file)
-package com.koushikdutta.superuser;
+/*
+ * Copyright (C) 2013 Koushik Dutta (@koush)
+ *
+ * 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.
+ */
 
-import java.util.ArrayList;
+package com.koushikdutta.superuser;
 
-import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
-import android.support.v4.app.DialogFragment;
-import android.text.format.DateFormat;
+import android.util.Log;
+import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.MenuItem.OnMenuItemClickListener;
-import android.view.View;
-import android.widget.ImageView;
 
-import com.koushikdutta.superuser.db.SuDatabaseHelper;
-import com.koushikdutta.superuser.db.UidPolicy;
+import com.koushikdutta.superuser.util.Settings;
+import com.koushikdutta.superuser.util.StreamUtility;
+import com.koushikdutta.superuser.util.SuHelper;
 import com.koushikdutta.widgets.BetterListActivity;
-import com.koushikdutta.widgets.BetterListFragment;
-import com.koushikdutta.widgets.ListContentFragment;
-import com.koushikdutta.widgets.ListItem;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
 
 public class MainActivity extends BetterListActivity {
     public MainActivity() {
-        super(ListContentFragment.class);
+        super(PolicyFragment.class);
     }
 
-    public ListContentFragment getFragment() {
-        return (ListContentFragment)super.getFragment();
+    public PolicyFragmentInternal getFragment() {
+        return (PolicyFragmentInternal)super.getFragment();
     }
     
-    void showAllLogs() {
-        setContent(null, null);
-        getFragment().getListView().clearChoices();
-    }
-    
-    public boolean onCreateOptionsMenu(android.view.Menu menu) {
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
         MenuInflater mi = new MenuInflater(this);
-        mi.inflate(R.menu.main, menu);
-        MenuItem log = menu.findItem(R.id.logs);
-        log.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+        mi.inflate(R.menu.app, menu);
+        MenuItem about = menu.findItem(R.id.about);
+        about.setOnMenuItemClickListener(new OnMenuItemClickListener() {
             @Override
             public boolean onMenuItemClick(MenuItem item) {
-                showAllLogs();
+                getFragment().setContent(new AboutFragment(), true, getString(R.string.about));
                 return true;
             }
         });
         
-        MenuItem settings = menu.findItem(R.id.settings);
-        settings.setOnMenuItemClickListener(new OnMenuItemClickListener() {
-            @Override
-            public boolean onMenuItemClick(final MenuItem item) {
-                getFragment().setContent(new SettingsFragment() {
-                    @Override
-                    public void onConfigurationChanged(Configuration newConfig) {
-                        super.onConfigurationChanged(newConfig);
-                        onMenuItemClick(item);
-                    }
-                }, true);
-                return true;
-            }
-        });
         return super.onCreateOptionsMenu(menu);
     }
+
+    private String getArch() {
+        String prop = System.getProperty("os.arch");
+        if (prop.contains("x86") || prop.contains("i686") || prop.contains("i386")) {
+            return "x86";
+        } else if (prop.contains("mips")) {
+            return "mips";
+        } else {
+            return "armeabi";
+        }
+    }
     
-    BetterListFragment mContent;
-    @Override
-    public void onCreate(Bundle savedInstanceState, View view) {
-        super.onCreate(savedInstanceState, view);
+    File extractSu() throws IOException, InterruptedException {
+        ZipFile zf = new ZipFile(getPackageCodePath());
+        ZipEntry su = zf.getEntry("assets/" + getArch() + "/su");
+        InputStream zin = zf.getInputStream(su);
+        File ret = getFileStreamPath("su");
+        FileOutputStream fout = new FileOutputStream(ret);
+        StreamUtility.copyStream(zin, fout);
+        zin.close();
+        zf.close();
+        fout.close();
+        return ret;
+    }
 
-        getFragment().setEmpty(R.string.no_apps);
-        
-        load();
+    void doRecoveryInstall() {
+        final ProgressDialog dlg = new ProgressDialog(this);
+        dlg.setTitle(R.string.installing);
+        dlg.setMessage(getString(R.string.installing_superuser));
+        dlg.setIndeterminate(true);
+        dlg.show();
+        new Thread() {
+            void doEntry(ZipOutputStream zout, String entryName, String dest) throws IOException {
+                ZipFile zf = new ZipFile(getPackageCodePath());
+                ZipEntry ze = zf.getEntry(entryName);
+                zout.putNextEntry(new ZipEntry(dest));
+                InputStream in;
+                StreamUtility.copyStream(in = zf.getInputStream(ze), zout);
+                zout.closeEntry();
+                in.close();
+                zf.close();
+            }
+            
+            public void run() {
+                try {
+                    File zip = getFileStreamPath("superuser.zip");
+                    ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zip));
+                    doEntry(zout, "assets/update-binary", "META-INF/com/google/android/update-binary");
+                    doEntry(zout, "assets/install-recovery.sh", "install-recovery.sh");
+                    zout.close();
+
+                    ZipFile zf = new ZipFile(getPackageCodePath());
+                    ZipEntry ze = zf.getEntry("assets/" + getArch() + "/reboot");
+                    InputStream in;
+                    FileOutputStream reboot;
+                    StreamUtility.copyStream(in = zf.getInputStream(ze), reboot = openFileOutput("reboot", MODE_PRIVATE));
+                    reboot.close();
+                    in.close();
+
+                    final File su = extractSu();
 
-        ImageView watermark = (ImageView)view.findViewById(R.id.watermark);
-        if (watermark != null)
-            watermark.setImageResource(R.drawable.clockwork512);
-        if (!getFragment().isPaged())
-            showAllLogs();
+                    String command =
+                            String.format("cat %s > /cache/superuser.zip\n", zip.getAbsolutePath()) +
+                            String.format("cat %s > /cache/su\n", su.getAbsolutePath()) +
+                            String.format("cat %s > /cache/Superuser.apk\n", getPackageCodePath()) +
+                            "mkdir /cache/recovery\n" +
+                            "echo '--update_package=CACHE:superuser.zip' > /cache/recovery/command\n" +
+                            "chmod 644 /cache/superuser.zip\n" +
+                            "chmod 644 /cache/recovery/command\n" +
+                            "sync\n" +
+                            String.format("chmod 755 %s\n", getFileStreamPath("reboot").getAbsolutePath()) +
+                            "reboot recovery\n";
+                    Process p = Runtime.getRuntime().exec("su");
+                    p.getOutputStream().write(command.getBytes());
+                    p.getOutputStream().close();
+                    File rebootScript = getFileStreamPath("reboot.sh");
+                    StreamUtility.writeFile(rebootScript, "reboot recovery ; " + getFileStreamPath("reboot").getAbsolutePath() + " recovery ;");
+                    p.waitFor();
+                    Runtime.getRuntime().exec(new String[] { "su", "-c", ". " + rebootScript.getAbsolutePath() });
+                    if (p.waitFor() != 0)
+                        throw new Exception("non zero result");
+                }
+                catch (Exception ex) {
+                    ex.printStackTrace();
+                    dlg.dismiss();
+
+                    runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
+                            builder.setPositiveButton(android.R.string.ok, null);
+                            builder.setTitle(R.string.install);
+                            builder.setMessage(R.string.install_error);
+                            builder.create().show();
+                        }
+                    });
+                }
+            }
+        }.start();
     }
     
-    public void onBackPressed() {
-        if (getFragment().onBackPressed())
-            return;
-        super.onBackPressed();
-    };
+    void doSystemInstall() {
+        final ProgressDialog dlg = new ProgressDialog(this);
+        dlg.setTitle(R.string.installing);
+        dlg.setMessage(getString(R.string.installing_superuser));
+        dlg.setIndeterminate(true);
+        dlg.show();
+        new Thread() {
+            public void run() {
+                boolean _error = false;
+                try {
+                    final File su = extractSu();
+                    final String command =
+                            "mount -orw,remount /system\n" +
+                            "rm /system/xbin/su\n" +
+                            "rm /system/bin/su\n" +
+                            "rm /system/app/Supersu.*\n" +
+                            "rm /system/app/superuser.*\n" +
+                            "rm /system/app/supersu.*\n" +
+                            "rm /system/app/SuperUser.*\n" +
+                            "rm /system/app/SuperSU.*\n" +
+                            String.format("cat %s > /system/xbin/su\n", su.getAbsolutePath()) +
+                            "chmod 6755 /system/xbin/su\n" +
+                            "ln -s /system/xbin/su /system/bin/su\n" +
+                            "mount -oro,remount /system\n" +
+                            "sync\n";
+                    Process p = Runtime.getRuntime().exec("su");
+                    p.getOutputStream().write(command.getBytes());
+                    p.getOutputStream().close();
+                    if (p.waitFor() != 0)
+                        throw new Exception("non zero result");
+                    SuHelper.checkSu(MainActivity.this);
+                }
+                catch (Exception ex) {
+                    _error = true;
+                    Log.e("Superuser", "error upgrading", ex);
+                }
+                dlg.dismiss();
+                final boolean error = _error;
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
+                        builder.setPositiveButton(android.R.string.ok, null);
+                        builder.setTitle(R.string.install);
+                        
+                        if (error) {
+                            builder.setMessage(R.string.install_error);
+                        }
+                        else {
+                            builder.setMessage(R.string.install_success);
+                        }
+                        builder.create().show();
+                    }
+                });
+            };
+        }.start();
+    }
     
-    void setContent(final ListItem li, final UidPolicy up) {
-        mContent = new LogFragment() {
+    void doInstall() {
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle(R.string.install);
+        builder.setMessage(R.string.install_superuser_info);
+        if (Build.VERSION.SDK_INT < 18) {
+            builder.setPositiveButton(R.string.install, new OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    doSystemInstall();
+                }
+            });
+        }
+        builder.setNegativeButton(android.R.string.cancel, null);
+        builder.setNeutralButton(R.string.recovery_install, new OnClickListener() {
             @Override
-            void onDelete() {
-                super.onDelete();
-                getFragment().removeItem(li);
-                showAllLogs();
+            public void onClick(DialogInterface dialog, int which) {
+                doRecoveryInstall();
             }
-
+        });
+        builder.create().show();
+    }
+    
+    private void saveWhatsNew() {
+        Settings.setString(this, "whats_new", WHATS_NEW);
+    }
+    
+    // this is intentionally not localized as it will change constantly.
+    private static final String WHATS_NEW = "Added support for Android 4.3.";
+    protected void doWhatsNew() {
+        if (WHATS_NEW.equals(Settings.getString(this, "whats_new")))
+            return;
+        saveWhatsNew();
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle(R.string.whats_new);
+        builder.setIcon(R.drawable.ic_launcher);
+        builder.setMessage(WHATS_NEW);
+        builder.setPositiveButton(R.string.rate, new OnClickListener() {
             @Override
-            public void onConfigurationChanged(Configuration newConfig) {
-                super.onConfigurationChanged(newConfig);
-                setContent(li, up);
+            public void onClick(DialogInterface dialog, int which) {
+                Intent i = new Intent();
+                i.setData(Uri.parse("market://details?id=com.koushikdutta.superuser"));
+                startActivity(i);
             }
-        }
-        .setUidPolicy(up);
-        getFragment().setContent(mContent, up == null);
-    }
-
-    void addPolicy(final UidPolicy up) {
-        java.text.DateFormat df = DateFormat.getLongDateFormat(MainActivity.this);
-        String date = df.format(up.getLastDate());
-        if (up.last == 0)
-            date = null;
-        ListItem li = addItem(up.getPolicyResource(), new ListItem(getFragment(), up.name, date) {
-            public void onClick(View view) {
-                super.onClick(view);
-
-                setContent(this, up);
-            };
         });
-        Drawable icon = UidHelper.loadPackageIcon(this, up.packageName);
-        if (icon == null)
-            li.setIcon(R.drawable.ic_launcher);
-        else
-            li.setDrawable(icon);
+        builder.setNegativeButton(android.R.string.cancel, null);
+        builder.create().show();
     }
-    
-    Handler mHandler = new Handler();
-    void load() {
-        final ArrayList<UidPolicy> policies = SuDatabaseHelper.getPolicies(MainActivity.this);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Settings.applyDarkThemeSetting(this, R.style.SuperuserDarkActivity);
+        super.onCreate(savedInstanceState);
         
-        for (UidPolicy up: policies) {
-            addPolicy(up);
+        if (Settings.getBoolean(this, "first_run", true)) {
+            saveWhatsNew();
+            Settings.setBoolean(this, "first_run", false);
         }
+        
+        final ProgressDialog dlg = new ProgressDialog(this);
+        dlg.setTitle(R.string.superuser);
+        dlg.setMessage(getString(R.string.checking_superuser));
+        dlg.setIndeterminate(true);
+        dlg.show();
+        new Thread() {
+            public void run() {
+                boolean _error = false;
+                try {
+                    SuHelper.checkSu(MainActivity.this);
+                }
+                catch (Exception e) {
+                    e.printStackTrace();
+                    _error = true;
+                }
+                final boolean error = _error;
+                dlg.dismiss();
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (error) {
+                            doInstall();
+                        }
+                        else {
+                            doWhatsNew();
+                        }
+                    }
+                });
+            };
+        }.start();
     }
 }