diff options
Diffstat (limited to 'packages')
40 files changed, 1074 insertions, 95 deletions
diff --git a/packages/BackupRestoreConfirmation/AndroidManifest.xml b/packages/BackupRestoreConfirmation/AndroidManifest.xml index ed9a519..19848f6 100644 --- a/packages/BackupRestoreConfirmation/AndroidManifest.xml +++ b/packages/BackupRestoreConfirmation/AndroidManifest.xml @@ -21,7 +21,7 @@ <uses-permission android:name="android.permission.BACKUP" /> <application android:allowClearUserData="false" - android:killAfterRestore="false" + android:allowBackup="false" android:permission="android.permission.CONFIRM_FULL_BACKUP" > <activity android:name=".BackupRestoreConfirmation" diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml index 109cfff..a4564e6 100644 --- a/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml +++ b/packages/BackupRestoreConfirmation/res/layout/confirm_backup.xml @@ -37,6 +37,7 @@ android:layout_marginBottom="30dp" /> <Button android:id="@+id/button_allow" + android:filterTouchesWhenObscured="true" android:text="@string/allow_backup_button_label" android:layout_below="@id/package_name" android:layout_height="wrap_content" diff --git a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml index a1f9a4a..ca99ae1 100644 --- a/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml +++ b/packages/BackupRestoreConfirmation/res/layout/confirm_restore.xml @@ -37,6 +37,7 @@ android:layout_marginBottom="30dp" /> <Button android:id="@+id/button_allow" + android:filterTouchesWhenObscured="true" android:text="@string/allow_restore_button_label" android:layout_below="@id/package_name" android:layout_height="wrap_content" diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java index 4b42067..ed413e6 100644 --- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java +++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java @@ -60,6 +60,7 @@ public class BackupRestoreConfirmation extends Activity { IBackupManager mBackupManager; FullObserver mObserver; int mToken; + boolean mDidAcknowledge; TextView mStatusView; Button mAllowButton; @@ -70,6 +71,7 @@ public class BackupRestoreConfirmation extends Activity { Context mContext; ObserverHandler(Context context) { mContext = context; + mDidAcknowledge = false; } @Override @@ -98,6 +100,8 @@ public class BackupRestoreConfirmation extends Activity { break; case MSG_RESTORE_PACKAGE: { + String name = (String) msg.obj; + mStatusView.setText(name); } break; @@ -155,11 +159,7 @@ public class BackupRestoreConfirmation extends Activity { mAllowButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - try { - mBackupManager.acknowledgeFullBackupOrRestore(mToken, true, mObserver); - } catch (RemoteException e) { - // TODO: bail gracefully if we can't contact the backup manager - } + sendAcknowledgement(mToken, true, mObserver); mAllowButton.setEnabled(false); mDenyButton.setEnabled(false); } @@ -168,11 +168,7 @@ public class BackupRestoreConfirmation extends Activity { mDenyButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - try { - mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, mObserver); - } catch (RemoteException e) { - // TODO: bail gracefully if we can't contact the backup manager - } + sendAcknowledgement(mToken, false, mObserver); mAllowButton.setEnabled(false); mDenyButton.setEnabled(false); } @@ -185,14 +181,21 @@ public class BackupRestoreConfirmation extends Activity { // We explicitly equate departure from the UI with refusal. This includes the // implicit configuration-changed stop/restart cycle. - try { - mBackupManager.acknowledgeFullBackupOrRestore(mToken, false, null); - } catch (RemoteException e) { - // if this fails we'll still time out with no acknowledgment - } + sendAcknowledgement(mToken, false, null); finish(); } + void sendAcknowledgement(int token, boolean allow, IFullBackupRestoreObserver observer) { + if (!mDidAcknowledge) { + mDidAcknowledge = true; + try { + mBackupManager.acknowledgeFullBackupOrRestore(mToken, true, mObserver); + } catch (RemoteException e) { + // TODO: bail gracefully if we can't contact the backup manager + } + } + } + /** * The observer binder for showing backup/restore progress. This binder just bounces * the notifications onto the main thread. diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index bf06f947..2e2768f 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -125,4 +125,7 @@ <!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS --> <integer name="def_long_press_timeout_millis">500</integer> + <!-- Default for Settings.System.POINTER_SPEED --> + <integer name="def_pointer_speed">0</integer> + </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index b99c8b0..9cbf704 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -17,6 +17,8 @@ package com.android.providers.settings; import com.android.internal.content.PackageHelper; +import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; @@ -1214,6 +1216,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.System.NOTIFICATIONS_USE_RING_VOLUME, R.bool.def_notifications_use_ring_volume); + loadIntegerSetting(stmt, Settings.System.POINTER_SPEED, + R.integer.def_pointer_speed); + } finally { if (stmt != null) stmt.close(); } @@ -1297,8 +1302,13 @@ public class DatabaseHelper extends SQLiteOpenHelper { } // Set the preferred network mode to 0 = Global, CDMA default - int type = SystemProperties.getInt("ro.telephony.default_network", - RILConstants.PREFERRED_NETWORK_MODE); + int type; + if (BaseCommands.getLteOnCdmaModeStatic() == Phone.LTE_ON_CDMA_TRUE) { + type = Phone.NT_MODE_GLOBAL; + } else { + type = SystemProperties.getInt("ro.telephony.default_network", + RILConstants.PREFERRED_NETWORK_MODE); + } loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type); // Enable or disable Cell Broadcast SMS diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 45bb2b6..0c4ef7d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -55,6 +55,7 @@ import android.util.Log; */ public class SettingsBackupAgent extends BackupAgentHelper { private static final boolean DEBUG = false; + private static final boolean DEBUG_BACKUP = DEBUG || true; private static final String KEY_SYSTEM = "system"; private static final String KEY_SECURE = "secure"; @@ -75,6 +76,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final int STATE_WIFI_CONFIG = 4; private static final int STATE_SIZE = 5; // The number of state items + // Versioning of the 'full backup' format + private static final int FULL_BACKUP_VERSION = 1; + private static String[] sortedSystemKeys = null; private static String[] sortedSecureKeys = null; @@ -109,6 +113,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static String mWifiConfigFile; public void onCreate() { + if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked"); + mSettingsHelper = new SettingsHelper(this); super.onCreate(); @@ -151,26 +157,32 @@ public class SettingsBackupAgent extends BackupAgentHelper { // representation of the backed-up settings. String root = getFilesDir().getAbsolutePath(); File stage = new File(root, STAGE_FILE); - FileOutputStream filestream = new FileOutputStream(stage); - BufferedOutputStream bufstream = new BufferedOutputStream(filestream); - DataOutputStream out = new DataOutputStream(bufstream); - - out.writeInt(systemSettingsData.length); - out.write(systemSettingsData); - out.writeInt(secureSettingsData.length); - out.write(secureSettingsData); - out.writeInt(locale.length); - out.write(locale); - out.writeInt(wifiSupplicantData.length); - out.write(wifiSupplicantData); - out.writeInt(wifiConfigData.length); - out.write(wifiConfigData); - - out.flush(); // also flushes downstream - - // now we're set to emit the tar stream - FullBackup.backupToTar(getPackageName(), FullBackup.DATA_TREE_TOKEN, null, - root, stage.getAbsolutePath(), data); + try { + FileOutputStream filestream = new FileOutputStream(stage); + BufferedOutputStream bufstream = new BufferedOutputStream(filestream); + DataOutputStream out = new DataOutputStream(bufstream); + + out.writeInt(FULL_BACKUP_VERSION); + + out.writeInt(systemSettingsData.length); + out.write(systemSettingsData); + out.writeInt(secureSettingsData.length); + out.write(secureSettingsData); + out.writeInt(locale.length); + out.write(locale); + out.writeInt(wifiSupplicantData.length); + out.write(wifiSupplicantData); + out.writeInt(wifiConfigData.length); + out.write(wifiConfigData); + + out.flush(); // also flushes downstream + + // now we're set to emit the tar stream + FullBackup.backupToTar(getPackageName(), FullBackup.DATA_TREE_TOKEN, null, + root, stage.getAbsolutePath(), data); + } finally { + stage.delete(); + } } } @@ -199,7 +211,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { } else if (KEY_LOCALE.equals(key)) { byte[] localeData = new byte[size]; data.readEntityData(localeData, 0, size); - mSettingsHelper.setLocaleData(localeData); + mSettingsHelper.setLocaleData(localeData, size); } else if (KEY_WIFI_CONFIG.equals(key)) { restoreFileData(mWifiConfigFile, data); } else { @@ -208,6 +220,70 @@ public class SettingsBackupAgent extends BackupAgentHelper { } } + @Override + public void onRestoreFile(ParcelFileDescriptor data, long size, + int type, String domain, String relpath, long mode, long mtime) + throws IOException { + if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked"); + // Our data is actually a blob of flattened settings data identical to that + // produced during incremental backups. Just unpack and apply it all in + // turn. + FileInputStream instream = new FileInputStream(data.getFileDescriptor()); + DataInputStream in = new DataInputStream(instream); + + int version = in.readInt(); + if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version); + if (version == FULL_BACKUP_VERSION) { + // system settings data first + int nBytes = in.readInt(); + if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data"); + byte[] buffer = new byte[nBytes]; + in.read(buffer, 0, nBytes); + restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI); + + // secure settings + nBytes = in.readInt(); + if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data"); + if (nBytes > buffer.length) buffer = new byte[nBytes]; + in.read(buffer, 0, nBytes); + restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI); + + // locale + nBytes = in.readInt(); + if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data"); + if (nBytes > buffer.length) buffer = new byte[nBytes]; + in.read(buffer, 0, nBytes); + mSettingsHelper.setLocaleData(buffer, nBytes); + + // wifi supplicant + nBytes = in.readInt(); + if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi supplicant data"); + if (nBytes > buffer.length) buffer = new byte[nBytes]; + in.read(buffer, 0, nBytes); + int retainedWifiState = enableWifi(false); + restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes); + FileUtils.setPermissions(FILE_WIFI_SUPPLICANT, + FileUtils.S_IRUSR | FileUtils.S_IWUSR | + FileUtils.S_IRGRP | FileUtils.S_IWGRP, + Process.myUid(), Process.WIFI_UID); + // retain the previous WIFI state. + enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED || + retainedWifiState == WifiManager.WIFI_STATE_ENABLING); + + // wifi config + nBytes = in.readInt(); + if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi config data"); + if (nBytes > buffer.length) buffer = new byte[nBytes]; + in.read(buffer, 0, nBytes); + restoreFileData(mWifiConfigFile, buffer, nBytes); + + if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete."); + } else { + data.close(); + throw new IOException("Invalid file schema"); + } + } + private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException { long[] stateChecksums = new long[STATE_SIZE]; @@ -287,6 +363,17 @@ public class SettingsBackupAgent extends BackupAgentHelper { } private void restoreSettings(BackupDataInput data, Uri contentUri) { + byte[] settings = new byte[data.getDataSize()]; + try { + data.readEntityData(settings, 0, settings.length); + } catch (IOException ioe) { + Log.e(TAG, "Couldn't read entity data"); + return; + } + restoreSettings(settings, settings.length, contentUri); + } + + private void restoreSettings(byte[] settings, int bytes, Uri contentUri) { if (DEBUG) Log.i(TAG, "restoreSettings: " + contentUri); String[] whitelist = null; if (contentUri.equals(Settings.Secure.CONTENT_URI)) { @@ -296,15 +383,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { } ContentValues cv = new ContentValues(2); - byte[] settings = new byte[data.getDataSize()]; - try { - data.readEntityData(settings, 0, settings.length); - } catch (IOException ioe) { - Log.e(TAG, "Couldn't read entity data"); - return; - } int pos = 0; - while (pos < settings.length) { + while (pos < bytes) { int length = readInt(settings, pos); pos += 4; String settingName = length > 0? new String(settings, pos, length) : null; @@ -451,13 +531,16 @@ public class SettingsBackupAgent extends BackupAgentHelper { private void restoreFileData(String filename, BackupDataInput data) { byte[] bytes = new byte[data.getDataSize()]; if (bytes.length <= 0) return; + restoreFileData(filename, bytes, bytes.length); + } + + private void restoreFileData(String filename, byte[] bytes, int size) { try { - data.readEntityData(bytes, 0, bytes.length); File file = new File(filename); if (file.exists()) file.delete(); OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true)); - os.write(bytes); + os.write(bytes, 0, size); os.close(); } catch (IOException ioe) { Log.w(TAG, "Couldn't restore " + filename); @@ -506,15 +589,18 @@ public class SettingsBackupAgent extends BackupAgentHelper { private void restoreWifiSupplicant(String filename, BackupDataInput data) { byte[] bytes = new byte[data.getDataSize()]; if (bytes.length <= 0) return; + restoreWifiSupplicant(filename, bytes, bytes.length); + } + + private void restoreWifiSupplicant(String filename, byte[] bytes, int size) { try { - data.readEntityData(bytes, 0, bytes.length); File supplicantFile = new File(FILE_WIFI_SUPPLICANT); if (supplicantFile.exists()) supplicantFile.delete(); copyWifiSupplicantTemplate(); OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true)); os.write("\n".getBytes()); - os.write(bytes); + os.write(bytes, 0, size); os.close(); } catch (IOException ioe) { Log.w(TAG, "Couldn't restore " + filename); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index 0e75fbc..3e7d86a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -147,7 +147,7 @@ public class SettingsHelper { * "ll" is the language code and "cc" is the country code. * @param data the locale string in bytes. */ - void setLocaleData(byte[] data) { + void setLocaleData(byte[] data, int size) { // Check if locale was set by the user: Configuration conf = mContext.getResources().getConfiguration(); Locale loc = conf.locale; @@ -157,9 +157,9 @@ public class SettingsHelper { if (conf.userSetLocale) return; // Don't change if user set it in the SetupWizard final String[] availableLocales = mContext.getAssets().getLocales(); - String localeCode = new String(data); + String localeCode = new String(data, 0, size); String language = new String(data, 0, 2); - String country = data.length > 4 ? new String(data, 3, 2) : ""; + String country = size > 4 ? new String(data, 3, 2) : ""; loc = null; for (int i = 0; i < availableLocales.length; i++) { if (availableLocales[i].equals(localeCode)) { diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk new file mode 100644 index 0000000..1d4f4da --- /dev/null +++ b/packages/SharedStorageBackup/Android.mk @@ -0,0 +1,33 @@ +# +# Copyright (C) 2011 The Android Open Source 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +LOCAL_PACKAGE_NAME := SharedStorageBackup +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) + +######################## +include $(call all-makefiles-under,$(LOCAL_PATH)) + diff --git a/packages/SharedStorageBackup/AndroidManifest.xml b/packages/SharedStorageBackup/AndroidManifest.xml new file mode 100644 index 0000000..258059c --- /dev/null +++ b/packages/SharedStorageBackup/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2011, The Android Open Source 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.sharedstoragebackup" > + + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> + + <application android:allowClearUserData="false" + android:permission="android.permission.CONFIRM_FULL_BACKUP" + android:fullBackupAgent=".SharedStorageAgent" + android:allowBackup="false" > + </application> +</manifest> diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags new file mode 100644 index 0000000..f43cb81 --- /dev/null +++ b/packages/SharedStorageBackup/proguard.flags @@ -0,0 +1 @@ +-keep class com.android.sharedstoragebackup.SharedStorageAgent diff --git a/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java new file mode 100644 index 0000000..b02ca2e --- /dev/null +++ b/packages/SharedStorageBackup/src/com/android/sharedstoragebackup/SharedStorageAgent.java @@ -0,0 +1,93 @@ +package com.android.sharedstoragebackup; + +import android.app.backup.FullBackup; +import android.app.backup.FullBackupAgent; +import android.app.backup.BackupDataInput; +import android.app.backup.BackupDataOutput; +import android.content.Context; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.os.storage.StorageManager; +import android.os.storage.StorageVolume; +import android.util.Slog; + +import java.io.File; +import java.io.IOException; + +public class SharedStorageAgent extends FullBackupAgent { + static final String TAG = "SharedStorageAgent"; + static final boolean DEBUG = true; + + StorageVolume[] mVolumes; + + @Override + public void onCreate() { + StorageManager mgr = (StorageManager) getSystemService(Context.STORAGE_SERVICE); + if (mgr != null) { + mVolumes = mgr.getVolumeList(); + } else { + Slog.e(TAG, "Unable to access Storage Manager"); + } + } + + @Override + public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState) throws IOException { + // If there are shared-storage volumes available, run the inherited directory- + // hierarchy backup process on them. By convention in the Storage Manager, the + // "primary" shared storage volume is first in the list. + if (mVolumes != null) { + for (int i = 0; i < mVolumes.length; i++) { + StorageVolume v = mVolumes[i]; + // Express the contents of volume N this way in the tar stream: + // shared/N/path/to/file + // The restore will then extract to the given volume + String domain = FullBackup.SHARED_PREFIX + i; + processTree(null, domain, v.getPath(), null, data); + } + } + } + + /** + * Incremental onRestore() implementation is not used. + */ + @Override + public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) + throws IOException { + } + + /** + * Full restore of one file to shared storage + */ + @Override + public void onRestoreFile(ParcelFileDescriptor data, long size, + int type, String domain, String relpath, long mode, long mtime) + throws IOException { + Slog.d(TAG, "Shared restore: [ " + domain + " : " + relpath + "]"); + + File outFile = null; + + // The file path must be in the semantic form [number]/path/to/file... + int slash = relpath.indexOf('/'); + if (slash > 0) { + try { + int i = Integer.parseInt(relpath.substring(0, slash)); + if (i <= mVolumes.length) { + outFile = new File(mVolumes[i].getPath(), relpath.substring(slash + 1)); + if (DEBUG) Slog.i(TAG, " => " + outFile.getAbsolutePath()); + } else { + Slog.w(TAG, "Cannot restore data for unavailable volume " + i); + } + } catch (NumberFormatException e) { + if (DEBUG) Slog.w(TAG, "Bad volume number token: " + relpath.substring(0, slash)); + } + } else { + if (DEBUG) Slog.i(TAG, "Can't find volume-number token"); + } + if (outFile == null) { + Slog.e(TAG, "Skipping data with malformed path " + relpath); + } + + FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, false); + } +} diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_default.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_default.png Binary files differnew file mode 100644 index 0000000..e2584e3 --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_default.png diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_pressed.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_pressed.png Binary files differnew file mode 100644 index 0000000..58b8510 --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/ic_sysbar_zoom_pressed.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_default.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_default.png Binary files differnew file mode 100644 index 0000000..2795c34 --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_default.png diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_pressed.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_pressed.png Binary files differnew file mode 100644 index 0000000..bbed6a6 --- /dev/null +++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/ic_sysbar_zoom_pressed.png diff --git a/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml b/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml new file mode 100644 index 0000000..977e002 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_sysbar_zoom.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true" android:drawable="@drawable/ic_sysbar_zoom_pressed" /> + <item android:drawable="@drawable/ic_sysbar_zoom_default" /> +</selector> + diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar.xml b/packages/SystemUI/res/layout-sw600dp/status_bar.xml index d9f3f23..707a8cb 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar.xml @@ -75,6 +75,13 @@ systemui:keyCode="82" android:visibility="invisible" /> + <com.android.systemui.statusbar.policy.CompatModeButton + android:id="@+id/compat_button" + android:layout_width="80dip" + android:layout_height="match_parent" + android:src="@drawable/ic_sysbar_zoom" + android:visibility="invisible" + /> </LinearLayout> <!-- fake space bar zone --> diff --git a/packages/SystemUI/res/values-fr-large/strings.xml b/packages/SystemUI/res/values-fr-large/strings.xml index 447b174..f8dd55e 100644 --- a/packages/SystemUI/res/values-fr-large/strings.xml +++ b/packages/SystemUI/res/values-fr-large/strings.xml @@ -21,7 +21,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Tout effacer"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Aucune connexion"</string> - <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Connecté au Wi-Fi."</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Connecté au Wi-Fi"</string> <string name="gps_notification_searching_text" msgid="4467935186864208249">"Recherche de GPS en cours"</string> <string name="gps_notification_found_text" msgid="6270628388918822956">"Position définie par GPS"</string> <string name="notifications_off_title" msgid="1860117696034775851">"Notifications désactivées"</string> diff --git a/packages/SystemUI/res/values-it-large/strings.xml b/packages/SystemUI/res/values-it-large/strings.xml index 3cde529..18ccd07 100644 --- a/packages/SystemUI/res/values-it-large/strings.xml +++ b/packages/SystemUI/res/values-it-large/strings.xml @@ -19,8 +19,8 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Cancella tutto"</string> - <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Nessuna conness. Internet"</string> + <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Cancella"</string> + <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Nessuna connessione"</string> <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi connesso"</string> <string name="gps_notification_searching_text" msgid="4467935186864208249">"Ricerca del GPS"</string> <string name="gps_notification_found_text" msgid="6270628388918822956">"Posizione stabilita dal GPS"</string> diff --git a/packages/SystemUI/res/values-large/config.xml b/packages/SystemUI/res/values-large/config.xml index 299ab97..4014f8d 100644 --- a/packages/SystemUI/res/values-large/config.xml +++ b/packages/SystemUI/res/values-large/config.xml @@ -20,14 +20,7 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - <integer name="config_status_bar_position">1</integer> - - <!-- Component to be used as the status bar service. Must implement the IStatusBar - interface. This name is in the ComponentName flattened format (package/class) --> - <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string> - <!-- Whether or not we show the number in the bar. --> <bool name="config_statusBarShowNumber">false</bool> - </resources> diff --git a/packages/SystemUI/res/values-ru-large/strings.xml b/packages/SystemUI/res/values-ru-large/strings.xml index c48321e..bafb97f 100644 --- a/packages/SystemUI/res/values-ru-large/strings.xml +++ b/packages/SystemUI/res/values-ru-large/strings.xml @@ -19,11 +19,11 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Очистить"</string> + <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Очистить все"</string> <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Нет подключения к Интернету"</string> - <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi: подключено"</string> - <string name="gps_notification_searching_text" msgid="4467935186864208249">"Выполняется поиск при помощи GPS"</string> + <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi подключено"</string> + <string name="gps_notification_searching_text" msgid="4467935186864208249">"Поиск GPS"</string> <string name="gps_notification_found_text" msgid="6270628388918822956">"Местоположение установлено с помощью GPS"</string> - <string name="notifications_off_title" msgid="1860117696034775851">"Показ уведомлений отключен"</string> - <string name="notifications_off_text" msgid="1439152806320786912">"Нажмите здесь, чтобы снова разрешить показ уведомлений."</string> + <string name="notifications_off_title" msgid="1860117696034775851">"Уведомления отключены"</string> + <string name="notifications_off_text" msgid="1439152806320786912">"Нажмите здесь, чтобы снова включить уведомления."</string> </resources> diff --git a/packages/SystemUI/res/values-sw600dp-port/config.xml b/packages/SystemUI/res/values-sw600dp-port/config.xml new file mode 100644 index 0000000..ab7661a --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-port/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source 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. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <integer name="config_maxNotificationIcons">3</integer> +</resources> + diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml index 78dd8c4..b8a6cfe 100644 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - * Copyright (c) 2010, The Android Open Source Project + * Copyright (c) 2011, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,6 @@ --> <resources> <!-- gap on either side of status bar notification icons --> - <dimen name="status_bar_icon_padding">2dp</dimen> + <dimen name="status_bar_icon_padding">0dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml new file mode 100644 index 0000000..74b266d --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (c) 2011, The Android Open Source 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. +*/ +--> +<resources> + <!-- gap on either side of status bar notification icons --> + <dimen name="status_bar_icon_padding">2dp</dimen> +</resources> + diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml new file mode 100644 index 0000000..56b8e54 --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp/config.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source 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. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <integer name="config_maxNotificationIcons">5</integer> +</resources> + diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 954a871..7a4ac5d 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -25,16 +25,14 @@ data icon on devices --> <bool name="config_hspa_data_distinguishable">false</bool> - <!-- The location of the status bar. - 0 - top - 1 - bottom - --> - <integer name="config_status_bar_position">0</integer> - <!-- Component to be used as the status bar service. Must implement the IStatusBar interface. This name is in the ComponentName flattened format (package/class) --> <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string> + <!-- Component to be used as the system bar service. Must implement the IStatusBar + interface. This name is in the ComponentName flattened format (package/class) --> + <string name="config_systemBarComponent" translatable="false">com.android.systemui.statusbar.tablet.TabletStatusBar</string> + <!-- Whether or not we show the number in the bar. --> <bool name="config_statusBarShowNumber">true</bool> @@ -42,5 +40,8 @@ autodetected from the Configuration. --> <bool name="config_showNavigationBar">false</bool> + <!-- How many icons may be shown at once in the system bar. Includes any + slots that may be reused for things like IME control. --> + <integer name="config_maxNotificationIcons">5</integer> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java index 870acd3..d7a5056 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java @@ -27,7 +27,10 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Binder; import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Slog; +import android.view.IWindowManager; public class SystemUIService extends Service { static final String TAG = "SystemUIService"; @@ -36,7 +39,7 @@ public class SystemUIService extends Service { * The class names of the stuff to start. */ final Object[] SERVICES = new Object[] { - R.string.config_statusBarComponent, + 0, // system bar or status bar, filled in below. com.android.systemui.power.PowerUI.class, }; @@ -62,6 +65,17 @@ public class SystemUIService extends Service { @Override public void onCreate() { + // Pick status bar or system bar. + IWindowManager wm = IWindowManager.Stub.asInterface( + ServiceManager.getService(Context.WINDOW_SERVICE)); + try { + SERVICES[0] = wm.canStatusBarHide() + ? R.string.config_statusBarComponent + : R.string.config_systemBarComponent; + } catch (RemoteException e) { + Slog.w(TAG, "Failing checking whether status bar can hide", e); + } + final int N = SERVICES.length; mServices = new SystemUI[N]; for (int i=0; i<N; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java new file mode 100644 index 0000000..c3052e8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CompatModeButton.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008 The Android Open Source 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.android.systemui.statusbar.policy; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.res.TypedArray; +import android.os.RemoteException; +import android.util.AttributeSet; +import android.util.Slog; +import android.view.View; +import android.widget.ImageView; + +import com.android.systemui.R; + +public class CompatModeButton extends ImageView implements View.OnClickListener { + private static final String TAG = "StatusBar.CompatModeButton"; + + private ActivityManager mAM; + + public CompatModeButton(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CompatModeButton(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs); + + setClickable(true); + + mAM = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + + setOnClickListener(this); + + refresh(); + } + + @Override + public void onClick(View v) { + mAM.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_TOGGLE); + } + + public void refresh() { + int mode = mAM.getFrontActivityScreenCompatMode(); + setVisibility((mode == ActivityManager.COMPAT_MODE_NEVER + || mode == ActivityManager.COMPAT_MODE_ALWAYS) + ? View.GONE + : View.VISIBLE + ); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 70a78df..3175a99 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -446,12 +446,14 @@ public class NetworkController extends BroadcastReceiver { } boolean isCdmaEri() { - final int iconIndex = mServiceState.getCdmaEriIconIndex(); - if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) { - final int iconMode = mServiceState.getCdmaEriIconMode(); - if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL - || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) { - return true; + if (mServiceState != null) { + final int iconIndex = mServiceState.getCdmaEriIconIndex(); + if (iconIndex != EriInfo.ROAMING_INDICATOR_OFF) { + final int iconMode = mServiceState.getCdmaEriIconMode(); + if (iconMode == EriInfo.ROAMING_ICON_MODE_NORMAL + || iconMode == EriInfo.ROAMING_ICON_MODE_FLASH) { + return true; + } } } return false; @@ -854,7 +856,7 @@ public class NetworkController extends BroadcastReceiver { pw.print(" mDataActivity="); pw.println(mDataActivity); pw.print(" mServiceState="); - pw.println(mServiceState.toString()); + pw.println(mServiceState); pw.print(" mNetworkName="); pw.println(mNetworkName); pw.print(" mNetworkNameDefault="); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java index e9db998..339e3f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodsPanel.java @@ -422,9 +422,8 @@ public class InputMethodsPanel extends LinearLayout implements StatusBarPanel, Log.d(TAG, "Get text from: " + imi.getPackageName() + subtype.getNameResId() + imi.getServiceInfo().applicationInfo); } - // TODO: Change the language of subtype name according to subtype's locale. - return mPackageManager.getText( - imi.getPackageName(), subtype.getNameResId(), imi.getServiceInfo().applicationInfo); + return subtype.getDisplayName( + mContext, imi.getPackageName(), imi.getServiceInfo().applicationInfo); } private Drawable getSubtypeIcon(InputMethodInfo imi, InputMethodSubtype subtype) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 63bc9b7..ffb45ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -69,6 +69,7 @@ import com.android.systemui.R; import com.android.systemui.statusbar.*; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BluetoothController; +import com.android.systemui.statusbar.policy.CompatModeButton; import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.Prefs; @@ -81,9 +82,6 @@ public class TabletStatusBar extends StatusBar implements public static final boolean DEBUG = false; public static final String TAG = "TabletStatusBar"; - public static final int MAX_NOTIFICATION_ICONS = 5; - // IME switcher icon is big and occupy width of two icons - public static final int MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE = MAX_NOTIFICATION_ICONS - 1; public static final int MSG_OPEN_NOTIFICATION_PANEL = 1000; public static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001; @@ -105,6 +103,7 @@ public class TabletStatusBar extends StatusBar implements int mNaturalBarHeight = -1; int mIconSize = -1; int mIconHPadding = -1; + private int mMaxNotificationIcons = 5; H mHandler = new H(); @@ -311,7 +310,7 @@ public class TabletStatusBar extends StatusBar implements final Resources res = mContext.getResources(); final Display d = WindowManagerImpl.getDefault().getDefaultDisplay(); return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height), - d.getHeight()); + d.getRealHeight()); } @Override @@ -331,10 +330,10 @@ public class TabletStatusBar extends StatusBar implements final Resources res = mContext.getResources(); mNaturalBarHeight = res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); + com.android.internal.R.dimen.system_bar_height); int newIconSize = res.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_icon_size); + com.android.internal.R.dimen.system_bar_icon_size); int newIconHPadding = res.getDimensionPixelSize( R.dimen.status_bar_icon_padding); @@ -344,6 +343,13 @@ public class TabletStatusBar extends StatusBar implements mIconSize = newIconSize; reloadAllNotificationIcons(); // reload the tray } + + final int numIcons = res.getInteger(R.integer.config_maxNotificationIcons); + if (numIcons != mMaxNotificationIcons) { + mMaxNotificationIcons = numIcons; + if (DEBUG) Slog.d(TAG, "max notification icons: " + mMaxNotificationIcons); + reloadAllNotificationIcons(); + } } protected View makeStatusBarView() { @@ -958,6 +964,10 @@ public class TabletStatusBar extends StatusBar implements // See above re: lights-out policy for legacy apps. if (visible) setLightsOn(true); + + // XXX: HACK: not sure if this is the best way to catch a new activity that might require a + // change in compatibility features, but it's a start. + ((CompatModeButton) mBarContents.findViewById(R.id.compat_button)).refresh(); } public void setImeWindowStatus(IBinder token, int vis, int backDisposition) { @@ -1430,9 +1440,11 @@ public class TabletStatusBar extends StatusBar implements // When IME button is visible, the number of notification icons should be decremented // to fit the upper limit. + // IME switcher icon is big and occupy width of one icon + final int maxNotificationIconsImeButtonVisible = mMaxNotificationIcons - 1; final int maxNotificationIconsCount = (mInputMethodSwitchButton.getVisibility() != View.GONE) ? - MAX_NOTIFICATION_ICONS_IME_BUTTON_VISIBLE : MAX_NOTIFICATION_ICONS; + maxNotificationIconsImeButtonVisible : mMaxNotificationIcons; for (int i=0; i< maxNotificationIconsCount; i++) { if (i>=N) break; toShow.add(mNotificationData.get(N-i-1).icon); diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk new file mode 100644 index 0000000..89f010a --- /dev/null +++ b/packages/VpnDialogs/Android.mk @@ -0,0 +1,27 @@ +# +# Copyright (C) 2011 The Android Open Source 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := VpnDialogs + +include $(BUILD_PACKAGE) diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml new file mode 100644 index 0000000..4e6784c --- /dev/null +++ b/packages/VpnDialogs/AndroidManifest.xml @@ -0,0 +1,22 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.vpndialogs"> + + <application android:label="VpnDialogs"> + <activity android:name=".ConfirmDialog" + android:theme="@style/transparent"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + + <activity android:name=".ManageDialog" + android:theme="@style/transparent" + android:noHistory="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/packages/VpnDialogs/res/layout/confirm.xml b/packages/VpnDialogs/res/layout/confirm.xml new file mode 100644 index 0000000..249b6e6 --- /dev/null +++ b/packages/VpnDialogs/res/layout/confirm.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source 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. +--> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <ImageView android:id="@+id/icon" + android:layout_width="@android:dimen/app_icon_size" + android:layout_height="@android:dimen/app_icon_size" + android:layout_alignParentTop="true" + android:layout_alignParentLeft="true" + android:layout_marginRight="1mm"/> + + <TextView android:id="@+id/warning" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_alignParentRight="true" + android:layout_below="@id/icon" + android:padding="2mm" + android:text="@string/warning" + android:textSize="18sp"/> + + <TextView android:id="@+id/prompt" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_alignParentRight="true" + android:layout_toRightOf="@id/icon" + android:layout_above="@id/warning" + android:gravity="center_vertical" + android:textSize="20sp"/> + + <CheckBox android:id="@+id/check" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_alignParentRight="true" + android:layout_below="@id/warning" + android:text="@string/accept" + + + android:textSize="18sp" + android:checked="false"/> + +</RelativeLayout> diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml new file mode 100644 index 0000000..330b8e3 --- /dev/null +++ b/packages/VpnDialogs/res/layout/manage.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source 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. +--> + +<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:stretchColumns="0,1"> + + <TableRow> + <TextView android:text="@string/session" style="@style/label"/> + <TextView android:id="@+id/session" style="@style/value"/> + </TableRow> + + <TableRow> + <TextView android:text="@string/duration" style="@style/label"/> + <TextView android:id="@+id/duration" style="@style/value"/> + </TableRow> + + <TableRow> + <TextView android:text="@string/data_transmitted" style="@style/label"/> + <TextView android:id="@+id/data_transmitted" style="@style/value"/> + </TableRow> + + <TableRow> + <TextView android:text="@string/data_received" style="@style/label"/> + <TextView android:id="@+id/data_received" style="@style/value"/> + </TableRow> + +</TableLayout> diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml new file mode 100644 index 0000000..8186e26 --- /dev/null +++ b/packages/VpnDialogs/res/values/strings.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source 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. +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <string name="prompt"><xliff:g id="app">%s</xliff:g> + attempts to create a VPN connection. + </string> + + <string name="warning">By proceeding, you are giving the application + permission to intercept all network traffic. + <b>Do NOT accept unless you trust the application.</b> Otherwise, + you run the risk of having your data compromised by a malicious + software. + </string> + + <string name="accept">I trust this application.</string> + + <string name="configure">Configure</string> + <string name="disconnect">Disconnect</string> + + <string name="session">Session:</string> + <string name="duration">Duration:</string> + <string name="data_transmitted">Data Transmitted:</string> + <string name="data_received">Data Received:</string> + + <string name="blank_value">--</string> + <string name="data_value_format"> + <xliff:g id="number">%1$s</xliff:g> bytes / + <xliff:g id="number">%2$s</xliff:g> packets + </string> +</resources> diff --git a/packages/VpnDialogs/res/values/styles.xml b/packages/VpnDialogs/res/values/styles.xml new file mode 100644 index 0000000..6eae218 --- /dev/null +++ b/packages/VpnDialogs/res/values/styles.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source 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. +--> + +<resources> + + <style name="transparent"> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowNoTitle">true</item> + <item name="android:windowIsFloating">true</item> + </style> + + <style name="label"> + <item name="android:gravity">center_vertical|right</item> + <item name="android:paddingRight">5mm</item> + <item name="android:textSize">16sp</item> + </style> + + <style name="value"> + <item name="android:gravity">center_vertical|left</item> + <item name="android:textSize">18sp</item> + <item name="android:textStyle">bold</item> + <item name="android:text">@string/blank_value</item> + </style> +</resources> diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java new file mode 100644 index 0000000..8fa6c7a --- /dev/null +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 The Android Open Source 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.android.vpndialogs; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.TextView; + +public class ConfirmDialog extends Activity implements CompoundButton.OnCheckedChangeListener, + DialogInterface.OnClickListener, DialogInterface.OnDismissListener { + private static final String TAG = "VpnConfirm"; + + private String mPackageName; + + private ConnectivityManager mService; + + private AlertDialog mDialog; + private Button mButton; + + @Override + protected void onResume() { + super.onResume(); + try { + mPackageName = getCallingPackage(); + mService = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + + if (mPackageName.equals(mService.prepareVpn(null))) { + setResult(RESULT_OK); + finish(); + return; + } + + PackageManager pm = getPackageManager(); + ApplicationInfo app = pm.getApplicationInfo(mPackageName, 0); + + View view = View.inflate(this, R.layout.confirm, null); + ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm)); + ((TextView) view.findViewById(R.id.prompt)).setText( + getString(R.string.prompt, app.loadLabel(pm))); + ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this); + + mDialog = new AlertDialog.Builder(this) + .setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(android.R.string.dialog_alert_title) + .setView(view) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .setCancelable(false) + .create(); + mDialog.setOnDismissListener(this); + mDialog.show(); + + mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE); + mButton.setEnabled(false); + } catch (Exception e) { + Log.e(TAG, "onResume", e); + finish(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mDialog != null) { + mDialog.setOnDismissListener(null); + mDialog.dismiss(); + } + } + + @Override + public void onCheckedChanged(CompoundButton button, boolean checked) { + mButton.setEnabled(checked); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + try { + if (which == AlertDialog.BUTTON_POSITIVE && + mPackageName.equals(mService.prepareVpn(mPackageName))) { + setResult(RESULT_OK); + } + } catch (Exception e) { + Log.e(TAG, "onClick", e); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + finish(); + } +} diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java new file mode 100644 index 0000000..853e625 --- /dev/null +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2011 The Android Open Source 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.android.vpndialogs; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.TextView; + +import java.io.DataInputStream; +import java.io.FileInputStream; + +public class ManageDialog extends Activity implements + DialogInterface.OnClickListener, DialogInterface.OnDismissListener { + private static final String TAG = "VpnManage"; + + private String mPackageName; + private String mInterfaceName; + private long mStartTime; + + private ConnectivityManager mService; + + private AlertDialog mDialog; + private TextView mDuration; + private TextView mDataTransmitted; + private TextView mDataReceived; + + private Updater mUpdater; + + @Override + protected void onResume() { + super.onResume(); + try { + Intent intent = getIntent(); + // TODO: Move constants into VpnBuilder. + mPackageName = intent.getStringExtra("packageName"); + mInterfaceName = intent.getStringExtra("interfaceName"); + mStartTime = intent.getLongExtra("startTime", 0); + + mService = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + + PackageManager pm = getPackageManager(); + ApplicationInfo app = pm.getApplicationInfo(mPackageName, 0); + + View view = View.inflate(this, R.layout.manage, null); + String session = intent.getStringExtra("session"); + if (session != null) { + ((TextView) view.findViewById(R.id.session)).setText(session); + } + mDuration = (TextView) view.findViewById(R.id.duration); + mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted); + mDataReceived = (TextView) view.findViewById(R.id.data_received); + + mDialog = new AlertDialog.Builder(this) + .setIcon(app.loadIcon(pm)) + .setTitle(app.loadLabel(pm)) + .setView(view) + .setPositiveButton(R.string.configure, this) + .setNeutralButton(R.string.disconnect, this) + .setNegativeButton(android.R.string.cancel, this) + .create(); + mDialog.setOnDismissListener(this); + mDialog.show(); + + mUpdater = new Updater(); + mUpdater.sendEmptyMessage(0); + } catch (Exception e) { + Log.e(TAG, "onResume", e); + finish(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (mDialog != null) { + mDialog.setOnDismissListener(null); + mDialog.dismiss(); + } + } + + @Override + public void onClick(DialogInterface dialog, int which) { + try { + if (which == AlertDialog.BUTTON_POSITIVE) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setPackage(mPackageName); + startActivity(intent); + } else if (which == AlertDialog.BUTTON_NEUTRAL) { + mService.prepareVpn(mPackageName); + } + } catch (Exception e) { + Log.e(TAG, "onClick", e); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + finish(); + } + + private class Updater extends Handler { + public void handleMessage(Message message) { + removeMessages(0); + + if (mDialog.isShowing()) { + if (mStartTime != 0) { + long seconds = (SystemClock.elapsedRealtime() - mStartTime) / 1000; + mDuration.setText(String.format("%02d:%02d:%02d", + seconds / 3600, seconds / 60 % 60, seconds % 60)); + } + + String[] numbers = getStatistics(); + if (numbers != null) { + // [1] and [2] are received data in bytes and packets. + mDataReceived.setText(getString(R.string.data_value_format, + numbers[1], numbers[2])); + + // [9] and [10] are transmitted data in bytes and packets. + mDataTransmitted.setText(getString(R.string.data_value_format, + numbers[9], numbers[10])); + } + sendEmptyMessageDelayed(0, 1000); + } + } + } + + private String[] getStatistics() { + DataInputStream in = null; + try { + // See dev_seq_printf_stats() in net/core/dev.c. + in = new DataInputStream(new FileInputStream("/proc/net/dev")); + String prefix = mInterfaceName + ':'; + + while (true) { + String line = in.readLine().trim(); + if (line.startsWith(prefix)) { + String[] numbers = line.substring(prefix.length()).split(" +"); + if (numbers.length == 17) { + return numbers; + } + break; + } + } + } catch (Exception e) { + // ignore + } finally { + try { + in.close(); + } catch (Exception e) { + // ignore + } + } + return null; + } +} |