OSDN Git Service

Merge pull request #3 from jchleb/master
[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.security.MessageDigest;
12
13 import android.content.ContentValues;
14 import android.content.Context;
15 import android.database.Cursor;
16 import android.database.sqlite.SQLiteDatabase;
17 import android.database.sqlite.SQLiteOpenHelper;
18 import android.os.Build;
19 import android.text.TextUtils;
20 import android.util.Base64;
21
22 import com.koushikdutta.superuser.Helper;
23
24 public class Settings {
25     SQLiteDatabase mDatabase;
26     Context mContext;
27
28     private Settings(Context context) {
29         mContext = context;
30         SQLiteOpenHelper helper = new SQLiteOpenHelper(mContext, "settings.db", null, 1) {
31             private final static String mDDL = "CREATE TABLE settings (key TEXT PRIMARY KEY, value TEXT);";
32
33             @Override
34             public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
35                 onCreate(db);
36             }
37
38             @Override
39             public void onCreate(SQLiteDatabase db) {
40                 db.execSQL(mDDL);
41             }
42         };
43         mDatabase = helper.getWritableDatabase();
44     }
45
46     private static Settings mInstance;
47
48     public static Settings getInstance(Context context) {
49         if (mInstance == null) {
50             mInstance = new Settings(context.getApplicationContext());
51         }
52         return mInstance;
53     }
54
55     public void setString(String name, String value) {
56         ContentValues cv = new ContentValues();
57         cv.put("key", name);
58         cv.put("value", value);
59         mDatabase.replace("settings", null, cv);
60     }
61
62     public String getString(String name) {
63         return getString(name, null);
64     }
65
66     public String getString(String name, String defaultValue) {
67         Cursor cursor = mDatabase.query("settings", new String[] { "value" }, "key='" + name + "'", null, null, null, null);
68         try {
69             if (cursor.moveToNext())
70                 return cursor.getString(0);
71         }
72         finally {
73             cursor.close();
74         }
75         return defaultValue;
76     }
77
78     public void setInt(String name, int value) {
79         setString(name, ((Integer) value).toString());
80     }
81
82     public int getInt(String name, int defaultValue) {
83         try {
84             return Integer.parseInt(getString(name, null));
85         }
86         catch (Exception ex) {
87             return defaultValue;
88         }
89     }
90
91     public void setLong(String name, long value) {
92         setString(name, ((Long) value).toString());
93     }
94
95     public long getLong(String name, long defaultValue) {
96         try {
97             return Long.parseLong(getString(name, null));
98         }
99         catch (Exception ex) {
100             return defaultValue;
101         }
102     }
103
104     public void setBoolean(String name, boolean value) {
105         setString(name, ((Boolean) value).toString());
106     }
107
108     public boolean getBoolean(String name, boolean defaultValue) {
109         try {
110             return Boolean.parseBoolean(getString(name, ((Boolean) defaultValue).toString()));
111         }
112         catch (Exception ex) {
113             ex.printStackTrace();
114             return defaultValue;
115         }
116     }
117     
118     private static final String KEY_LOGGING = "logging";
119     public static boolean getLogging(Context context) {
120         return getInstance(context).getBoolean(KEY_LOGGING, true);
121     }
122     
123     public static void setLogging(Context context, boolean logging) {
124         getInstance(context).setBoolean(KEY_LOGGING, logging);
125     }
126     
127     private static final String KEY_TIMEOUT = "timeout";
128     public static final int REQUEST_TIMEOUT_DEFAULT = 30;
129     public static int getRequestTimeout(Context context) {
130         return getInstance(context).getInt(KEY_TIMEOUT, REQUEST_TIMEOUT_DEFAULT);
131     }
132     
133     public static void setTimeout(Context context, int timeout) {
134         getInstance(context).setInt(KEY_TIMEOUT, timeout);
135     }
136
137     private static final String KEY_NOTIFICATION = "notification";
138     public static final int NOTIFICATION_TYPE_NONE = 0;
139     public static final int NOTIFICATION_TYPE_TOAST = 1;
140     public static final int NOTIFICATION_TYPE_NOTIFICATION = 2;
141     public static final int NOTIFICATION_TYPE_DEFAULT = NOTIFICATION_TYPE_TOAST;
142     public static int getNotificationType(Context context) {
143         switch (getInstance(context).getInt(KEY_NOTIFICATION, NOTIFICATION_TYPE_DEFAULT)) {
144         case NOTIFICATION_TYPE_NONE:
145             return NOTIFICATION_TYPE_NONE;
146         case NOTIFICATION_TYPE_NOTIFICATION:
147             return NOTIFICATION_TYPE_NOTIFICATION;
148         case NOTIFICATION_TYPE_TOAST:
149             return NOTIFICATION_TYPE_TOAST;
150         default:
151             return NOTIFICATION_TYPE_DEFAULT;
152         }
153     }
154     
155     public static void setNotificationType(Context context, int notification) {
156         getInstance(context).setInt(KEY_NOTIFICATION, notification);
157     }
158     
159     public static final String KEY_PIN = "pin";
160     public static final boolean isPinProtected(Context context) {
161         return Settings.getInstance(context).getString(KEY_PIN) != null;
162     }
163     
164     private static String digest(String value) {
165         // ok, there's honestly no point in digesting the pin.
166         // if someone gets a hold of the hash, there's really only like
167         // 10^n possible values to brute force, where N is generally
168         // 4. Ie, 10000. Yay, security theater. This really ought
169         // to be a password.
170         if (TextUtils.isEmpty(value))
171             return null;
172         try {
173             MessageDigest digester = MessageDigest.getInstance("MD5");
174             return Base64.encodeToString(digester.digest(value.getBytes()), Base64.DEFAULT);
175         }
176         catch (Exception e) {
177             return value;
178         }
179     }
180     
181     public static void setPin(Context context, String pin) {
182         Settings.getInstance(context).setString(KEY_PIN, digest(pin));
183     }
184     
185     public static boolean checkPin(Context context, String pin) {
186         pin = digest(pin);
187         String hashed = Settings.getInstance(context).getString(KEY_PIN);
188         if (TextUtils.isEmpty(pin))
189             return TextUtils.isEmpty(hashed);
190         return pin.equals(hashed);
191     }
192
193     private static final String KEY_REQUIRE_PREMISSION = "require_permission";
194     public static boolean getRequirePermission(Context context) {
195         return getInstance(context).getBoolean(KEY_REQUIRE_PREMISSION, false);
196     }
197     
198     public static void setRequirePermission(Context context, boolean require) {
199         getInstance(context).setBoolean(KEY_REQUIRE_PREMISSION, require);
200     }
201     
202     private static final String KEY_AUTOMATIC_RESPONSE = "automatic_response";
203     public static final int AUTOMATIC_RESPONSE_PROMPT = 0;
204     public static final int AUTOMATIC_RESPONSE_ALLOW = 1;
205     public static final int AUTOMATIC_RESPONSE_DENY = 2;
206     public static final int AUTOMATIC_RESPONSE_DEFAULT = AUTOMATIC_RESPONSE_PROMPT;
207     public static int getAutomaticResponse(Context context) {
208         switch (getInstance(context).getInt(KEY_AUTOMATIC_RESPONSE, AUTOMATIC_RESPONSE_DEFAULT)) {
209         case AUTOMATIC_RESPONSE_ALLOW:
210             return AUTOMATIC_RESPONSE_ALLOW;
211         case AUTOMATIC_RESPONSE_PROMPT:
212             return AUTOMATIC_RESPONSE_PROMPT;
213         case AUTOMATIC_RESPONSE_DENY:
214             return AUTOMATIC_RESPONSE_DENY;
215         default:
216             return AUTOMATIC_RESPONSE_DEFAULT;
217         }
218     }
219
220     public static void setAutomaticResponse(Context context, int response) {
221         getInstance(context).setInt(KEY_AUTOMATIC_RESPONSE, response);
222     }
223     
224     
225     static public String readFile(String filename) throws IOException {
226         return readFile(new File(filename));
227     }
228     
229     static public String readFile(File file) throws IOException {
230         byte[] buffer = new byte[(int) file.length()];
231         DataInputStream input = new DataInputStream(new FileInputStream(file));
232         input.readFully(buffer);
233         return new String(buffer);
234     }
235     
236     public static void writeFile(File file, String string) throws IOException {
237         writeFile(file.getAbsolutePath(), string);
238     }
239     
240     public static void writeFile(String file, String string) throws IOException {
241         File f = new File(file);
242         f.getParentFile().mkdirs();
243         DataOutputStream dout = new DataOutputStream(new FileOutputStream(f));
244         dout.write(string.getBytes());
245         dout.close();
246     }
247     
248     public static byte[] readToEndAsArray(InputStream input) throws IOException {
249         DataInputStream dis = new DataInputStream(input);
250         byte[] stuff = new byte[1024];
251         ByteArrayOutputStream buff = new ByteArrayOutputStream();
252         int read = 0;
253         while ((read = dis.read(stuff)) != -1)
254         {
255             buff.write(stuff, 0, read);
256         }
257         input.close();
258         return buff.toByteArray();
259     }
260
261     public static String readToEnd(InputStream input) throws IOException {
262         return new String(readToEndAsArray(input));
263     }
264
265     public static final int MULTIUSER_MODE_OWNER_ONLY = 0;
266     public static final int MULTIUSER_MODE_OWNER_MANAGED = 1;
267     public static final int MULTIUSER_MODE_USER = 2;
268     public static final int MULTIUSER_MODE_NONE = 3;
269     
270     private static final String MULTIUSER_VALUE_OWNER_ONLY  = "owner";
271     private static final String MULTIUSER_VALUE_OWNER_MANAGED = "managed";
272     private static final String MULTIUSER_VALUE_USER = "user";
273
274     public static final int getMultiuserMode(Context context) {
275         if (Build.VERSION.SDK_INT < 17)
276             return MULTIUSER_MODE_NONE;
277
278         if (!Helper.supportsMultipleUsers(context))
279             return MULTIUSER_MODE_NONE;
280         
281         try {
282             String mode;
283             if (Helper.isAdminUser(context)) {
284                 File file = context.getFileStreamPath("multiuser_mode");
285                 mode = readFile(file);
286             }
287             else {
288                 Process p = Runtime.getRuntime().exec("su -u");
289                 mode = readToEnd(p.getInputStream()).trim();
290             }
291             
292             if (MULTIUSER_VALUE_OWNER_MANAGED.equals(mode))
293                 return MULTIUSER_MODE_OWNER_MANAGED;
294             if (MULTIUSER_VALUE_USER.equals(mode))
295                 return MULTIUSER_MODE_USER;
296             if (MULTIUSER_VALUE_OWNER_ONLY.equals(mode))
297                 return MULTIUSER_MODE_OWNER_ONLY;
298         }
299         catch (Exception e) {
300         }
301         return MULTIUSER_MODE_OWNER_ONLY;
302     }
303     
304     public static void setMultiuserMode(Context context, int mode) {
305         if (!Helper.isAdminUser(context))
306             return;
307         try {
308             File file = context.getFileStreamPath("multiuser_mode");
309             switch (mode) {
310             case MULTIUSER_MODE_OWNER_MANAGED:
311                 writeFile(file, MULTIUSER_VALUE_OWNER_MANAGED);
312                 break;
313             case MULTIUSER_MODE_USER:
314                 writeFile(file, MULTIUSER_VALUE_USER);
315                 break;
316             case MULTIUSER_MODE_NONE:
317                 file.delete();
318                 break;
319             default:
320                 writeFile(file, MULTIUSER_VALUE_OWNER_ONLY);
321                 break;
322             }
323         }
324         catch (Exception ex) {
325         }
326     }
327 }