OSDN Git Service

Merge "Add Superuser uk translation" into cm-10.1
[android-x86/external-koush-Superuser.git] / Superuser / src / com / koushikdutta / superuser / MainActivity.java
1 /*
2  * Copyright (C) 2013 Koushik Dutta (@koush)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.koushikdutta.superuser;
18
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.zip.ZipEntry;
24 import java.util.zip.ZipFile;
25 import java.util.zip.ZipOutputStream;
26
27 import android.app.AlertDialog;
28 import android.app.ProgressDialog;
29 import android.content.DialogInterface;
30 import android.content.Intent;
31 import android.content.DialogInterface.OnClickListener;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.view.Menu;
35 import android.view.MenuInflater;
36 import android.view.MenuItem;
37 import android.view.MenuItem.OnMenuItemClickListener;
38
39 import com.koushikdutta.superuser.util.Settings;
40 import com.koushikdutta.superuser.util.StreamUtility;
41 import com.koushikdutta.superuser.util.SuHelper;
42 import com.koushikdutta.widgets.BetterListActivity;
43
44 public class MainActivity extends BetterListActivity {
45     public MainActivity() {
46         super(PolicyFragment.class);
47     }
48
49     public PolicyFragmentInternal getFragment() {
50         return (PolicyFragmentInternal)super.getFragment();
51     }
52     
53     @Override
54     public boolean onCreateOptionsMenu(Menu menu) {
55         MenuInflater mi = new MenuInflater(this);
56         mi.inflate(R.menu.app, menu);
57         MenuItem about = menu.findItem(R.id.about);
58         about.setOnMenuItemClickListener(new OnMenuItemClickListener() {
59             @Override
60             public boolean onMenuItemClick(MenuItem item) {
61                 getFragment().setContent(new AboutFragment(), true, getString(R.string.about));
62                 return true;
63             }
64         });
65         
66         return super.onCreateOptionsMenu(menu);
67     }
68     
69     File extractSu() throws IOException, InterruptedException {
70         String arch = "armeabi";
71         if (System.getProperty("os.arch").contains("x86") || System.getProperty("os.arch").contains("i686") || System.getProperty("os.arch").contains("i386"))
72             arch = "x86";
73         ZipFile zf = new ZipFile(getPackageCodePath());
74         ZipEntry su = zf.getEntry("assets/" + arch + "/su");
75         InputStream zin = zf.getInputStream(su);
76         File ret = getFileStreamPath("su");
77         FileOutputStream fout = new FileOutputStream(ret);
78         StreamUtility.copyStream(zin, fout);
79         zin.close();
80         zf.close();
81         fout.close();
82         return ret;
83     }
84     
85     void doRecoveryInstall() {
86         final ProgressDialog dlg = new ProgressDialog(this);
87         dlg.setTitle(R.string.installing);
88         dlg.setMessage(getString(R.string.installing_superuser));
89         dlg.setIndeterminate(true);
90         dlg.show();
91         new Thread() {
92             void doEntry(ZipOutputStream zout, String entryName, String dest) throws IOException {
93                 ZipFile zf = new ZipFile(getPackageCodePath());
94                 ZipEntry ze = zf.getEntry(entryName);
95                 zout.putNextEntry(new ZipEntry(dest));
96                 InputStream in;
97                 StreamUtility.copyStream(in = zf.getInputStream(ze), zout);
98                 zout.closeEntry();
99                 in.close();
100                 zf.close();
101             }
102             
103             public void run() {
104                 try {
105                     File zip = getFileStreamPath("superuser.zip");
106                     ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zip));
107                     doEntry(zout, "assets/update-binary", "META-INF/com/google/android/update-binary");
108                     zout.close();
109
110                     final File su = extractSu();
111
112                     String command =
113                             String.format("cat %s > /cache/superuser.zip\n", zip.getAbsolutePath()) +
114                             String.format("cat %s > /cache/su\n", su.getAbsolutePath()) +
115                             String.format("cat %s > /cache/Superuser.apk\n", getPackageCodePath()) +
116                             "mkdir /cache/recovery\n" +
117                             "echo '--update_package=CACHE:superuser.zip' > /cache/recovery/command\n" +
118                             "chmod 644 /cache/superuser.zip\n" +
119                             "chmod 644 /cache/recovery/command\n" +
120                             "sync\n" +
121                             "reboot recovery\n";
122                     Process p = Runtime.getRuntime().exec("su");
123                     p.getOutputStream().write(command.getBytes());
124                     p.getOutputStream().close();
125                     if (p.waitFor() != 0)
126                         throw new Exception("non zero result");
127                 }
128                 catch (Exception ex) {
129                     ex.printStackTrace();
130                     dlg.dismiss();
131
132                     runOnUiThread(new Runnable() {
133                         @Override
134                         public void run() {
135                             AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
136                             builder.setPositiveButton(android.R.string.ok, null);
137                             builder.setTitle(R.string.install);
138                             builder.setMessage(R.string.install_error);
139                             builder.create().show();
140                         }
141                     });
142                 }
143             }
144         }.start();
145     }
146     
147     void doSystemInstall() {
148         final ProgressDialog dlg = new ProgressDialog(this);
149         dlg.setTitle(R.string.installing);
150         dlg.setMessage(getString(R.string.installing_superuser));
151         dlg.setIndeterminate(true);
152         dlg.show();
153         new Thread() {
154             public void run() {
155                 boolean _error = false;
156                 try {
157                     final File su = extractSu();
158                     final String command =
159                             "mount -orw,remount /system\n" +
160                             "rm /system/xbin/su\n" +
161                             "rm /system/bin/su\n" +
162                             "rm /system/app/Supersu.*\n" +
163                             "rm /system/app/superuser.*\n" +
164                             "rm /system/app/supersu.*\n" +
165                             "rm /system/app/SuperUser.*\n" +
166                             "rm /system/app/SuperSU.*\n" +
167                             String.format("cat %s > /system/xbin/su\n", su.getAbsolutePath()) +
168                             "chmod 6755 /system/xbin/su\n" +
169                             "ln -s /system/xbin/su /system/bin/su\n" +
170                             "mount -oro,remount /system\n" +
171                             "sync\n";
172                     Process p = Runtime.getRuntime().exec("su");
173                     p.getOutputStream().write(command.getBytes());
174                     p.getOutputStream().close();
175                     if (p.waitFor() != 0)
176                         throw new Exception("non zero result");
177                     SuHelper.checkSu(MainActivity.this);
178                 }
179                 catch (Exception ex) {
180                     _error = true;
181                     ex.printStackTrace();
182                 }
183                 dlg.dismiss();
184                 final boolean error = _error;
185                 runOnUiThread(new Runnable() {
186                     @Override
187                     public void run() {
188                         AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
189                         builder.setPositiveButton(android.R.string.ok, null);
190                         builder.setTitle(R.string.install);
191                         
192                         if (error) {
193                             builder.setMessage(R.string.install_error);
194                         }
195                         else {
196                             builder.setMessage(R.string.install_success);
197                         }
198                         builder.create().show();
199                     }
200                 });
201             };
202         }.start();
203     }
204     
205     void doInstall() {
206         AlertDialog.Builder builder = new AlertDialog.Builder(this);
207         builder.setTitle(R.string.install);
208         builder.setMessage(R.string.install_superuser_info);
209         builder.setPositiveButton(R.string.install, new OnClickListener() {
210             @Override
211             public void onClick(DialogInterface dialog, int which) {
212                 doSystemInstall();
213             }
214         });
215         builder.setNegativeButton(android.R.string.cancel, null);
216         builder.setNeutralButton(R.string.recovery_install, new OnClickListener() {
217             @Override
218             public void onClick(DialogInterface dialog, int which) {
219                 doRecoveryInstall();
220             }
221         });
222         builder.create().show();
223     }
224     
225     private void saveWhatsNew() {
226         Settings.setString(this, "whats_new", WHATS_NEW);
227     }
228     
229     // this is intentionally not localized as it will change constantly.
230     private static final String WHATS_NEW = "This update includes a security fix. See Google Play release notes for more information.";
231     protected void doWhatsNew() {
232         if (WHATS_NEW.equals(Settings.getString(this, "whats_new")))
233             return;
234         saveWhatsNew();
235         AlertDialog.Builder builder = new AlertDialog.Builder(this);
236         builder.setTitle(R.string.whats_new);
237         builder.setIcon(R.drawable.ic_launcher);
238         builder.setMessage(WHATS_NEW);
239         builder.setPositiveButton(R.string.rate, new OnClickListener() {
240             @Override
241             public void onClick(DialogInterface dialog, int which) {
242                 Intent i = new Intent();
243                 i.setData(Uri.parse("market://details?id=com.koushikdutta.superuser"));
244                 startActivity(i);
245             }
246         });
247         builder.setNegativeButton(android.R.string.cancel, null);
248         builder.create().show();
249     }
250
251     @Override
252     protected void onCreate(Bundle savedInstanceState) {
253         Settings.applyDarkThemeSetting(this, R.style.SuperuserDarkActivity);
254         super.onCreate(savedInstanceState);
255         
256         if (Settings.getBoolean(this, "first_run", true)) {
257             saveWhatsNew();
258             Settings.setBoolean(this, "first_run", false);
259         }
260         
261         final ProgressDialog dlg = new ProgressDialog(this);
262         dlg.setTitle(R.string.superuser);
263         dlg.setMessage(getString(R.string.checking_superuser));
264         dlg.setIndeterminate(true);
265         dlg.show();
266         new Thread() {
267             public void run() {
268                 boolean _error = false;
269                 try {
270                     SuHelper.checkSu(MainActivity.this);
271                 }
272                 catch (Exception e) {
273                     e.printStackTrace();
274                     _error = true;
275                 }
276                 final boolean error = _error;
277                 dlg.dismiss();
278                 runOnUiThread(new Runnable() {
279                     @Override
280                     public void run() {
281                         if (error) {
282                             doInstall();
283                         }
284                         else {
285                             doWhatsNew();
286                         }
287                     }
288                 });
289             };
290         }.start();
291     }
292 }