2012-02-26 04:22:40 +00:00
|
|
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
2013-05-22 17:23:53 +00:00
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2012-02-26 04:22:40 +00:00
|
|
|
|
|
|
|
package org.mozilla.gecko;
|
|
|
|
|
2012-08-02 17:40:57 +00:00
|
|
|
import org.mozilla.gecko.util.INIParser;
|
|
|
|
import org.mozilla.gecko.util.INISection;
|
2013-08-02 18:04:42 +00:00
|
|
|
import org.mozilla.gecko.util.ThreadUtils;
|
2012-08-02 17:40:57 +00:00
|
|
|
|
2012-07-28 00:53:54 +00:00
|
|
|
import android.content.Context;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.util.Log;
|
|
|
|
|
2012-02-26 04:22:40 +00:00
|
|
|
import java.io.File;
|
2013-05-21 16:03:11 +00:00
|
|
|
import java.io.FileOutputStream;
|
2012-02-26 04:22:40 +00:00
|
|
|
import java.io.FileReader;
|
|
|
|
import java.io.IOException;
|
2013-05-21 16:03:11 +00:00
|
|
|
import java.io.OutputStreamWriter;
|
|
|
|
import java.nio.charset.Charset;
|
2012-07-28 00:53:54 +00:00
|
|
|
import java.util.Enumeration;
|
2012-02-26 04:22:40 +00:00
|
|
|
import java.util.HashMap;
|
2012-06-18 17:03:03 +00:00
|
|
|
import java.util.Hashtable;
|
2012-02-26 04:22:40 +00:00
|
|
|
|
|
|
|
public final class GeckoProfile {
|
|
|
|
private static final String LOGTAG = "GeckoProfile";
|
2013-08-02 18:04:42 +00:00
|
|
|
// Used to "lock" the guest profile, so that we'll always restart in it
|
|
|
|
private static final String LOCK_FILE_NAME = ".active_lock";
|
2012-02-26 04:22:40 +00:00
|
|
|
|
|
|
|
private static HashMap<String, GeckoProfile> sProfileCache = new HashMap<String, GeckoProfile>();
|
2012-11-27 20:35:43 +00:00
|
|
|
private static String sDefaultProfileName = null;
|
2013-08-27 18:05:56 +00:00
|
|
|
private static File mMozDir;
|
2012-02-26 04:22:40 +00:00
|
|
|
|
|
|
|
private final Context mContext;
|
|
|
|
private final String mName;
|
|
|
|
private File mDir;
|
|
|
|
|
2013-08-02 18:04:42 +00:00
|
|
|
// Constants to cache whether or not a profile is "locked".
|
|
|
|
private enum LockState {
|
|
|
|
LOCKED,
|
|
|
|
UNLOCKED,
|
|
|
|
UNDEFINED
|
|
|
|
};
|
|
|
|
// Caches whether or not a profile is "locked". Only used by the guest profile to determine if it should
|
|
|
|
// be reused or deleted on startup
|
|
|
|
private LockState mLocked = LockState.UNDEFINED;
|
|
|
|
|
|
|
|
// Caches the guest profile dir
|
|
|
|
private static File mGuestDir = null;
|
|
|
|
|
2013-07-18 18:43:34 +00:00
|
|
|
private boolean mInGuestMode = false;
|
2013-08-02 18:04:42 +00:00
|
|
|
private static GeckoProfile mGuestProfile = null;
|
2013-07-18 18:43:34 +00:00
|
|
|
|
2013-08-27 18:05:56 +00:00
|
|
|
private static native int createSymLink(String filePath, String linkPath);
|
|
|
|
private static native int removeSymLink(String linkPath);
|
2012-06-15 16:02:11 +00:00
|
|
|
|
2012-02-26 04:22:40 +00:00
|
|
|
public static GeckoProfile get(Context context) {
|
2013-07-18 18:43:34 +00:00
|
|
|
if (context instanceof GeckoApp) {
|
2013-08-02 18:04:42 +00:00
|
|
|
// Check for a cached profile on this context already
|
|
|
|
// TODO: We should not be caching profile information on the Activity context
|
|
|
|
if (((GeckoApp)context).mProfile != null) {
|
2013-07-18 18:43:34 +00:00
|
|
|
return ((GeckoApp)context).mProfile;
|
2013-08-02 18:04:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GeckoProfile guest = GeckoProfile.getGuestProfile(context);
|
|
|
|
// if the guest profile exists and is locked, return it
|
|
|
|
if (guest != null && guest.locked()) {
|
|
|
|
return guest;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, get the default profile for the Activity
|
2012-06-18 17:03:03 +00:00
|
|
|
return get(context, ((GeckoApp)context).getDefaultProfileName());
|
2013-07-18 18:43:34 +00:00
|
|
|
}
|
2012-06-18 17:03:03 +00:00
|
|
|
|
2012-06-15 16:02:11 +00:00
|
|
|
return get(context, "");
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static GeckoProfile get(Context context, String profileName) {
|
2012-11-27 20:35:43 +00:00
|
|
|
synchronized (sProfileCache) {
|
|
|
|
GeckoProfile profile = sProfileCache.get(profileName);
|
|
|
|
if (profile != null)
|
|
|
|
return profile;
|
|
|
|
}
|
2013-07-18 18:43:34 +00:00
|
|
|
return get(context, profileName, (File)null);
|
2012-06-29 22:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static GeckoProfile get(Context context, String profileName, String profilePath) {
|
2013-07-18 18:43:34 +00:00
|
|
|
File dir = null;
|
|
|
|
if (!TextUtils.isEmpty(profilePath))
|
|
|
|
dir = new File(profilePath);
|
|
|
|
return get(context, profileName, dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static GeckoProfile get(Context context, String profileName, File profileDir) {
|
2012-02-26 04:22:40 +00:00
|
|
|
if (context == null) {
|
|
|
|
throw new IllegalArgumentException("context must be non-null");
|
|
|
|
}
|
2012-06-15 16:02:11 +00:00
|
|
|
|
|
|
|
// if no profile was passed in, look for the default profile listed in profiles.ini
|
|
|
|
// if that doesn't exist, look for a profile called 'default'
|
2013-07-18 18:43:34 +00:00
|
|
|
if (TextUtils.isEmpty(profileName) && profileDir == null) {
|
2012-11-27 20:35:43 +00:00
|
|
|
profileName = GeckoProfile.findDefaultProfile(context);
|
|
|
|
if (profileName == null)
|
|
|
|
profileName = "default";
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
|
|
|
|
2012-06-15 16:02:11 +00:00
|
|
|
// actually try to look up the profile
|
2012-02-26 04:22:40 +00:00
|
|
|
synchronized (sProfileCache) {
|
|
|
|
GeckoProfile profile = sProfileCache.get(profileName);
|
|
|
|
if (profile == null) {
|
2013-07-18 18:43:34 +00:00
|
|
|
profile = new GeckoProfile(context, profileName, profileDir);
|
2012-02-26 04:22:40 +00:00
|
|
|
sProfileCache.put(profileName, profile);
|
2012-06-29 22:34:15 +00:00
|
|
|
} else {
|
2013-07-18 18:43:34 +00:00
|
|
|
profile.setDir(profileDir);
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
|
|
|
return profile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-08 22:51:07 +00:00
|
|
|
public static File ensureMozillaDirectory(Context context) throws IOException {
|
2013-08-27 18:05:56 +00:00
|
|
|
if (mMozDir != null) {
|
|
|
|
return mMozDir;
|
|
|
|
}
|
|
|
|
|
2012-05-08 22:51:07 +00:00
|
|
|
synchronized (context) {
|
|
|
|
File filesDir = context.getFilesDir();
|
|
|
|
File mozDir = new File(filesDir, "mozilla");
|
|
|
|
if (! mozDir.exists()) {
|
|
|
|
if (! mozDir.mkdirs()) {
|
|
|
|
throw new IOException("Unable to create mozilla directory at " + mozDir.getAbsolutePath());
|
|
|
|
}
|
|
|
|
}
|
2013-08-27 18:05:56 +00:00
|
|
|
mMozDir = mozDir;
|
2012-05-08 22:51:07 +00:00
|
|
|
return mozDir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-18 17:03:03 +00:00
|
|
|
public static boolean removeProfile(Context context, String profileName) {
|
|
|
|
return new GeckoProfile(context, profileName).remove();
|
|
|
|
}
|
|
|
|
|
2013-07-18 18:43:34 +00:00
|
|
|
public static GeckoProfile createGuestProfile(Context context) {
|
|
|
|
try {
|
2013-07-30 16:05:25 +00:00
|
|
|
removeGuestProfile(context);
|
2013-08-02 18:04:42 +00:00
|
|
|
// We need to force the creation of a new guest profile if we want it outside of the normal profile path,
|
|
|
|
// otherwise GeckoProfile.getDir will try to be smart and build it for us in the normal profiles dir.
|
|
|
|
getGuestDir(context).mkdir();
|
|
|
|
GeckoProfile profile = getGuestProfile(context);
|
|
|
|
profile.lock();
|
2013-07-18 18:43:34 +00:00
|
|
|
return profile;
|
|
|
|
} catch (Exception ex) {
|
|
|
|
Log.e(LOGTAG, "Error creating guest profile", ex);
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-08-02 18:04:42 +00:00
|
|
|
public static void leaveGuestSession(Context context) {
|
|
|
|
GeckoProfile profile = getGuestProfile(context);
|
|
|
|
if (profile != null) {
|
|
|
|
profile.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static File getGuestDir(Context context) {
|
|
|
|
if (mGuestDir == null) {
|
2013-08-14 16:07:00 +00:00
|
|
|
mGuestDir = context.getFileStreamPath("guest");
|
2013-08-02 18:04:42 +00:00
|
|
|
}
|
|
|
|
return mGuestDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static GeckoProfile getGuestProfile(Context context) {
|
|
|
|
if (mGuestProfile == null) {
|
|
|
|
File guestDir = getGuestDir(context);
|
2013-08-26 23:32:10 +00:00
|
|
|
if (guestDir.exists()) {
|
|
|
|
mGuestProfile = get(context, "guest", guestDir);
|
|
|
|
mGuestProfile.mInGuestMode = true;
|
|
|
|
}
|
2013-08-02 18:04:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return mGuestProfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean maybeCleanupGuestProfile(final Context context) {
|
2013-08-26 23:32:10 +00:00
|
|
|
final GeckoProfile profile = getGuestProfile(context);
|
|
|
|
|
|
|
|
if (profile == null) {
|
2013-08-14 16:07:00 +00:00
|
|
|
return false;
|
2013-08-26 23:32:10 +00:00
|
|
|
} else if (!profile.locked()) {
|
|
|
|
profile.mInGuestMode = false;
|
2013-08-14 16:07:00 +00:00
|
|
|
|
2013-08-26 23:32:10 +00:00
|
|
|
// If the guest dir exists, but it's unlocked, delete it
|
2013-08-26 23:32:10 +00:00
|
|
|
removeGuestProfile(context);
|
|
|
|
|
2013-08-02 18:04:42 +00:00
|
|
|
return true;
|
2013-07-30 16:05:25 +00:00
|
|
|
}
|
2013-08-02 18:04:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void removeGuestProfile(Context context) {
|
2013-07-30 16:05:25 +00:00
|
|
|
try {
|
2013-08-02 18:04:42 +00:00
|
|
|
File guestDir = getGuestDir(context);
|
2013-07-30 16:05:25 +00:00
|
|
|
if (guestDir.exists()) {
|
|
|
|
delete(guestDir);
|
|
|
|
}
|
|
|
|
} catch (Exception ex) {
|
|
|
|
Log.e(LOGTAG, "Error removing guest profile", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean delete(File file) throws IOException {
|
|
|
|
// Try to do a quick initial delete
|
|
|
|
if (file.delete())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (file.isDirectory()) {
|
|
|
|
// If the quick delete failed and this is a dir, recursively delete the contents of the dir
|
|
|
|
String files[] = file.list();
|
|
|
|
for (String temp : files) {
|
|
|
|
File fileDelete = new File(file, temp);
|
|
|
|
delete(fileDelete);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Even if this is a dir, it should now be empty and delete should work
|
|
|
|
return file.delete();
|
|
|
|
}
|
|
|
|
|
2013-08-02 18:04:42 +00:00
|
|
|
// Warning, Changing the lock file state from outside apis will cause this to become out of sync
|
|
|
|
public boolean locked() {
|
|
|
|
if (mLocked != LockState.UNDEFINED) {
|
|
|
|
return mLocked == LockState.LOCKED;
|
|
|
|
}
|
|
|
|
|
|
|
|
File lockFile = new File(getDir(), LOCK_FILE_NAME);
|
|
|
|
boolean res = lockFile.exists();
|
|
|
|
mLocked = res ? LockState.LOCKED : LockState.UNLOCKED;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean lock() {
|
|
|
|
try {
|
|
|
|
File lockFile = new File(getDir(), LOCK_FILE_NAME);
|
|
|
|
boolean result = lockFile.createNewFile();
|
|
|
|
if (result) {
|
|
|
|
mLocked = LockState.LOCKED;
|
|
|
|
} else {
|
|
|
|
mLocked = LockState.UNLOCKED;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
} catch(IOException ex) {
|
|
|
|
Log.e(LOGTAG, "Error locking profile", ex);
|
|
|
|
}
|
|
|
|
mLocked = LockState.UNLOCKED;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean unlock() {
|
|
|
|
try {
|
|
|
|
File lockFile = new File(getDir(), LOCK_FILE_NAME);
|
|
|
|
boolean result = delete(lockFile);
|
|
|
|
if (result) {
|
|
|
|
mLocked = LockState.UNLOCKED;
|
|
|
|
} else {
|
|
|
|
mLocked = LockState.LOCKED;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
} catch(IOException ex) {
|
|
|
|
Log.e(LOGTAG, "Error unlocking profile", ex);
|
|
|
|
}
|
|
|
|
mLocked = LockState.LOCKED;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-26 04:22:40 +00:00
|
|
|
private GeckoProfile(Context context, String profileName) {
|
|
|
|
mContext = context;
|
|
|
|
mName = profileName;
|
|
|
|
}
|
|
|
|
|
2013-07-18 18:43:34 +00:00
|
|
|
private GeckoProfile(Context context, String profileName, File profileDir) {
|
2012-06-29 22:34:15 +00:00
|
|
|
mContext = context;
|
|
|
|
mName = profileName;
|
2013-07-18 18:43:34 +00:00
|
|
|
setDir(profileDir);
|
2012-06-29 22:34:15 +00:00
|
|
|
}
|
|
|
|
|
2013-07-18 18:43:34 +00:00
|
|
|
public boolean inGuestMode() {
|
|
|
|
return mInGuestMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setDir(File dir) {
|
|
|
|
if (dir != null && dir.exists() && dir.isDirectory()) {
|
|
|
|
mDir = dir;
|
|
|
|
} else {
|
|
|
|
Log.w(LOGTAG, "requested profile directory missing: " + dir);
|
2012-06-29 22:34:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-15 16:02:11 +00:00
|
|
|
public String getName() {
|
|
|
|
return mName;
|
|
|
|
}
|
|
|
|
|
2012-02-26 23:08:03 +00:00
|
|
|
public synchronized File getDir() {
|
2012-02-26 04:22:40 +00:00
|
|
|
if (mDir != null) {
|
|
|
|
return mDir;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2013-07-24 22:50:26 +00:00
|
|
|
// Check if a profile with this name already exists.
|
2012-05-08 22:51:07 +00:00
|
|
|
File mozillaDir = ensureMozillaDirectory(mContext);
|
2012-02-26 04:22:40 +00:00
|
|
|
mDir = findProfileDir(mozillaDir);
|
|
|
|
if (mDir == null) {
|
2012-06-15 16:02:11 +00:00
|
|
|
// otherwise create it
|
2012-02-26 04:22:40 +00:00
|
|
|
mDir = createProfileDir(mozillaDir);
|
|
|
|
} else {
|
|
|
|
Log.d(LOGTAG, "Found profile dir: " + mDir.getAbsolutePath());
|
|
|
|
}
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
Log.e(LOGTAG, "Error getting profile dir", ioe);
|
|
|
|
}
|
|
|
|
return mDir;
|
|
|
|
}
|
|
|
|
|
2012-06-26 18:56:03 +00:00
|
|
|
public File getFile(String aFile) {
|
|
|
|
File f = getDir();
|
|
|
|
if (f == null)
|
|
|
|
return null;
|
|
|
|
|
|
|
|
return new File(f, aFile);
|
|
|
|
}
|
|
|
|
|
2012-05-08 22:51:07 +00:00
|
|
|
public File getFilesDir() {
|
|
|
|
return mContext.getFilesDir();
|
|
|
|
}
|
|
|
|
|
2012-10-29 23:34:29 +00:00
|
|
|
/**
|
|
|
|
* Moves the session file to the backup session file.
|
|
|
|
*
|
|
|
|
* sessionstore.js should hold the current session, and sessionstore.bak
|
|
|
|
* should hold the previous session (where it is used to read the "tabs
|
|
|
|
* from last time"). Normally, sessionstore.js is moved to sessionstore.bak
|
|
|
|
* on a clean quit, but this doesn't happen if Fennec crashed. Thus, this
|
|
|
|
* method should be called after a crash so sessionstore.bak correctly
|
|
|
|
* holds the previous session.
|
|
|
|
*/
|
|
|
|
public void moveSessionFile() {
|
|
|
|
File sessionFile = getFile("sessionstore.js");
|
|
|
|
if (sessionFile != null && sessionFile.exists()) {
|
|
|
|
File sessionFileBackup = getFile("sessionstore.bak");
|
|
|
|
sessionFile.renameTo(sessionFileBackup);
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
2012-10-29 23:34:29 +00:00
|
|
|
}
|
2012-02-26 04:22:40 +00:00
|
|
|
|
2012-10-29 23:34:29 +00:00
|
|
|
/**
|
|
|
|
* Get the string from a session file.
|
|
|
|
*
|
|
|
|
* The session can either be read from sessionstore.js or sessionstore.bak.
|
|
|
|
* In general, sessionstore.js holds the current session, and
|
|
|
|
* sessionstore.bak holds the previous session.
|
|
|
|
*
|
|
|
|
* @param readBackup if true, the session is read from sessionstore.bak;
|
|
|
|
* otherwise, the session is read from sessionstore.js
|
|
|
|
*
|
|
|
|
* @return the session string
|
|
|
|
*/
|
|
|
|
public String readSessionFile(boolean readBackup) {
|
|
|
|
File sessionFile = getFile(readBackup ? "sessionstore.bak" : "sessionstore.js");
|
2012-02-26 04:22:40 +00:00
|
|
|
|
|
|
|
try {
|
2012-10-29 23:34:29 +00:00
|
|
|
if (sessionFile != null && sessionFile.exists()) {
|
|
|
|
return readFile(sessionFile);
|
|
|
|
}
|
2012-02-26 04:22:40 +00:00
|
|
|
} catch (IOException ioe) {
|
2012-10-29 23:34:29 +00:00
|
|
|
Log.e(LOGTAG, "Unable to read session file", ioe);
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
2012-10-29 23:34:29 +00:00
|
|
|
return null;
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public String readFile(String filename) throws IOException {
|
|
|
|
File dir = getDir();
|
|
|
|
if (dir == null) {
|
|
|
|
throw new IOException("No profile directory found");
|
|
|
|
}
|
|
|
|
File target = new File(dir, filename);
|
|
|
|
return readFile(target);
|
|
|
|
}
|
|
|
|
|
|
|
|
private String readFile(File target) throws IOException {
|
|
|
|
FileReader fr = new FileReader(target);
|
|
|
|
try {
|
2013-07-02 12:12:17 +00:00
|
|
|
StringBuilder sb = new StringBuilder();
|
2012-02-26 04:22:40 +00:00
|
|
|
char[] buf = new char[8192];
|
|
|
|
int read = fr.read(buf);
|
|
|
|
while (read >= 0) {
|
|
|
|
sb.append(buf, 0, read);
|
|
|
|
read = fr.read(buf);
|
|
|
|
}
|
|
|
|
return sb.toString();
|
|
|
|
} finally {
|
|
|
|
fr.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-18 17:03:03 +00:00
|
|
|
private boolean remove() {
|
|
|
|
try {
|
2013-08-02 18:04:42 +00:00
|
|
|
File dir = getDir();
|
|
|
|
if (dir.exists())
|
|
|
|
delete(dir);
|
|
|
|
|
2012-06-18 17:03:03 +00:00
|
|
|
File mozillaDir = ensureMozillaDirectory(mContext);
|
|
|
|
mDir = findProfileDir(mozillaDir);
|
2013-08-02 18:04:42 +00:00
|
|
|
if (mDir == null) {
|
2012-06-18 17:03:03 +00:00
|
|
|
return false;
|
2013-08-27 18:05:56 +00:00
|
|
|
} else {
|
|
|
|
delete(mDir);
|
|
|
|
return true;
|
2013-08-02 18:04:42 +00:00
|
|
|
}
|
2013-08-27 18:05:56 +00:00
|
|
|
} catch (IOException ioe) {
|
|
|
|
Log.e(LOGTAG, "Error getting profile dir", ioe);
|
2012-06-18 17:03:03 +00:00
|
|
|
}
|
2013-08-27 18:05:56 +00:00
|
|
|
return false;
|
2012-06-18 17:03:03 +00:00
|
|
|
}
|
|
|
|
|
2012-11-27 20:35:43 +00:00
|
|
|
public static String findDefaultProfile(Context context) {
|
|
|
|
// Have we read the default profile from the INI already?
|
|
|
|
// Changing the default profile requires a restart, so we don't
|
|
|
|
// need to worry about runtime changes.
|
|
|
|
if (sDefaultProfileName != null) {
|
|
|
|
return sDefaultProfileName;
|
|
|
|
}
|
|
|
|
|
2013-08-27 18:05:56 +00:00
|
|
|
try {
|
|
|
|
File activeDir = new File(ensureMozillaDirectory(context), "active-profile");
|
|
|
|
if (activeDir.exists()) {
|
|
|
|
sDefaultProfileName = activeDir.getCanonicalFile().getName();
|
2012-11-27 20:35:43 +00:00
|
|
|
}
|
2013-08-27 18:05:56 +00:00
|
|
|
} catch (IOException ioe) {
|
|
|
|
Log.e(LOGTAG, "Error getting currDir", ioe);
|
2012-11-27 20:35:43 +00:00
|
|
|
}
|
2013-08-27 18:05:56 +00:00
|
|
|
return sDefaultProfileName;
|
2012-11-27 20:35:43 +00:00
|
|
|
}
|
|
|
|
|
2013-08-27 18:05:56 +00:00
|
|
|
public static void setAsDefault(Context context, File defaultFile) {
|
|
|
|
try {
|
|
|
|
String symlinkPath = ensureMozillaDirectory(context).getAbsolutePath() + "/active-profile";
|
|
|
|
File activeFile = new File(symlinkPath);
|
|
|
|
// Unlink from previous file
|
|
|
|
if (activeFile.exists()) {
|
|
|
|
removeSymLink(symlinkPath);
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
2012-06-15 16:02:11 +00:00
|
|
|
|
2013-08-27 18:05:56 +00:00
|
|
|
// Set as active profile
|
|
|
|
createSymLink(defaultFile.getAbsolutePath(), symlinkPath);
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
Log.e(LOGTAG, "Error setting default profile", ioe);
|
|
|
|
}
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
|
|
|
|
2013-08-27 18:05:56 +00:00
|
|
|
private File findProfileDir(File mozillaDir) {
|
|
|
|
File nameDir = new File(mozillaDir, mName);
|
|
|
|
if (! nameDir.exists()) {
|
|
|
|
return null;
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
2013-08-27 18:05:56 +00:00
|
|
|
|
|
|
|
return nameDir;
|
2012-02-26 04:22:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private File createProfileDir(File mozillaDir) throws IOException {
|
2013-08-27 18:05:56 +00:00
|
|
|
File profileDir = new File(mozillaDir, mName);
|
2012-02-26 04:22:40 +00:00
|
|
|
|
2013-08-27 18:05:56 +00:00
|
|
|
// Attempt to create the profile dir
|
2012-02-26 04:22:40 +00:00
|
|
|
if (! profileDir.mkdirs()) {
|
|
|
|
throw new IOException("Unable to create profile at " + profileDir.getAbsolutePath());
|
|
|
|
}
|
|
|
|
Log.d(LOGTAG, "Created new profile dir at " + profileDir.getAbsolutePath());
|
|
|
|
|
2013-05-21 16:03:11 +00:00
|
|
|
// Write out profile creation time, mirroring the logic in nsToolkitProfileService.
|
|
|
|
try {
|
|
|
|
FileOutputStream stream = new FileOutputStream(profileDir.getAbsolutePath() + File.separator + "times.json");
|
|
|
|
OutputStreamWriter writer = new OutputStreamWriter(stream, Charset.forName("UTF-8"));
|
|
|
|
try {
|
|
|
|
writer.append("{\"created\": " + System.currentTimeMillis() + "}\n");
|
|
|
|
} finally {
|
|
|
|
writer.close();
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
// Best-effort.
|
|
|
|
Log.w(LOGTAG, "Couldn't write times.json.", e);
|
|
|
|
}
|
|
|
|
|
2012-02-26 04:22:40 +00:00
|
|
|
return profileDir;
|
|
|
|
}
|
|
|
|
}
|