/*
* Copyright (C) 2012 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cyanogenmod.filemanager;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.util.Log;
import com.cyanogenmod.filemanager.console.Console;
import com.cyanogenmod.filemanager.console.ConsoleAllocException;
import com.cyanogenmod.filemanager.console.ConsoleBuilder;
import com.cyanogenmod.filemanager.console.ConsoleHolder;
import com.cyanogenmod.filemanager.console.shell.PrivilegedConsole;
import com.cyanogenmod.filemanager.preferences.AccessMode;
import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
import com.cyanogenmod.filemanager.preferences.ObjectStringIdentifier;
import com.cyanogenmod.filemanager.preferences.Preferences;
import com.cyanogenmod.filemanager.ui.ThemeManager;
import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
import com.cyanogenmod.filemanager.util.AIDHelper;
import com.cyanogenmod.filemanager.util.FileHelper;
import com.cyanogenmod.filemanager.util.MimeTypeHelper;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
/**
* A class that wraps the information of the application (constants,
* identifiers, statics variables, ...).
* @hide
*/
public final class FileManagerApplication extends Application {
private static final String TAG = "FileManagerApplication"; //$NON-NLS-1$
private static boolean DEBUG = false;
private static Properties sSystemProperties;
/**
* A constant that contains the main process name.
* @hide
*/
public static final String MAIN_PROCESS = "com.cyanogenmod.filemanager"; //$NON-NLS-1$
//Static resources
private static FileManagerApplication sApp;
private static ConsoleHolder sBackgroundConsole;
private static boolean sIsDebuggable = false;
private static boolean sIsDeviceRooted = false;
private final BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
if (intent.getAction().compareTo(
FileManagerSettings.INTENT_SETTING_CHANGED) == 0) {
// The settings has changed
String key =
intent.getStringExtra(FileManagerSettings.EXTRA_SETTING_CHANGED_KEY);
if (key != null &&
key.compareTo(FileManagerSettings.SETTINGS_SHOW_TRACES.getId()) == 0) {
// The debug traces setting has changed. Notify to consoles
Console c = null;
try {
c = getBackgroundConsole();
} catch (Exception e) {/**NON BLOCK**/}
if (c != null) {
c.reloadTrace();
}
try {
c = ConsoleBuilder.getConsole(context, false);
if (c != null) {
c.reloadTrace();
}
} catch (Throwable _throw) {/**NON BLOCK**/}
}
}
}
}
};
// A broadcast receiver for detect the install/uninstall of apps (for themes, AIDs, ...)
private final BroadcastReceiver mUninstallReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
if (intent.getAction().compareTo(Intent.ACTION_PACKAGE_REMOVED) == 0 ||
intent.getAction().compareTo(Intent.ACTION_PACKAGE_FULLY_REMOVED) == 0) {
// Check that the remove package is not the current theme
if (intent.getData() != null) {
// --- AIDs
try {
AIDHelper.getAIDs(getApplicationContext(), true);
} catch (Exception e) {
Log.w(TAG, "Failed to reload AIDs", e); //$NON-NLS-1$
}
// --- Themes
try {
// Get the package name and remove the schema
String apkPackage = intent.getData().toString();
apkPackage = apkPackage.substring("package:".length()); //$NON-NLS-1$
Theme currentTheme = ThemeManager.getCurrentTheme(context);
if (currentTheme.getPackage().compareTo(apkPackage) == 0) {
// The apk that contains the current theme was remove, change
// to default theme
String composedId =
(String)FileManagerSettings.SETTINGS_THEME.getDefaultValue();
ThemeManager.setCurrentTheme(getApplicationContext(), composedId);
try {
Preferences.savePreference(
FileManagerSettings.SETTINGS_THEME, composedId, true);
} catch (Throwable ex) {
Log.w(TAG, "can't save theme preference", ex); //$NON-NLS-1$
}
// Notify the changes to activities
try {
Intent broadcastIntent =
new Intent(FileManagerSettings.INTENT_THEME_CHANGED);
broadcastIntent.putExtra(
FileManagerSettings.EXTRA_THEME_ID, composedId);
sendBroadcast(broadcastIntent);
} catch (Throwable ex) {
Log.w(TAG, "notify of theme change failed", ex); //$NON-NLS-1$
}
}
} catch (Exception e) {
Log.w(TAG, "Failed to reload themes", e); //$NON-NLS-1$
}
}
}
}
}
};
/**
* {@inheritDoc}
*/
@Override
public void onCreate() {
if (DEBUG) {
Log.d(TAG, "FileManagerApplication.onCreate"); //$NON-NLS-1$
}
init();
register();
}
/**
* {@inheritDoc}
*/
@Override
public void onTerminate() {
if (DEBUG) {
Log.d(TAG, "onTerminate"); //$NON-NLS-1$
}
try {
unregisterReceiver(this.mNotificationReceiver);
} catch (Throwable ex) {
/**NON BLOCK**/
}
try {
unregisterReceiver(this.mUninstallReceiver);
} catch (Throwable ex) {
/**NON BLOCK**/
}
try {
destroyBackgroundConsole();
} catch (Throwable ex) {
/**NON BLOCK**/
}
try {
ConsoleBuilder.destroyConsole();
} catch (Throwable ex) {
/**NON BLOCK**/
}
super.onTerminate();
}
/**
* Method that register the application context.
*/
private void register() {
// Register the notify broadcast receiver
IntentFilter filter = new IntentFilter();
filter.addAction(FileManagerSettings.INTENT_SETTING_CHANGED);
registerReceiver(this.mNotificationReceiver, filter);
// Register the uninstall broadcast receiver
IntentFilter unfilter = new IntentFilter();
unfilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
unfilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
unfilter.addDataScheme("package"); //$NON-NLS-1$
registerReceiver(this.mUninstallReceiver, unfilter);
}
/**
* Method that initializes the application.
*/
private void init() {
//Save the static application reference
sApp = this;
// Read the system properties
sSystemProperties = new Properties();
readSystemProperties();
// Check if the application is debuggable
sIsDebuggable = (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE));
// Check if the device is rooted
sIsDeviceRooted = areShellCommandsPresent();
//Sets the default preferences if no value is set yet
Preferences.loadDefaults();
// Read AIDs
AIDHelper.getAIDs(getApplicationContext(), true);
// Allocate the default and current themes
String defaultValue = ((String)FileManagerSettings.
SETTINGS_THEME.getDefaultValue());
String value = Preferences.getSharedPreferences().getString(
FileManagerSettings.SETTINGS_THEME.getId(),
defaultValue);
ThemeManager.getDefaultTheme(getApplicationContext());
if (!ThemeManager.setCurrentTheme(getApplicationContext(), value)) {
//The current theme was not found. Mark the default setting as default theme
ThemeManager.setCurrentTheme(getApplicationContext(), defaultValue);
try {
Preferences.savePreference(
FileManagerSettings.SETTINGS_THEME, defaultValue, true);
} catch (Throwable ex) {
Log.w(TAG, "can't save theme preference", ex); //$NON-NLS-1$
}
}
// Set the base theme
Theme theme = ThemeManager.getCurrentTheme(getApplicationContext());
theme.setBaseTheme(getApplicationContext(), false);
//Create a console for background tasks
allocBackgroundConsole(getApplicationContext());
//Force the load of mime types
try {
MimeTypeHelper.loadMimeTypes(getApplicationContext());
} catch (Exception e) {
Log.e(TAG, "Mime-types failed.", e); //$NON-NLS-1$
}
}
/**
* Method that returns the singleton reference of the application.
*
* @return Application The application singleton reference
* @hide
*/
public static FileManagerApplication getInstance() {
return sApp;
}
/**
* Method that returns if the application is debuggable
*
* @return boolean If the application is debuggable
*/
public static boolean isDebuggable() {
return sIsDebuggable;
}
/**
* Method that returns if the device is rooted
*
* @return boolean If the device is rooted
*/
public static boolean isDeviceRooted() {
return sIsDeviceRooted;
}
/**
* Method that returns a system property value
*
* @param property The system property key
* @return String The system property value
*/
public static String getSystemProperty(String property) {
return sSystemProperties.getProperty(property);
}
/**
* Method that returns the application background console.
*
* @return Console The background console
*/
public static Console getBackgroundConsole() {
if (sBackgroundConsole == null ||
sBackgroundConsole.getConsole() == null ||
!sBackgroundConsole.getConsole().isActive()) {
allocBackgroundConsole(getInstance().getApplicationContext());
}
return sBackgroundConsole.getConsole();
}
/**
* Method that destroy the background console
*/
public static void destroyBackgroundConsole() {
try {
sBackgroundConsole.dispose();
} catch (Throwable ex) {
/**NON BLOCK**/
}
}
/**
* Method that allocate a new background console
*
* @param ctx The current context
*/
private static synchronized void allocBackgroundConsole(Context ctx) {
try {
// Dispose the current console
if (sBackgroundConsole != null) {
sBackgroundConsole.dispose();
sBackgroundConsole = null;
}
//Create a console for background tasks
if (ConsoleBuilder.isPrivileged()) {
sBackgroundConsole =
new ConsoleHolder(
ConsoleBuilder.createPrivilegedConsole(
ctx, FileHelper.ROOT_DIRECTORY));
} else {
sBackgroundConsole =
new ConsoleHolder(
ConsoleBuilder.createNonPrivilegedConsole(
ctx, FileHelper.ROOT_DIRECTORY));
}
} catch (Exception e) {
Log.e(TAG,
"Background console creation failed. " + //$NON-NLS-1$
"This probably will cause a force close.", e); //$NON-NLS-1$
}
}
/**
* Method that changes the background console to a privileged console
*
* @throws ConsoleAllocException If the console can't be allocated
*/
public static void changeBackgroundConsoleToPriviligedConsole()
throws ConsoleAllocException {
if (sBackgroundConsole == null ||
!(sBackgroundConsole.getConsole() instanceof PrivilegedConsole)) {
try {
if (sBackgroundConsole != null) {
sBackgroundConsole.dispose();
}
} catch (Throwable ex) {/**NON BLOCK**/}
// Change the privileged console
try {
sBackgroundConsole =
new ConsoleHolder(
ConsoleBuilder.createPrivilegedConsole(
getInstance().getApplicationContext(),
FileHelper.ROOT_DIRECTORY));
} catch (Exception e) {
try {
if (sBackgroundConsole != null) {
sBackgroundConsole.dispose();
}
} catch (Throwable ex) {/**NON BLOCK**/}
sBackgroundConsole = null;
throw new ConsoleAllocException(
"Failed to alloc background console", e); //$NON-NLS-1$
}
}
}
/**
* Method that returns the access mode of the application
*
* @return boolean If the access mode of the application
*/
public static AccessMode getAccessMode() {
String defaultValue =
((ObjectStringIdentifier)FileManagerSettings.
SETTINGS_ACCESS_MODE.getDefaultValue()).getId();
String id = FileManagerSettings.SETTINGS_ACCESS_MODE.getId();
AccessMode mode =
AccessMode.fromId(Preferences.getSharedPreferences().getString(id, defaultValue));
return mode;
}
/**
* Method that reads the system properties
*/
private static void readSystemProperties() {
try {
String propsFile =
getInstance().getApplicationContext().getString(R.string.system_props_file);
Properties props = new Properties();
props.load(new FileInputStream(new File(propsFile)));
sSystemProperties = props;
} catch (Throwable e) {
Log.e(TAG,
"Failed to read system properties.", e); //$NON-NLS-1$
}
}
/**
* Method that check if all shell commands are present in the device
*
* @return boolean Check if the device has all of the shell commands
*/
private boolean areShellCommandsPresent() {
try {
String shellCommands = getString(R.string.shell_required_commands);
String[] commands = shellCommands.split(","); //$NON-NLS-1$
int cc = commands.length;
if (cc == 0) {
//???
Log.w(TAG, "No shell commands."); //$NON-NLS-1$
return false;
}
for (int i = 0; i < cc; i++) {
String c = commands[i].trim();
if (c.length() == 0) continue;
File cmd = new File(c);
if (!cmd.exists() || !cmd.isFile()) {
Log.w(TAG,
String.format(
"Command %s not found. Exists: %s; IsFile: %s.", //$NON-NLS-1$
c,
String.valueOf(cmd.exists()),
String.valueOf(cmd.isFile())));
return false;
}
}
// All commands are present
return true;
} catch (Exception e) {
Log.e(TAG,
"Failed to read shell commands.", e); //$NON-NLS-1$
}
return false;
}
}