OSDN Git Service

Add dark theme option.
[android-x86/external-koush-Superuser.git] / Superuser / src / com / koushikdutta / superuser / util / Settings.java
1 package com.koushikdutta.superuser.util;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.DataInputStream;
5 import java.io.DataOutputStream;
6 import java.io.File;
7 import java.io.FileInputStream;
8 import java.io.FileOutputStream;
9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.lang.reflect.Method;
12 import java.security.MessageDigest;
13
14 import android.app.Activity;
15 import android.content.ContentValues;
16 import android.content.Context;
17 import android.database.Cursor;
18 import android.database.sqlite.SQLiteDatabase;
19 import android.os.Build;
20 import android.text.TextUtils;
21 import android.util.Base64;
22
23 import com.koushikdutta.superuser.Helper;
24 import com.koushikdutta.superuser.db.SuperuserDatabaseHelper;
25
26 public class Settings {
27     SQLiteDatabase mDatabase;
28     Context mContext;
29
30     public static void setString(Context context, String name, String value) {
31         ContentValues cv = new ContentValues();
32         cv.put("key", name);
33         cv.put("value", value);
34         SQLiteDatabase db = new SuperuserDatabaseHelper(context).getWritableDatabase();
35         try {
36             db.replace("settings", null, cv);
37         }
38         finally {
39             db.close();
40         }
41     }
42
43     public static String getString(Context context, String name) {
44         return getString(context, name, null);
45     }
46
47     public static String getString(Context context, String name, String defaultValue) {
48         SQLiteDatabase db = new SuperuserDatabaseHelper(context).getReadableDatabase();
49         Cursor cursor = db.query("settings", new String[] { "value" }, "key='" + name + "'", null, null, null, null);
50         try {
51             if (cursor.moveToNext())
52                 return cursor.getString(0);
53         }
54         finally {
55             cursor.close();
56             db.close();
57         }
58         return defaultValue;
59     }
60
61     public static void setInt(Context context, String name, int value) {
62         setString(context, name, ((Integer) value).toString());
63     }
64
65     public static int getInt(Context context, String name, int defaultValue) {
66         try {
67             return Integer.parseInt(getString(context, name, null));
68         }
69         catch (Exception ex) {
70             return defaultValue;
71         }
72     }
73
74     public static void setLong(Context context, String name, long value) {
75         setString(context, name, ((Long) value).toString());
76     }
77
78     public static long getLong(Context context, String name, long defaultValue) {
79         try {
80             return Long.parseLong(getString(context, name, null));
81         }
82         catch (Exception ex) {
83             return defaultValue;
84         }
85     }
86
87     public static void setBoolean(Context context, String name, boolean value) {
88         setString(context, name, ((Boolean) value).toString());
89     }
90
91     public static boolean getBoolean(Context context, String name, boolean defaultValue) {
92         try {
93             return Boolean.parseBoolean(getString(context, name, ((Boolean) defaultValue).toString()));
94         }
95         catch (Exception ex) {
96             ex.printStackTrace();
97             return defaultValue;
98         }
99     }
100     
101     private static final String KEY_LOGGING = "logging";
102     public static boolean getLogging(Context context) {
103         return getBoolean(context, KEY_LOGGING, true);
104     }
105     
106     public static void setLogging(Context context, boolean logging) {
107         setBoolean(context, KEY_LOGGING, logging);
108     }
109     
110     private static final String KEY_TIMEOUT = "timeout";
111     public static final int REQUEST_TIMEOUT_DEFAULT = 30;
112     public static int getRequestTimeout(Context context) {
113         return getInt(context, KEY_TIMEOUT, REQUEST_TIMEOUT_DEFAULT);
114     }
115     
116     public static void setTimeout(Context context, int timeout) {
117         setInt(context, KEY_TIMEOUT, timeout);
118     }
119
120     private static final String KEY_NOTIFICATION = "notification";
121     public static final int NOTIFICATION_TYPE_NONE = 0;
122     public static final int NOTIFICATION_TYPE_TOAST = 1;
123     public static final int NOTIFICATION_TYPE_NOTIFICATION = 2;
124     public static final int NOTIFICATION_TYPE_DEFAULT = NOTIFICATION_TYPE_TOAST;
125     public static int getNotificationType(Context context) {
126         switch (getInt(context, KEY_NOTIFICATION, NOTIFICATION_TYPE_DEFAULT)) {
127         case NOTIFICATION_TYPE_NONE:
128             return NOTIFICATION_TYPE_NONE;
129         case NOTIFICATION_TYPE_NOTIFICATION:
130             return NOTIFICATION_TYPE_NOTIFICATION;
131         case NOTIFICATION_TYPE_TOAST:
132             return NOTIFICATION_TYPE_TOAST;
133         default:
134             return NOTIFICATION_TYPE_DEFAULT;
135         }
136     }
137     
138     public static void setNotificationType(Context context, int notification) {
139         setInt(context, KEY_NOTIFICATION, notification);
140     }
141     
142     public static final String KEY_PIN = "pin";
143     public static final boolean isPinProtected(Context context) {
144         return Settings.getString(context, KEY_PIN) != null;
145     }
146     
147     private static String digest(String value) {
148         // ok, there's honestly no point in digesting the pin.
149         // if someone gets a hold of the hash, there's really only like
150         // 10^n possible values to brute force, where N is generally
151         // 4. Ie, 10000. Yay, security theater. This really ought
152         // to be a password.
153         if (TextUtils.isEmpty(value))
154             return null;
155         try {
156             MessageDigest digester = MessageDigest.getInstance("MD5");
157             return Base64.encodeToString(digester.digest(value.getBytes()), Base64.DEFAULT);
158         }
159         catch (Exception e) {
160             return value;
161         }
162     }
163     
164     public static void setPin(Context context, String pin) {
165         Settings.setString(context, KEY_PIN, digest(pin));
166     }
167     
168     public static boolean checkPin(Context context, String pin) {
169         pin = digest(pin);
170         String hashed = Settings.getString(context, KEY_PIN);
171         if (TextUtils.isEmpty(pin))
172             return TextUtils.isEmpty(hashed);
173         return pin.equals(hashed);
174     }
175
176     private static final String KEY_REQUIRE_PREMISSION = "require_permission";
177     public static boolean getRequirePermission(Context context) {
178         return getBoolean(context, KEY_REQUIRE_PREMISSION, false);
179     }
180     
181     public static void setRequirePermission(Context context, boolean require) {
182         setBoolean(context, KEY_REQUIRE_PREMISSION, require);
183     }
184     
185     private static final String KEY_AUTOMATIC_RESPONSE = "automatic_response";
186     public static final int AUTOMATIC_RESPONSE_PROMPT = 0;
187     public static final int AUTOMATIC_RESPONSE_ALLOW = 1;
188     public static final int AUTOMATIC_RESPONSE_DENY = 2;
189     public static final int AUTOMATIC_RESPONSE_DEFAULT = AUTOMATIC_RESPONSE_PROMPT;
190     public static int getAutomaticResponse(Context context) {
191         switch (getInt(context, KEY_AUTOMATIC_RESPONSE, AUTOMATIC_RESPONSE_DEFAULT)) {
192         case AUTOMATIC_RESPONSE_ALLOW:
193             return AUTOMATIC_RESPONSE_ALLOW;
194         case AUTOMATIC_RESPONSE_PROMPT:
195             return AUTOMATIC_RESPONSE_PROMPT;
196         case AUTOMATIC_RESPONSE_DENY:
197             return AUTOMATIC_RESPONSE_DENY;
198         default:
199             return AUTOMATIC_RESPONSE_DEFAULT;
200         }
201     }
202
203     public static void setAutomaticResponse(Context context, int response) {
204         setInt(context, KEY_AUTOMATIC_RESPONSE, response);
205     }
206     
207     
208     static public String readFile(String filename) throws IOException {
209         return readFile(new File(filename));
210     }
211     
212     static public String readFile(File file) throws IOException {
213         byte[] buffer = new byte[(int) file.length()];
214         DataInputStream input = new DataInputStream(new FileInputStream(file));
215         input.readFully(buffer);
216         input.close();
217         return new String(buffer);
218     }
219     
220     public static void writeFile(File file, String string) throws IOException {
221         writeFile(file.getAbsolutePath(), string);
222     }
223     
224     public static void writeFile(String file, String string) throws IOException {
225         File f = new File(file);
226         f.getParentFile().mkdirs();
227         DataOutputStream dout = new DataOutputStream(new FileOutputStream(f));
228         dout.write(string.getBytes());
229         dout.close();
230     }
231     
232     public static byte[] readToEndAsArray(InputStream input) throws IOException {
233         DataInputStream dis = new DataInputStream(input);
234         byte[] stuff = new byte[1024];
235         ByteArrayOutputStream buff = new ByteArrayOutputStream();
236         int read = 0;
237         while ((read = dis.read(stuff)) != -1)
238         {
239             buff.write(stuff, 0, read);
240         }
241         input.close();
242         return buff.toByteArray();
243     }
244
245     public static String readToEnd(InputStream input) throws IOException {
246         return new String(readToEndAsArray(input));
247     }
248
249     public static final int MULTIUSER_MODE_OWNER_ONLY = 0;
250     public static final int MULTIUSER_MODE_OWNER_MANAGED = 1;
251     public static final int MULTIUSER_MODE_USER = 2;
252     public static final int MULTIUSER_MODE_NONE = 3;
253     
254     private static final String MULTIUSER_VALUE_OWNER_ONLY  = "owner";
255     private static final String MULTIUSER_VALUE_OWNER_MANAGED = "managed";
256     private static final String MULTIUSER_VALUE_USER = "user";
257
258     public static final int getMultiuserMode(Context context) {
259         if (Build.VERSION.SDK_INT < 17)
260             return MULTIUSER_MODE_NONE;
261
262         if (!Helper.supportsMultipleUsers(context))
263             return MULTIUSER_MODE_NONE;
264         
265         try {
266             String mode;
267             if (Helper.isAdminUser(context)) {
268                 File file = context.getFileStreamPath("multiuser_mode");
269                 mode = readFile(file);
270             }
271             else {
272                 Process p = Runtime.getRuntime().exec("su -u");
273                 mode = readToEnd(p.getInputStream()).trim();
274             }
275             
276             if (MULTIUSER_VALUE_OWNER_MANAGED.equals(mode))
277                 return MULTIUSER_MODE_OWNER_MANAGED;
278             if (MULTIUSER_VALUE_USER.equals(mode))
279                 return MULTIUSER_MODE_USER;
280             if (MULTIUSER_VALUE_OWNER_ONLY.equals(mode))
281                 return MULTIUSER_MODE_OWNER_ONLY;
282         }
283         catch (Exception e) {
284         }
285         return MULTIUSER_MODE_OWNER_ONLY;
286     }
287     
288     public static void setMultiuserMode(Context context, int mode) {
289         if (!Helper.isAdminUser(context))
290             return;
291         try {
292             File file = context.getFileStreamPath("multiuser_mode");
293             switch (mode) {
294             case MULTIUSER_MODE_OWNER_MANAGED:
295                 writeFile(file, MULTIUSER_VALUE_OWNER_MANAGED);
296                 break;
297             case MULTIUSER_MODE_USER:
298                 writeFile(file, MULTIUSER_VALUE_USER);
299                 break;
300             case MULTIUSER_MODE_NONE:
301                 file.delete();
302                 break;
303             default:
304                 writeFile(file, MULTIUSER_VALUE_OWNER_ONLY);
305                 break;
306             }
307         }
308         catch (Exception ex) {
309         }
310     }
311     
312     
313     public static final int SUPERUSER_ACCESS_DISABLED = 0;
314     public static final int SUPERUSER_ACCESS_APPS_ONLY = 1;
315     public static final int SUPERUSER_ACCESS_ADB_ONLY = 2;
316     public static final int SUPERUSER_ACCESS_APPS_AND_ADB = 3;
317     public static int getSuperuserAccess() {
318         try {
319             Class c = Class.forName("android.os.SystemProperties");
320             Method m = c.getMethod("get", String.class);
321             String value = (String)m.invoke(null, "persist.sys.root_access");
322             int val = Integer.valueOf(value);
323             switch (val) {
324             case SUPERUSER_ACCESS_DISABLED:
325             case SUPERUSER_ACCESS_APPS_ONLY:
326             case SUPERUSER_ACCESS_ADB_ONLY:
327             case SUPERUSER_ACCESS_APPS_AND_ADB:
328                 return val;
329             default:
330                 return SUPERUSER_ACCESS_APPS_AND_ADB;
331             }
332         }
333         catch (Exception e) {
334             return SUPERUSER_ACCESS_APPS_AND_ADB;
335         }
336     }
337     
338     public static void setSuperuserAccess(int mode) {
339         // TODO: fallback to using SystemProperties.set if this has system uid (ie, embedded)
340         try {
341             String command = "setprop persist.sys.root_access " + mode;
342             Process p = Runtime.getRuntime().exec("su");
343             p.getOutputStream().write(command.getBytes());
344             p.getOutputStream().close();
345             p.waitFor();
346         }
347         catch (Exception ex) {
348         }
349     }
350     
351     private static final String CHECK_SU_QUIET = "check_su_quiet";
352     public static final int getCheckSuQuietCounter(Context context) {
353         return getInt(context, CHECK_SU_QUIET, 0);
354     }
355     
356     public static final void setCheckSuQuietCounter(Context context, int counter) {
357         setInt(context, CHECK_SU_QUIET, counter);
358     }
359     
360     private static final String KEY_THEME = "theme";
361     public static final int THEME_LIGHT = 0;
362     public static final int THEME_DARK = 1;
363     public static void applyDarkThemeSetting(Activity activity, int dark) {
364         if (!"com.koushikdutta.superuser".equals(activity.getPackageName()))
365             return;
366         try {
367             if (getTheme(activity) == THEME_DARK)
368                 activity.setTheme(dark);
369         }
370         catch (Exception e) {
371         }
372     }
373     
374     public static final int getTheme(Context context) {
375         return getInt(context, KEY_THEME, THEME_LIGHT);
376     }
377     
378     public static final void setTheme(Context context, int theme) {
379         setInt(context, KEY_THEME, theme);
380     }
381 }