1 package com.koushikdutta.superuser.util;
3 import java.io.ByteArrayOutputStream;
4 import java.io.DataInputStream;
5 import java.io.DataOutputStream;
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;
13 import android.content.ContentValues;
14 import android.content.Context;
15 import android.database.Cursor;
16 import android.database.sqlite.SQLiteDatabase;
17 import android.os.Build;
18 import android.text.TextUtils;
19 import android.util.Base64;
21 import com.koushikdutta.superuser.Helper;
22 import com.koushikdutta.superuser.db.SuDatabaseHelper;
24 public class Settings {
25 SQLiteDatabase mDatabase;
28 public static void setString(Context context, String name, String value) {
29 ContentValues cv = new ContentValues();
31 cv.put("value", value);
32 SQLiteDatabase db = new SuDatabaseHelper(context).getWritableDatabase();
34 db.replace("settings", null, cv);
41 public static String getString(Context context, String name) {
42 return getString(context, name, null);
45 public static String getString(Context context, String name, String defaultValue) {
46 SQLiteDatabase db = new SuDatabaseHelper(context).getReadableDatabase();
47 Cursor cursor = db.query("settings", new String[] { "value" }, "key='" + name + "'", null, null, null, null);
49 if (cursor.moveToNext())
50 return cursor.getString(0);
59 public static void setInt(Context context, String name, int value) {
60 setString(context, name, ((Integer) value).toString());
63 public static int getInt(Context context, String name, int defaultValue) {
65 return Integer.parseInt(getString(context, name, null));
67 catch (Exception ex) {
72 public static void setLong(Context context, String name, long value) {
73 setString(context, name, ((Long) value).toString());
76 public static long getLong(Context context, String name, long defaultValue) {
78 return Long.parseLong(getString(context, name, null));
80 catch (Exception ex) {
85 public static void setBoolean(Context context, String name, boolean value) {
86 setString(context, name, ((Boolean) value).toString());
89 public static boolean getBoolean(Context context, String name, boolean defaultValue) {
91 return Boolean.parseBoolean(getString(context, name, ((Boolean) defaultValue).toString()));
93 catch (Exception ex) {
99 private static final String KEY_LOGGING = "logging";
100 public static boolean getLogging(Context context) {
101 return getBoolean(context, KEY_LOGGING, true);
104 public static void setLogging(Context context, boolean logging) {
105 setBoolean(context, KEY_LOGGING, logging);
108 private static final String KEY_TIMEOUT = "timeout";
109 public static final int REQUEST_TIMEOUT_DEFAULT = 30;
110 public static int getRequestTimeout(Context context) {
111 return getInt(context, KEY_TIMEOUT, REQUEST_TIMEOUT_DEFAULT);
114 public static void setTimeout(Context context, int timeout) {
115 setInt(context, KEY_TIMEOUT, timeout);
118 private static final String KEY_NOTIFICATION = "notification";
119 public static final int NOTIFICATION_TYPE_NONE = 0;
120 public static final int NOTIFICATION_TYPE_TOAST = 1;
121 public static final int NOTIFICATION_TYPE_NOTIFICATION = 2;
122 public static final int NOTIFICATION_TYPE_DEFAULT = NOTIFICATION_TYPE_TOAST;
123 public static int getNotificationType(Context context) {
124 switch (getInt(context, KEY_NOTIFICATION, NOTIFICATION_TYPE_DEFAULT)) {
125 case NOTIFICATION_TYPE_NONE:
126 return NOTIFICATION_TYPE_NONE;
127 case NOTIFICATION_TYPE_NOTIFICATION:
128 return NOTIFICATION_TYPE_NOTIFICATION;
129 case NOTIFICATION_TYPE_TOAST:
130 return NOTIFICATION_TYPE_TOAST;
132 return NOTIFICATION_TYPE_DEFAULT;
136 public static void setNotificationType(Context context, int notification) {
137 setInt(context, KEY_NOTIFICATION, notification);
140 public static final String KEY_PIN = "pin";
141 public static final boolean isPinProtected(Context context) {
142 return Settings.getString(context, KEY_PIN) != null;
145 private static String digest(String value) {
146 // ok, there's honestly no point in digesting the pin.
147 // if someone gets a hold of the hash, there's really only like
148 // 10^n possible values to brute force, where N is generally
149 // 4. Ie, 10000. Yay, security theater. This really ought
151 if (TextUtils.isEmpty(value))
154 MessageDigest digester = MessageDigest.getInstance("MD5");
155 return Base64.encodeToString(digester.digest(value.getBytes()), Base64.DEFAULT);
157 catch (Exception e) {
162 public static void setPin(Context context, String pin) {
163 Settings.setString(context, KEY_PIN, digest(pin));
166 public static boolean checkPin(Context context, String pin) {
168 String hashed = Settings.getString(context, KEY_PIN);
169 if (TextUtils.isEmpty(pin))
170 return TextUtils.isEmpty(hashed);
171 return pin.equals(hashed);
174 private static final String KEY_REQUIRE_PREMISSION = "require_permission";
175 public static boolean getRequirePermission(Context context) {
176 return getBoolean(context, KEY_REQUIRE_PREMISSION, false);
179 public static void setRequirePermission(Context context, boolean require) {
180 setBoolean(context, KEY_REQUIRE_PREMISSION, require);
183 private static final String KEY_AUTOMATIC_RESPONSE = "automatic_response";
184 public static final int AUTOMATIC_RESPONSE_PROMPT = 0;
185 public static final int AUTOMATIC_RESPONSE_ALLOW = 1;
186 public static final int AUTOMATIC_RESPONSE_DENY = 2;
187 public static final int AUTOMATIC_RESPONSE_DEFAULT = AUTOMATIC_RESPONSE_PROMPT;
188 public static int getAutomaticResponse(Context context) {
189 switch (getInt(context, KEY_AUTOMATIC_RESPONSE, AUTOMATIC_RESPONSE_DEFAULT)) {
190 case AUTOMATIC_RESPONSE_ALLOW:
191 return AUTOMATIC_RESPONSE_ALLOW;
192 case AUTOMATIC_RESPONSE_PROMPT:
193 return AUTOMATIC_RESPONSE_PROMPT;
194 case AUTOMATIC_RESPONSE_DENY:
195 return AUTOMATIC_RESPONSE_DENY;
197 return AUTOMATIC_RESPONSE_DEFAULT;
201 public static void setAutomaticResponse(Context context, int response) {
202 setInt(context, KEY_AUTOMATIC_RESPONSE, response);
206 static public String readFile(String filename) throws IOException {
207 return readFile(new File(filename));
210 static public String readFile(File file) throws IOException {
211 byte[] buffer = new byte[(int) file.length()];
212 DataInputStream input = new DataInputStream(new FileInputStream(file));
213 input.readFully(buffer);
215 return new String(buffer);
218 public static void writeFile(File file, String string) throws IOException {
219 writeFile(file.getAbsolutePath(), string);
222 public static void writeFile(String file, String string) throws IOException {
223 File f = new File(file);
224 f.getParentFile().mkdirs();
225 DataOutputStream dout = new DataOutputStream(new FileOutputStream(f));
226 dout.write(string.getBytes());
230 public static byte[] readToEndAsArray(InputStream input) throws IOException {
231 DataInputStream dis = new DataInputStream(input);
232 byte[] stuff = new byte[1024];
233 ByteArrayOutputStream buff = new ByteArrayOutputStream();
235 while ((read = dis.read(stuff)) != -1)
237 buff.write(stuff, 0, read);
240 return buff.toByteArray();
243 public static String readToEnd(InputStream input) throws IOException {
244 return new String(readToEndAsArray(input));
247 public static final int MULTIUSER_MODE_OWNER_ONLY = 0;
248 public static final int MULTIUSER_MODE_OWNER_MANAGED = 1;
249 public static final int MULTIUSER_MODE_USER = 2;
250 public static final int MULTIUSER_MODE_NONE = 3;
252 private static final String MULTIUSER_VALUE_OWNER_ONLY = "owner";
253 private static final String MULTIUSER_VALUE_OWNER_MANAGED = "managed";
254 private static final String MULTIUSER_VALUE_USER = "user";
256 public static final int getMultiuserMode(Context context) {
257 if (Build.VERSION.SDK_INT < 17)
258 return MULTIUSER_MODE_NONE;
260 if (!Helper.supportsMultipleUsers(context))
261 return MULTIUSER_MODE_NONE;
265 if (Helper.isAdminUser(context)) {
266 File file = context.getFileStreamPath("multiuser_mode");
267 mode = readFile(file);
270 Process p = Runtime.getRuntime().exec("su -u");
271 mode = readToEnd(p.getInputStream()).trim();
274 if (MULTIUSER_VALUE_OWNER_MANAGED.equals(mode))
275 return MULTIUSER_MODE_OWNER_MANAGED;
276 if (MULTIUSER_VALUE_USER.equals(mode))
277 return MULTIUSER_MODE_USER;
278 if (MULTIUSER_VALUE_OWNER_ONLY.equals(mode))
279 return MULTIUSER_MODE_OWNER_ONLY;
281 catch (Exception e) {
283 return MULTIUSER_MODE_OWNER_ONLY;
286 public static void setMultiuserMode(Context context, int mode) {
287 if (!Helper.isAdminUser(context))
290 File file = context.getFileStreamPath("multiuser_mode");
292 case MULTIUSER_MODE_OWNER_MANAGED:
293 writeFile(file, MULTIUSER_VALUE_OWNER_MANAGED);
295 case MULTIUSER_MODE_USER:
296 writeFile(file, MULTIUSER_VALUE_USER);
298 case MULTIUSER_MODE_NONE:
302 writeFile(file, MULTIUSER_VALUE_OWNER_ONLY);
306 catch (Exception ex) {