Merge change 5339 into donut
* changes:
Fix intermittent crash related to call waiting
diff --git a/api/current.xml b/api/current.xml
index 658a87c..66bdb28 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -22088,6 +22088,19 @@
<parameter name="position" type="int">
</parameter>
</method>
+<method name="itemForPosition"
+ return="android.app.LauncherActivity.ListItem"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="position" type="int">
+</parameter>
+</method>
<method name="makeListItems"
return="java.util.List<android.app.LauncherActivity.ListItem>"
abstract="false"
@@ -22196,6 +22209,16 @@
visibility="public"
>
</field>
+<field name="resolveInfo"
+ type="android.content.pm.ResolveInfo"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="ListActivity"
extends="android.app.Activity"
@@ -180577,7 +180600,7 @@
<method name="startMethodTracing"
return="void"
abstract="false"
- native="true"
+ native="false"
synchronized="false"
static="true"
final="false"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index e945056..105d4d2 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -98,7 +98,7 @@
LOGD("CameraService::connect E (pid %d, client %p)", callingPid,
cameraClient->asBinder().get());
- Mutex::Autolock lock(mLock);
+ Mutex::Autolock lock(mServiceLock);
sp<Client> client;
if (mClient != 0) {
sp<Client> currentClient = mClient.promote();
@@ -125,13 +125,14 @@
LOGD("New client (pid %d) connecting, old reference was dangling...",
callingPid);
mClient.clear();
- if (mUsers > 0) {
- LOGD("Still have client, rejected");
- return client;
- }
}
}
+ if (mUsers > 0) {
+ LOGD("Still have client, rejected");
+ return client;
+ }
+
// create a new Client object
client = new Client(this, cameraClient, callingPid);
mClient = client;
@@ -152,7 +153,7 @@
// destructor won't be called with the lock held.
sp<Client> client;
- Mutex::Autolock lock(mLock);
+ Mutex::Autolock lock(mServiceLock);
if (mClient == 0) {
// This happens when we have already disconnected.
@@ -390,8 +391,6 @@
// from the user directly, or called by the destructor.
if (mHardware == 0) return;
- mCameraService->removeClient(mCameraClient);
-
LOGD("hardware teardown");
// Before destroying mHardware, we must make sure it's in the
// idle state.
@@ -402,6 +401,7 @@
mHardware->release();
mHardware.clear();
+ mCameraService->removeClient(mCameraClient);
mCameraService->decUsers();
LOGD("Client::disconnect() X (pid %d)", callingPid);
@@ -661,7 +661,7 @@
sp<Client> client = 0;
CameraService *service = static_cast<CameraService*>(user);
if (service != NULL) {
- Mutex::Autolock ourLock(service->mLock);
+ Mutex::Autolock ourLock(service->mServiceLock);
if (service->mClient != 0) {
client = service->mClient.promote();
if (client == 0) {
@@ -1104,7 +1104,7 @@
result.append(buffer);
write(fd, result.string(), result.size());
} else {
- AutoMutex lock(&mLock);
+ AutoMutex lock(&mServiceLock);
if (mClient != 0) {
sp<Client> currentClient = mClient.promote();
sprintf(buffer, "Client (%p) PID: %d\n",
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index 729e539..8b8b54c 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -199,7 +199,7 @@
virtual void incUsers();
virtual void decUsers();
- mutable Mutex mLock;
+ mutable Mutex mServiceLock;
wp<Client> mClient;
#if DEBUG_HEAP_LEAKS
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 2a4a672..3782136 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -26,10 +26,13 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.view.IWindowManager;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.util.Iterator;
import java.util.Set;
@@ -446,6 +449,8 @@
return;
}
+ ParcelFileDescriptor fd = null;
+
String cmd = nextArg();
if ("start".equals(cmd)) {
start = true;
@@ -455,6 +460,16 @@
showUsage();
return;
}
+ try {
+ fd = ParcelFileDescriptor.open(
+ new File(profileFile),
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ } catch (FileNotFoundException e) {
+ System.err.println("Error: Unable to open file: " + profileFile);
+ return;
+ }
} else if (!"stop".equals(cmd)) {
System.err.println("Error: Profile command " + cmd + " not valid");
showUsage();
@@ -462,8 +477,8 @@
}
try {
- if (!mAm.profileControl(process, start, profileFile)) {
- System.out.println("PROFILE FAILED on process " + process);
+ if (!mAm.profileControl(process, start, profileFile, fd)) {
+ System.err.println("PROFILE FAILED on process " + process);
return;
}
} catch (IllegalArgumentException e) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b6f855a..dfa8139 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -986,7 +986,9 @@
String process = data.readString();
boolean start = data.readInt() != 0;
String path = data.readString();
- boolean res = profileControl(process, start, path);
+ ParcelFileDescriptor fd = data.readInt() != 0
+ ? data.readFileDescriptor() : null;
+ boolean res = profileControl(process, start, path, fd);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
@@ -2232,7 +2234,7 @@
}
public boolean profileControl(String process, boolean start,
- String path) throws RemoteException
+ String path, ParcelFileDescriptor fd) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -2240,6 +2242,12 @@
data.writeString(process);
data.writeInt(start ? 1 : 0);
data.writeString(path);
+ if (fd != null) {
+ data.writeInt(1);
+ fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ data.writeInt(0);
+ }
mRemote.transact(PROFILE_CONTROL_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 98bd45a..79588ea 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -48,6 +48,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
+import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -74,6 +75,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -1236,6 +1238,11 @@
String who;
}
+ private static final class ProfilerControlData {
+ String path;
+ ParcelFileDescriptor fd;
+ }
+
private final class ApplicationThread extends ApplicationThreadNative {
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
private static final String ONE_COUNT_COLUMN = "%17s %8d";
@@ -1494,8 +1501,11 @@
}
}
- public void profilerControl(boolean start, String path) {
- queueOrSendMessage(H.PROFILER_CONTROL, path, start ? 1 : 0);
+ public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) {
+ ProfilerControlData pcd = new ProfilerControlData();
+ pcd.path = path;
+ pcd.fd = fd;
+ queueOrSendMessage(H.PROFILER_CONTROL, pcd, start ? 1 : 0);
}
public void setSchedulingGroup(int group) {
@@ -1838,7 +1848,7 @@
handleActivityConfigurationChanged((IBinder)msg.obj);
break;
case PROFILER_CONTROL:
- handleProfilerControl(msg.arg1 != 0, (String)msg.obj);
+ handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj);
break;
case CREATE_BACKUP_AGENT:
handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
@@ -3618,15 +3628,20 @@
performConfigurationChanged(r.activity, mConfiguration);
}
- final void handleProfilerControl(boolean start, String path) {
+ final void handleProfilerControl(boolean start, ProfilerControlData pcd) {
if (start) {
- File file = new File(path);
- file.getParentFile().mkdirs();
try {
- Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
+ Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(),
+ 8 * 1024 * 1024, 0);
} catch (RuntimeException e) {
- Log.w(TAG, "Profiling failed on path " + path
+ Log.w(TAG, "Profiling failed on path " + pcd.path
+ " -- can the process access this path?");
+ } finally {
+ try {
+ pcd.fd.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Failure closing profile fd", e);
+ }
}
} else {
Debug.stopMethodTracing();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 4b64c94..b052c99 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -26,6 +26,7 @@
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
@@ -331,7 +332,9 @@
data.enforceInterface(IApplicationThread.descriptor);
boolean start = data.readInt() != 0;
String path = data.readString();
- profilerControl(start, path);
+ ParcelFileDescriptor fd = data.readInt() != 0
+ ? data.readFileDescriptor() : null;
+ profilerControl(start, path, fd);
return true;
}
@@ -711,11 +714,18 @@
data.recycle();
}
- public void profilerControl(boolean start, String path) throws RemoteException {
+ public void profilerControl(boolean start, String path,
+ ParcelFileDescriptor fd) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeInt(start ? 1 : 0);
data.writeString(path);
+ if (fd != null) {
+ data.writeInt(1);
+ fd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ } else {
+ data.writeInt(0);
+ }
mRemote.transact(PROFILER_CONTROL_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 66bc85b..3ec7938 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -250,7 +250,7 @@
// Turn on/off profiling in a particular process.
public boolean profileControl(String process, boolean start,
- String path) throws RemoteException;
+ String path, ParcelFileDescriptor fd) throws RemoteException;
public boolean shutdown(int timeout) throws RemoteException;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 029c650..c0bc2a0 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -25,6 +25,7 @@
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
@@ -92,7 +93,8 @@
void scheduleLowMemory() throws RemoteException;
void scheduleActivityConfigurationChanged(IBinder token) throws RemoteException;
void requestPss() throws RemoteException;
- void profilerControl(boolean start, String path) throws RemoteException;
+ void profilerControl(boolean start, String path, ParcelFileDescriptor fd)
+ throws RemoteException;
void setSchedulingGroup(int group) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 8d249da..accdda9 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -60,26 +60,20 @@
* An item in the list
*/
public static class ListItem {
+ public ResolveInfo resolveInfo;
public CharSequence label;
- //public CharSequence description;
public Drawable icon;
public String packageName;
public String className;
public Bundle extras;
ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
+ this.resolveInfo = resolveInfo;
label = resolveInfo.loadLabel(pm);
if (label == null && resolveInfo.activityInfo != null) {
label = resolveInfo.activityInfo.name;
}
- /*
- if (resolveInfo.activityInfo != null &&
- resolveInfo.activityInfo.applicationInfo != null) {
- description = resolveInfo.activityInfo.applicationInfo.loadDescription(pm);
- }
- */
-
icon = resizer.createIconThumbnail(resolveInfo.loadIcon(pm));
packageName = resolveInfo.activityInfo.applicationInfo.packageName;
className = resolveInfo.activityInfo.name;
@@ -122,6 +116,14 @@
return intent;
}
+ public ListItem itemForPosition(int position) {
+ if (mActivitiesList == null) {
+ return null;
+ }
+
+ return mActivitiesList.get(position);
+ }
+
public int getCount() {
return mActivitiesList != null ? mActivitiesList.size() : 0;
}
@@ -354,6 +356,16 @@
}
/**
+ * Return the {@link ListItem} for a specific position in our
+ * {@link android.widget.ListView}.
+ * @param position The item to return
+ */
+ protected ListItem itemForPosition(int position) {
+ ActivityAdapter adapter = (ActivityAdapter) mAdapter;
+ return adapter.itemForPosition(position);
+ }
+
+ /**
* Get the base intent to use when running
* {@link PackageManager#queryIntentActivities(Intent, int)}.
*/
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 9b0cc39..6ddf50f 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -560,12 +560,8 @@
if (mGlobalSearchMode) {
mSearchAutoComplete.setDropDownAlwaysVisible(true); // fill space until results come in
- mSearchAutoComplete.setDropDownBackgroundResource(
- com.android.internal.R.drawable.search_dropdown_background);
} else {
mSearchAutoComplete.setDropDownAlwaysVisible(false);
- mSearchAutoComplete.setDropDownBackgroundResource(
- com.android.internal.R.drawable.search_dropdown_background_apps);
}
// attach the suggestions adapter, if suggestions are available
@@ -1326,6 +1322,7 @@
String query = intent.getStringExtra(SearchManager.QUERY);
setUserQuery(query);
+ mSearchAutoComplete.showDropDown();
}
/**
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 0bdb10b..49c94d1 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -147,7 +147,7 @@
final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query);
// trigger fill window so the spinner stays up until the results are copied over and
// closer to being ready
- if (!mGlobalSearchMode) cursor.getCount();
+ if (!mGlobalSearchMode && cursor != null) cursor.getCount();
return cursor;
} catch (RuntimeException e) {
Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
diff --git a/core/java/android/backup/AbsoluteFileBackupHelper.java b/core/java/android/backup/AbsoluteFileBackupHelper.java
new file mode 100644
index 0000000..ab24675
--- /dev/null
+++ b/core/java/android/backup/AbsoluteFileBackupHelper.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 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 android.backup;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileDescriptor;
+
+/**
+ * Like FileBackupHelper, but takes absolute paths for the files instead of
+ * subpaths of getFilesDir()
+ *
+ * @hide
+ */
+public class AbsoluteFileBackupHelper extends FileBackupHelperBase implements BackupHelper {
+ private static final String TAG = "AbsoluteFileBackupHelper";
+
+ Context mContext;
+ String[] mFiles;
+
+ public AbsoluteFileBackupHelper(Context context, String... files) {
+ super(context);
+
+ mContext = context;
+ mFiles = files;
+ }
+
+ /**
+ * Based on oldState, determine which of the files from the application's data directory
+ * need to be backed up, write them to the data stream, and fill in newState with the
+ * state as it exists now.
+ */
+ public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) {
+ // use the file paths as the keys, too
+ performBackup_checked(oldState, data, newState, mFiles, mFiles);
+ }
+
+ public void restoreEntity(BackupDataInputStream data) {
+ // TODO: turn this off before ship
+ Log.d(TAG, "got entity '" + data.getKey() + "' size=" + data.size());
+ String key = data.getKey();
+ if (isKeyInList(key, mFiles)) {
+ File f = new File(key);
+ writeFile(f, data);
+ }
+ }
+}
+
diff --git a/core/java/android/backup/RestoreSet.java b/core/java/android/backup/RestoreSet.java
index 96a99ae..eeca148 100644
--- a/core/java/android/backup/RestoreSet.java
+++ b/core/java/android/backup/RestoreSet.java
@@ -43,14 +43,14 @@
* transport. This is guaranteed to be valid for the duration of a restore
* session, but is meaningless once the session has ended.
*/
- public int token;
+ public long token;
public RestoreSet() {
// Leave everything zero / null
}
- public RestoreSet(String _name, String _dev, int _token) {
+ public RestoreSet(String _name, String _dev, long _token) {
name = _name;
device = _dev;
token = _token;
@@ -65,7 +65,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeString(device);
- out.writeInt(token);
+ out.writeLong(token);
}
public static final Parcelable.Creator<RestoreSet> CREATOR
@@ -82,6 +82,6 @@
private RestoreSet(Parcel in) {
name = in.readString();
device = in.readString();
- token = in.readInt();
+ token = in.readLong();
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 609fa74..6fe5506 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1578,6 +1578,16 @@
public static final String ACTION_REBOOT =
"android.intent.action.REBOOT";
+ /**
+ * @hide
+ * TODO: This will be unhidden in a later CL.
+ * Broadcast Action: The TextToSpeech synthesizer has completed processing
+ * all of the text in the speech queue.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
+ "android.intent.action.TTS_QUEUE_PROCESSING_COMPLETED";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 680fef8..179b9bd 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -17,8 +17,15 @@
package android.content.res;
import android.content.pm.ApplicationInfo;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Region;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
/**
* CompatibilityInfo class keeps the information about compatibility mode that the application is
@@ -27,6 +34,9 @@
* {@hide}
*/
public class CompatibilityInfo {
+ private static final boolean DBG = false;
+ private static final String TAG = "CompatibilityInfo";
+
/** default compatibility info object for compatible applications */
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo();
@@ -41,36 +51,75 @@
public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
/**
+ * The x-shift mode that controls the position of the content or the window under
+ * compatibility mode.
+ * {@see getTranslator}
+ * {@see Translator#mShiftMode}
+ */
+ private static final int X_SHIFT_NONE = 0;
+ private static final int X_SHIFT_CONTENT = 1;
+ private static final int X_SHIFT_AND_CLIP_CONTENT = 2;
+ private static final int X_SHIFT_WINDOW = 3;
+
+
+ /**
+ * A compatibility flags
+ */
+ private int compatibilityFlags;
+
+ /**
+ * A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f)
+ * {@see compatibilityFlag}
+ */
+ private static final int SCALING_REQUIRED = 1;
+
+ /**
+ * A flag mask to indicates that the application can expand over the original size.
+ * The flag is set to true if
+ * 1) Application declares its expandable in manifest file using <expandable /> or
+ * 2) The screen size is same as (320 x 480) * density.
+ * {@see compatibilityFlag}
+ */
+ private static final int EXPANDABLE = 2;
+
+ /**
+ * A flag mask to tell if the application is configured to be expandable. This differs
+ * from EXPANDABLE in that the application that is not expandable will be
+ * marked as expandable if it runs in (320x 480) * density screen size.
+ */
+ private static final int CONFIGURED_EXPANDABLE = 4;
+
+ private static final int SCALING_EXPANDABLE_MASK = SCALING_REQUIRED | EXPANDABLE;
+
+ /**
* Application's scale.
*/
- public final float mApplicationScale;
+ public final float applicationScale;
/**
* Application's inverted scale.
*/
- public final float mApplicationInvertedScale;
-
- /**
- * A boolean flag to indicates that the application can expand over the original size.
- * The flag is set to true if
- * 1) Application declares its expandable in manifest file using <expandable /> or
- * 2) The screen size is same as (320 x 480) * density.
- */
- public boolean mExpandable;
+ public final float applicationInvertedScale;
+
/**
- * A expandable flag in the configuration.
+ * Window size in Compatibility Mode, in real pixels. This is updated by
+ * {@link DisplayMetrics#updateMetrics}.
*/
- public final boolean mConfiguredExpandable;
+ private int mWidth;
+ private int mHeight;
/**
- * A boolean flag to tell if the application needs scaling (when mApplicationScale != 1.0f)
+ * The x offset to center the window content. In X_SHIFT_WINDOW mode, the offset is added
+ * to the window's layout. In X_SHIFT_CONTENT/X_SHIFT_AND_CLIP_CONTENT mode, the offset
+ * is used to translate the Canvas.
*/
- public final boolean mScalingRequired;
+ private int mXOffset;
public CompatibilityInfo(ApplicationInfo appInfo) {
- mExpandable = mConfiguredExpandable =
- (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0;
+ if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+ compatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
+ }
float packageDensityScale = -1.0f;
if (appInfo.supportsDensities != null) {
@@ -93,23 +142,323 @@
}
}
if (packageDensityScale > 0.0f) {
- mApplicationScale = packageDensityScale;
+ applicationScale = packageDensityScale;
} else {
- mApplicationScale = DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
+ applicationScale =
+ DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
}
- mApplicationInvertedScale = 1.0f / mApplicationScale;
- mScalingRequired = mApplicationScale != 1.0f;
+ applicationInvertedScale = 1.0f / applicationScale;
+ if (applicationScale != 1.0f) {
+ compatibilityFlags |= SCALING_REQUIRED;
+ }
}
private CompatibilityInfo() {
- mApplicationScale = mApplicationInvertedScale = 1.0f;
- mExpandable = mConfiguredExpandable = true;
- mScalingRequired = false;
+ applicationScale = applicationInvertedScale = 1.0f;
+ compatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE;
}
+ /**
+ * Sets the application's visible rect in compatibility mode.
+ * @param xOffset the application's x offset that is added to center the content.
+ * @param widthPixels the application's width in real pixels on the screen.
+ * @param heightPixels the application's height in real pixels on the screen.
+ */
+ public void setVisibleRect(int xOffset, int widthPixels, int heightPixels) {
+ this.mXOffset = xOffset;
+ mWidth = widthPixels;
+ mHeight = heightPixels;
+ }
+
+ /**
+ * Sets expandable bit in the compatibility flag.
+ */
+ public void setExpandable(boolean expandable) {
+ if (expandable) {
+ compatibilityFlags |= CompatibilityInfo.EXPANDABLE;
+ } else {
+ compatibilityFlags &= ~CompatibilityInfo.EXPANDABLE;
+ }
+ }
+
+ /**
+ * @return true if the application is configured to be expandable.
+ */
+ public boolean isConfiguredExpandable() {
+ return (compatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0;
+ }
+
+ /**
+ * @return true if the scaling is required
+ */
+ public boolean isScalingRequired() {
+ return (compatibilityFlags & SCALING_REQUIRED) != 0;
+ }
+
@Override
public String toString() {
- return "CompatibilityInfo{scale=" + mApplicationScale +
- ", expandable=" + mExpandable + "}";
+ return "CompatibilityInfo{scale=" + applicationScale +
+ ", compatibility flag=" + compatibilityFlags + "}";
}
-}
+
+ /**
+ * Returns the translator which can translate the coordinates of the window.
+ * There are five different types of Translator.
+ *
+ * 1) {@link CompatibilityInfo#X_SHIFT_AND_CLIP_CONTENT}
+ * Shift and clip the content of the window at drawing time. Used for activities'
+ * main window (with no gravity).
+ * 2) {@link CompatibilityInfo#X_SHIFT_CONTENT}
+ * Shift the content of the window at drawing time. Used for windows that is created by
+ * an application and expected to be aligned with the application window.
+ * 3) {@link CompatibilityInfo#X_SHIFT_WINDOW}
+ * Create the window with adjusted x- coordinates. This is typically used
+ * in popup window, where it has to be placed relative to main window.
+ * 4) {@link CompatibilityInfo#X_SHIFT_NONE}
+ * No adjustment required, such as dialog.
+ * 5) Same as X_SHIFT_WINDOW, but no scaling. This is used by {@link SurfaceView}, which
+ * does not require scaling, but its window's location has to be adjusted.
+ *
+ * @param params the window's parameter
+ */
+ public Translator getTranslator(WindowManager.LayoutParams params) {
+ if ( (compatibilityFlags & CompatibilityInfo.SCALING_EXPANDABLE_MASK)
+ == CompatibilityInfo.EXPANDABLE) {
+ if (DBG) Log.d(TAG, "no translation required");
+ return null;
+ }
+
+ if ((compatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) {
+ if ((params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) {
+ if (DBG) Log.d(TAG, "translation for surface view selected");
+ return new Translator(X_SHIFT_WINDOW, false, 1.0f, 1.0f);
+ } else {
+ int shiftMode;
+ if (params.gravity == Gravity.NO_GRAVITY) {
+ // For Regular Application window
+ shiftMode = X_SHIFT_AND_CLIP_CONTENT;
+ if (DBG) Log.d(TAG, "shift and clip translator");
+ } else if (params.width == WindowManager.LayoutParams.FILL_PARENT) {
+ // For Regular Application window
+ shiftMode = X_SHIFT_CONTENT;
+ if (DBG) Log.d(TAG, "shift content translator");
+ } else if ((params.gravity & Gravity.LEFT) != 0 && params.x > 0) {
+ shiftMode = X_SHIFT_WINDOW;
+ if (DBG) Log.d(TAG, "shift window translator");
+ } else {
+ shiftMode = X_SHIFT_NONE;
+ if (DBG) Log.d(TAG, "no content/window translator");
+ }
+ return new Translator(shiftMode);
+ }
+ } else if (isScalingRequired()) {
+ return new Translator();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * A helper object to translate the screen and window coordinates back and forth.
+ * @hide
+ */
+ public class Translator {
+ final private int mShiftMode;
+ final public boolean scalingRequired;
+ final public float applicationScale;
+ final public float applicationInvertedScale;
+
+ private Rect mContentInsetsBuffer = null;
+ private Rect mVisibleInsets = null;
+
+ Translator(int shiftMode, boolean scalingRequired, float applicationScale,
+ float applicationInvertedScale) {
+ mShiftMode = shiftMode;
+ this.scalingRequired = scalingRequired;
+ this.applicationScale = applicationScale;
+ this.applicationInvertedScale = applicationInvertedScale;
+ }
+
+ Translator(int shiftMode) {
+ this(shiftMode,
+ isScalingRequired(),
+ CompatibilityInfo.this.applicationScale,
+ CompatibilityInfo.this.applicationInvertedScale);
+ }
+
+ Translator() {
+ this(X_SHIFT_NONE);
+ }
+
+ /**
+ * Translate the screen rect to the application frame.
+ */
+ public void translateRectInScreenToAppWinFrame(Rect rect) {
+ if (rect.isEmpty()) return; // skip if the window size is empty.
+ switch (mShiftMode) {
+ case X_SHIFT_AND_CLIP_CONTENT:
+ rect.intersect(0, 0, mWidth, mHeight);
+ break;
+ case X_SHIFT_CONTENT:
+ rect.intersect(0, 0, mWidth + mXOffset, mHeight);
+ break;
+ case X_SHIFT_WINDOW:
+ case X_SHIFT_NONE:
+ break;
+ }
+ if (scalingRequired) {
+ rect.scale(applicationInvertedScale);
+ }
+ }
+
+ /**
+ * Translate the region in window to screen.
+ */
+ public void translateRegionInWindowToScreen(Region transparentRegion) {
+ switch (mShiftMode) {
+ case X_SHIFT_AND_CLIP_CONTENT:
+ case X_SHIFT_CONTENT:
+ transparentRegion.scale(applicationScale);
+ transparentRegion.translate(mXOffset, 0);
+ break;
+ case X_SHIFT_WINDOW:
+ case X_SHIFT_NONE:
+ transparentRegion.scale(applicationScale);
+ }
+ }
+
+ /**
+ * Apply translation to the canvas that is necessary to draw the content.
+ */
+ public void translateCanvas(Canvas canvas) {
+ if (mShiftMode == X_SHIFT_CONTENT ||
+ mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
+ // TODO: clear outside when rotation is changed.
+
+ // Translate x-offset only when the content is shifted.
+ canvas.translate(mXOffset, 0);
+ }
+ if (scalingRequired) {
+ canvas.scale(applicationScale, applicationScale);
+ }
+ }
+
+ /**
+ * Translate the motion event captured on screen to the application's window.
+ */
+ public void translateEventInScreenToAppWindow(MotionEvent event) {
+ if (mShiftMode == X_SHIFT_CONTENT ||
+ mShiftMode == X_SHIFT_AND_CLIP_CONTENT) {
+ event.translate(-mXOffset, 0);
+ }
+ if (scalingRequired) {
+ event.scale(applicationInvertedScale);
+ }
+ }
+
+ /**
+ * Translate the window's layout parameter, from application's view to
+ * Screen's view.
+ */
+ public void translateWindowLayout(WindowManager.LayoutParams params) {
+ switch (mShiftMode) {
+ case X_SHIFT_NONE:
+ case X_SHIFT_AND_CLIP_CONTENT:
+ case X_SHIFT_CONTENT:
+ params.scale(applicationScale);
+ break;
+ case X_SHIFT_WINDOW:
+ params.scale(applicationScale);
+ params.x += mXOffset;
+ break;
+ }
+ }
+
+ /**
+ * Translate a Rect in application's window to screen.
+ */
+ public void translateRectInAppWindowToScreen(Rect rect) {
+ // TODO Auto-generated method stub
+ if (scalingRequired) {
+ rect.scale(applicationScale);
+ }
+ switch(mShiftMode) {
+ case X_SHIFT_NONE:
+ case X_SHIFT_WINDOW:
+ break;
+ case X_SHIFT_CONTENT:
+ case X_SHIFT_AND_CLIP_CONTENT:
+ rect.offset(mXOffset, 0);
+ break;
+ }
+ }
+
+ /**
+ * Translate a Rect in screen coordinates into the app window's coordinates.
+ */
+ public void translateRectInScreenToAppWindow(Rect rect) {
+ switch (mShiftMode) {
+ case X_SHIFT_NONE:
+ case X_SHIFT_WINDOW:
+ break;
+ case X_SHIFT_CONTENT: {
+ rect.intersects(mXOffset, 0, rect.right, rect.bottom);
+ int dx = Math.min(mXOffset, rect.left);
+ rect.offset(-dx, 0);
+ break;
+ }
+ case X_SHIFT_AND_CLIP_CONTENT: {
+ rect.intersects(mXOffset, 0, mWidth + mXOffset, mHeight);
+ int dx = Math.min(mXOffset, rect.left);
+ rect.offset(-dx, 0);
+ break;
+ }
+ }
+ if (scalingRequired) {
+ rect.scale(applicationInvertedScale);
+ }
+ }
+
+ /**
+ * Translate the location of the sub window.
+ * @param params
+ */
+ public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
+ if (scalingRequired) {
+ params.scale(applicationScale);
+ }
+ switch (mShiftMode) {
+ // the window location on these mode does not require adjustmenet.
+ case X_SHIFT_NONE:
+ case X_SHIFT_WINDOW:
+ break;
+ case X_SHIFT_CONTENT:
+ case X_SHIFT_AND_CLIP_CONTENT:
+ params.x += mXOffset;
+ break;
+ }
+ }
+
+ /**
+ * Translate the content insets in application window to Screen. This uses
+ * the internal buffer for content insets to avoid extra object allocation.
+ */
+ public Rect getTranslatedContentInsets(Rect contentInsets) {
+ if (mContentInsetsBuffer == null) mContentInsetsBuffer = new Rect();
+ mContentInsetsBuffer.set(contentInsets);
+ translateRectInAppWindowToScreen(mContentInsetsBuffer);
+ return mContentInsetsBuffer;
+ }
+
+ /**
+ * Translate the visible insets in application window to Screen. This uses
+ * the internal buffer for content insets to avoid extra object allocation.
+ */
+ public Rect getTranslatedVisbileInsets(Rect visibleInsets) {
+ if (mVisibleInsets == null) mVisibleInsets = new Rect();
+ mVisibleInsets.set(visibleInsets);
+ translateRectInAppWindowToScreen(mVisibleInsets);
+ return mVisibleInsets;
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 71dbd38..cb9d46e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -158,10 +158,10 @@
}
updateConfiguration(config, metrics);
assets.ensureStringBlocks();
- if (!mCompatibilityInfo.mScalingRequired) {
- mPreloadedDrawables = sPreloadedDrawables;
- } else {
+ if (mCompatibilityInfo.isScalingRequired()) {
mPreloadedDrawables = emptySparseArray();
+ } else {
+ mPreloadedDrawables = sPreloadedDrawables;
}
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 8fcb4d7..d40ea6b 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -21,6 +21,7 @@
import android.util.Config;
import android.util.Log;
+import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
@@ -378,6 +379,20 @@
}
/**
+ * Like startMethodTracing(String, int, int), but taking an already-opened
+ * FileDescriptor in which the trace is written. The file name is also
+ * supplied simply for logging. Makes a dup of the file descriptor.
+ *
+ * Not exposed in the SDK unless we are really comfortable with supporting
+ * this and find it would be useful.
+ * @hide
+ */
+ public static void startMethodTracing(String traceName, FileDescriptor fd,
+ int bufferSize, int flags) {
+ VMDebug.startMethodTracing(traceName, fd, bufferSize, flags);
+ }
+
+ /**
* Determine whether method tracing is currently active.
* @hide
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5dc03eb..7356326 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1274,6 +1274,50 @@
public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
/**
+ * CDMA only settings
+ * DTMF tone type played by the dialer when dialing.
+ * 0 = Normal
+ * 1 = Long
+ * @hide
+ */
+ public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
+
+ /**
+ * CDMA only settings
+ * Emergency Tone 0 = Off
+ * 1 = Alert
+ * 2 = Vibrate
+ * @hide
+ */
+ public static final String EMERGENCY_TONE = "emergency_tone";
+
+ /**
+ * CDMA only settings
+ * Whether the auto retry is enabled. The value is
+ * boolean (1 or 0).
+ * @hide
+ */
+ public static final String CALL_AUTO_RETRY = "call_auto_retry";
+
+ /**
+ * Whether the hearing aid is enabled. The value is
+ * boolean (1 or 0).
+ * @hide
+ */
+ public static final String HEARING_AID = "hearing_aid";
+
+ /**
+ * CDMA only settings
+ * TTY Mode
+ * 0 = OFF
+ * 1 = FULL
+ * 2 = VCO
+ * 3 = HCO
+ * @hide
+ */
+ public static final String TTY_MODE = "tty_mode";
+
+ /**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
* boolean (1 or 0).
*/
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index a095913..d89ada0 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -106,16 +106,8 @@
* {@hide}
*/
public void updateMetrics(CompatibilityInfo compatibilityInfo, int orientation) {
- if (compatibilityInfo.mScalingRequired) {
- float invertedRatio = compatibilityInfo.mApplicationInvertedScale;
- density *= invertedRatio;
- scaledDensity *= invertedRatio;
- xdpi *= invertedRatio;
- ydpi *= invertedRatio;
- widthPixels *= invertedRatio;
- heightPixels *= invertedRatio;
- }
- if (!compatibilityInfo.mConfiguredExpandable) {
+ int xOffset = 0;
+ if (!compatibilityInfo.isConfiguredExpandable()) {
// Note: this assume that configuration is updated before calling
// updateMetrics method.
int defaultWidth;
@@ -141,11 +133,13 @@
if (defaultWidth == widthPixels && defaultHeight == heightPixels) {
// the screen size is same as expected size. make it expandable
- compatibilityInfo.mExpandable = true;
+ compatibilityInfo.setExpandable(true);
} else {
- compatibilityInfo.mExpandable = false;
+ compatibilityInfo.setExpandable(false);
// adjust the size only when the device's screen is bigger.
if (defaultWidth < widthPixels) {
+ // content/window's x offset in original pixels
+ xOffset = ((widthPixels - defaultWidth) / 2);
widthPixels = defaultWidth;
}
if (defaultHeight < heightPixels) {
@@ -153,8 +147,19 @@
}
}
}
+ compatibilityInfo.setVisibleRect(xOffset, widthPixels, heightPixels);
+ if (compatibilityInfo.isScalingRequired()) {
+ float invertedRatio = compatibilityInfo.applicationInvertedScale;
+ density *= invertedRatio;
+ scaledDensity *= invertedRatio;
+ xdpi *= invertedRatio;
+ ydpi *= invertedRatio;
+ widthPixels *= invertedRatio;
+ heightPixels *= invertedRatio;
+ }
}
+ @Override
public String toString() {
return "DisplayMetrics{density=" + density + ", width=" + widthPixels +
", height=" + heightPixels + ", scaledDensity=" + scaledDensity +
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ca01448..a224ed3 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -212,28 +212,47 @@
}
/**
- * Scales down the cood of this event by the given scale.
+ * Scales down the coordination of this event by the given scale.
*
* @hide
*/
public void scale(float scale) {
- if (scale != 1.0f) {
- mX *= scale;
- mY *= scale;
- mRawX *= scale;
- mRawY *= scale;
- mSize *= scale;
- mXPrecision *= scale;
- mYPrecision *= scale;
- if (mHistory != null) {
- float[] history = mHistory;
- int length = history.length;
- for (int i = 0; i < length; i += 4) {
- history[i] *= scale; // X
- // history[i + 2] == pressure
- history[i + 1] *= scale; // Y
- history[i + 3] *= scale; // Size, TODO: square this?
- }
+ mX *= scale;
+ mY *= scale;
+ mRawX *= scale;
+ mRawY *= scale;
+ mSize *= scale;
+ mXPrecision *= scale;
+ mYPrecision *= scale;
+ if (mHistory != null) {
+ float[] history = mHistory;
+ int length = history.length;
+ for (int i = 0; i < length; i += 4) {
+ history[i] *= scale; // X
+ history[i + 1] *= scale; // Y
+ // no need to scale pressure ([i+2])
+ history[i + 3] *= scale; // Size, TODO: square this?
+ }
+ }
+ }
+
+ /**
+ * Translate the coordination of the event by given x and y.
+ *
+ * @hide
+ */
+ public void translate(float dx, float dy) {
+ mX += dx;
+ mY += dy;
+ mRawX += dx;
+ mRawY += dx;
+ if (mHistory != null) {
+ float[] history = mHistory;
+ int length = history.length;
+ for (int i = 0; i < length; i += 4) {
+ history[i] += dx; // X
+ history[i + 1] += dy; // Y
+ // no need to translate pressure (i+2) and size (i+3)
}
}
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 082cca2..45b0f0a7 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.CompatibilityInfo;
+import android.content.res.CompatibilityInfo.Translator;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
@@ -138,24 +139,21 @@
int mFormat = -1;
int mType = -1;
final Rect mSurfaceFrame = new Rect();
- private final CompatibilityInfo mCompatibilityInfo;
+ private Translator mTranslator;
public SurfaceView(Context context) {
super(context);
setWillNotDraw(true);
- mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
public SurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(true);
- mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(true);
- mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
/**
@@ -258,9 +256,9 @@
public boolean dispatchTouchEvent(MotionEvent event) {
// SurfaceView uses pre-scaled size unless fixed size is requested. This hook
// scales the event back to the pre-scaled coordinates for such surface.
- if (mRequestedWidth < 0 && mCompatibilityInfo.mScalingRequired) {
+ if (mRequestedWidth < 0 && mTranslator != null) {
MotionEvent scaledBack = MotionEvent.obtain(event);
- scaledBack.scale(mCompatibilityInfo.mApplicationScale);
+ scaledBack.scale(mTranslator.applicationScale);
try {
return super.dispatchTouchEvent(scaledBack);
} finally {
@@ -297,15 +295,18 @@
if (!mHaveFrame) {
return;
}
- float appScale = mCompatibilityInfo.mApplicationScale;
+ mTranslator = ((ViewRoot)getRootView().getParent()).mTranslator;
+
+ float appScale = mTranslator == null ? 1.0f : mTranslator.applicationScale;
int myWidth = mRequestedWidth;
if (myWidth <= 0) myWidth = getWidth();
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
- // Use original size for surface unless fixed size is requested.
- if (mRequestedWidth <= 0 && mCompatibilityInfo.mScalingRequired) {
+ // Use original size if the app specified the size of the view,
+ // and let the flinger to scale up.
+ if (mRequestedWidth <= 0 && mTranslator != null && mTranslator.scalingRequired) {
myWidth *= appScale;
myHeight *= appScale;
}
@@ -325,7 +326,7 @@
+ " visible=" + visibleChanged
+ " left=" + (mLeft != mLocation[0])
+ " top=" + (mTop != mLocation[1]));
-
+
try {
final boolean visible = mVisible = mRequestedVisible;
mLeft = mLocation[0];
@@ -335,16 +336,23 @@
mFormat = mRequestedFormat;
mType = mRequestedType;
- // Scaling window's layout here because mLayout is not used elsewhere.
- mLayout.x = (int) (mLeft * appScale);
- mLayout.y = (int) (mTop * appScale);
- mLayout.width = (int) (getWidth() * appScale);
- mLayout.height = (int) (getHeight() * appScale);
+ // Scaling/Translate window's layout here because mLayout is not used elsewhere.
+
+ // Places the window relative
+ mLayout.x = mLeft;
+ mLayout.y = mTop;
+ mLayout.width = getWidth();
+ mLayout.height = getHeight();
+ if (mTranslator != null) {
+ mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
+ }
+
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_SCALED
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING
;
mLayout.memoryType = mRequestedType;
@@ -371,13 +379,6 @@
visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
mVisibleInsets, mSurface);
- if (mCompatibilityInfo.mScalingRequired) {
- float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
- mContentInsets.scale(invertedScale);
- mVisibleInsets.scale(invertedScale);
- mWinFrame.scale(invertedScale);
- }
-
if (localLOGV) Log.i(TAG, "New surface: " + mSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;
@@ -446,24 +447,14 @@
private static class MyWindow extends IWindow.Stub {
private final WeakReference<SurfaceView> mSurfaceView;
- private final CompatibilityInfo mCompatibilityInfo;
public MyWindow(SurfaceView surfaceView) {
mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
- mCompatibilityInfo = surfaceView.getContext().getResources().getCompatibilityInfo();
}
public void resized(int w, int h, Rect coveredInsets,
Rect visibleInsets, boolean reportDraw) {
SurfaceView surfaceView = mSurfaceView.get();
- if (mCompatibilityInfo.mScalingRequired) {
- float scale = mCompatibilityInfo.mApplicationInvertedScale;
- w *= scale;
- h *= scale;
- coveredInsets.scale(scale);
- visibleInsets.scale(scale);
- }
-
if (surfaceView != null) {
if (localLOGV) Log.v(
"SurfaceView", surfaceView + " got resized: w=" +
@@ -626,9 +617,6 @@
Canvas c = null;
if (!mDrawingStopped && mWindow != null) {
Rect frame = dirty != null ? dirty : mSurfaceFrame;
- if (mCompatibilityInfo.mScalingRequired) {
- frame.scale(mCompatibilityInfo.mApplicationScale);
- }
try {
c = mSurface.lockCanvas(frame);
} catch (Exception e) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f17f0e4..3bfdde8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6543,7 +6543,7 @@
boolean changed = false;
if (DBG) {
- System.out.println(this + " View.setFrame(" + left + "," + top + ","
+ Log.d("View", this + " View.setFrame(" + left + "," + top + ","
+ right + "," + bottom + ")");
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index d35b048..65457c5 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -128,13 +128,12 @@
Rect mDirty; // will be a graphics.Region soon
boolean mIsAnimating;
- private CompatibilityInfo mCompatibilityInfo;
+ CompatibilityInfo.Translator mTranslator;
final View.AttachInfo mAttachInfo;
final Rect mTempRect; // used in the transaction to not thrash the heap.
final Rect mVisRect; // used to retrieve visible rect of focused view.
- final Point mVisPoint; // used to retrieve global offset of focused view.
boolean mTraversalScheduled;
boolean mWillDrawSoon;
@@ -218,7 +217,6 @@
mDirty = new Rect();
mTempRect = new Rect();
mVisRect = new Rect();
- mVisPoint = new Point();
mWinFrame = new Rect();
mWindow = new W(this, context);
mInputMethodCallback = new InputMethodCallback(this);
@@ -387,20 +385,25 @@
if (mView == null) {
mView = view;
mWindowAttributes.copyFrom(attrs);
- mCompatibilityInfo = mView.getContext().getResources().getCompatibilityInfo();
+
+ CompatibilityInfo compatibilityInfo =
+ mView.getContext().getResources().getCompatibilityInfo();
+ mTranslator = compatibilityInfo.getTranslator(attrs);
boolean restore = false;
- if (mCompatibilityInfo.mScalingRequired || !mCompatibilityInfo.mExpandable) {
+ if (attrs != null && mTranslator != null) {
restore = true;
- mWindowAttributes.backup();
+ attrs.backup();
+ mTranslator.translateWindowLayout(attrs);
}
- if (!mCompatibilityInfo.mExpandable) {
- adjustWindowAttributesForCompatibleMode(mWindowAttributes);
- }
+ if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
+
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mAttachInfo.mRootView = view;
- mAttachInfo.mScalingRequired = mCompatibilityInfo.mScalingRequired;
- mAttachInfo.mApplicationScale = mCompatibilityInfo.mApplicationScale;
+ mAttachInfo.mScalingRequired =
+ mTranslator == null ? false : mTranslator.scalingRequired;
+ mAttachInfo.mApplicationScale =
+ mTranslator == null ? 1.0f : mTranslator.applicationScale;
if (panelParentView != null) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
@@ -421,15 +424,14 @@
mAttachInfo.mRootView = null;
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
+ } finally {
+ if (restore) {
+ attrs.restore();
+ }
}
- if (restore) {
- mWindowAttributes.restore();
- }
-
- if (mCompatibilityInfo.mScalingRequired) {
- mAttachInfo.mContentInsets.scale(
- mCompatibilityInfo.mApplicationInvertedScale);
+ if (mTranslator != null) {
+ mTranslator.translateRectInScreenToAppWindow(mAttachInfo.mContentInsets);
}
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
@@ -541,14 +543,14 @@
public void invalidateChild(View child, Rect dirty) {
checkThread();
- if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
- if (mCurScrollY != 0 || mCompatibilityInfo.mScalingRequired) {
+ if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
+ if (mCurScrollY != 0 || mTranslator != null) {
mTempRect.set(dirty);
if (mCurScrollY != 0) {
mTempRect.offset(0, -mCurScrollY);
}
- if (mCompatibilityInfo.mScalingRequired) {
- mTempRect.scale(mCompatibilityInfo.mApplicationScale);
+ if (mTranslator != null) {
+ mTranslator.translateRectInAppWindowToScreen(mTempRect);
}
dirty = mTempRect;
}
@@ -567,7 +569,7 @@
return null;
}
- public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
+ public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
if (child != mView) {
throw new RuntimeException("child is not mine, honest!");
}
@@ -628,14 +630,14 @@
boolean viewVisibilityChanged = mViewVisibility != viewVisibility
|| mNewSurfaceNeeded;
- float appScale = mCompatibilityInfo.mApplicationScale;
+ float appScale = mAttachInfo.mApplicationScale;
WindowManager.LayoutParams params = null;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
params = lp;
}
-
+ Rect frame = mWinFrame;
if (mFirst) {
fullRedrawNeeded = true;
mLayoutRequested = true;
@@ -660,11 +662,11 @@
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
} else {
- desiredWindowWidth = mWinFrame.width();
- desiredWindowHeight = mWinFrame.height();
+ desiredWindowWidth = frame.width();
+ desiredWindowHeight = frame.height();
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
if (DEBUG_ORIENTATION) Log.v("ViewRoot",
- "View " + host + " resized to: " + mWinFrame);
+ "View " + host + " resized to: " + frame);
fullRedrawNeeded = true;
mLayoutRequested = true;
windowResizesToFitContent = true;
@@ -810,7 +812,6 @@
}
}
- final Rect frame = mWinFrame;
boolean initialized = false;
boolean contentInsetsChanged = false;
boolean visibleInsetsChanged;
@@ -883,7 +884,7 @@
} catch (RemoteException e) {
}
if (DEBUG_ORIENTATION) Log.v(
- "ViewRoot", "Relayout returned: frame=" + mWinFrame + ", surface=" + mSurface);
+ "ViewRoot", "Relayout returned: frame=" + frame + ", surface=" + mSurface);
attachInfo.mWindowLeft = frame.left;
attachInfo.mWindowTop = frame.top;
@@ -958,7 +959,6 @@
if (Config.DEBUG && ViewDebug.profileLayout) {
startTime = SystemClock.elapsedRealtime();
}
-
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@@ -985,7 +985,10 @@
mTmpLocation[1] + host.mBottom - host.mTop);
host.gatherTransparentRegion(mTransparentRegion);
- mTransparentRegion.scale(appScale);
+ if (mTranslator != null) {
+ mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
+ }
+
if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
mPreviousTransparentRegion.set(mTransparentRegion);
// reconfigure window manager
@@ -1016,15 +1019,17 @@
= givenContent.bottom = givenVisible.left = givenVisible.top
= givenVisible.right = givenVisible.bottom = 0;
attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
- if (mCompatibilityInfo.mScalingRequired) {
- insets.contentInsets.scale(appScale);
- insets.visibleInsets.scale(appScale);
+ Rect contentInsets = insets.contentInsets;
+ Rect visibleInsets = insets.visibleInsets;
+ if (mTranslator != null) {
+ contentInsets = mTranslator.getTranslatedContentInsets(contentInsets);
+ visibleInsets = mTranslator.getTranslatedVisbileInsets(visibleInsets);
}
if (insetsPending || !mLastGivenInsets.equals(insets)) {
mLastGivenInsets.set(insets);
try {
sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
- insets.contentInsets, insets.visibleInsets);
+ contentInsets, visibleInsets);
} catch (RemoteException e) {
}
}
@@ -1167,8 +1172,8 @@
mCurScrollY = yoff;
fullRedrawNeeded = true;
}
- float appScale = mCompatibilityInfo.mApplicationScale;
- boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
+ float appScale = mAttachInfo.mApplicationScale;
+ boolean scalingRequired = mAttachInfo.mScalingRequired;
Rect dirty = mDirty;
if (mUseGL) {
@@ -1187,8 +1192,8 @@
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
- if (scalingRequired) {
- canvas.scale(appScale, appScale);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(canvas);
}
mView.draw(canvas);
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@@ -1239,7 +1244,6 @@
int top = dirty.top;
int right = dirty.right;
int bottom = dirty.bottom;
-
canvas = surface.lockCanvas(dirty);
if (left != dirty.left || top != dirty.top || right != dirty.right ||
@@ -1295,8 +1299,8 @@
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
- if (scalingRequired) {
- canvas.scale(appScale, appScale);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(canvas);
}
mView.draw(canvas);
} finally {
@@ -1599,10 +1603,9 @@
} else {
didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
}
- if (event != null && mCompatibilityInfo.mScalingRequired) {
- event.scale(mCompatibilityInfo.mApplicationInvertedScale);
+ if (event != null && mTranslator != null) {
+ mTranslator.translateEventInScreenToAppWindow(event);
}
-
try {
boolean handled;
if (mView != null && mAdded && event != null) {
@@ -1688,6 +1691,7 @@
case RESIZED:
Rect coveredInsets = ((Rect[])msg.obj)[0];
Rect visibleInsets = ((Rect[])msg.obj)[1];
+
if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
&& mPendingContentInsets.equals(coveredInsets)
&& mPendingVisibleInsets.equals(visibleInsets)) {
@@ -1722,7 +1726,7 @@
if (mGlWanted && !mUseGL) {
initializeGL();
if (mGlCanvas != null) {
- float appScale = mCompatibilityInfo.mApplicationScale;
+ float appScale = mAttachInfo.mApplicationScale;
mGlCanvas.setViewport(
(int) (mWidth * appScale), (int) (mHeight * appScale));
}
@@ -2356,18 +2360,16 @@
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
+
+ float appScale = mAttachInfo.mApplicationScale;
boolean restore = false;
- float appScale = mCompatibilityInfo.mApplicationScale;
- boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
- if (params != null && !mCompatibilityInfo.mExpandable) {
+ if (params != null && mTranslator != null) {
restore = true;
params.backup();
- adjustWindowAttributesForCompatibleMode(params);
+ mTranslator.translateWindowLayout(params);
}
- if (params != null && scalingRequired) {
- if (!restore) params.backup();
- restore = true;
- params.scale(appScale);
+ if (params != null) {
+ if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
}
int relayoutResult = sWindowSession.relayout(
mWindow, params,
@@ -2378,44 +2380,16 @@
if (restore) {
params.restore();
}
- if (scalingRequired) {
- float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
- mPendingContentInsets.scale(invertedScale);
- mPendingVisibleInsets.scale(invertedScale);
- mWinFrame.scale(invertedScale);
+
+ if (mTranslator != null) {
+ mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
+ mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
+ mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
}
return relayoutResult;
}
/**
- * Adjust the window's layout parameter for compatibility mode. It replaces FILL_PARENT
- * with the default window size, and centers if the window wanted to fill
- * horizontally.
- *
- * @param attrs the window's layout params to adjust
- */
- private void adjustWindowAttributesForCompatibleMode(WindowManager.LayoutParams attrs) {
- // fix app windows only
- if (attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
- DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
- // TODO: improve gravity logic
- if (attrs.width == ViewGroup.LayoutParams.FILL_PARENT) {
- attrs.width = metrics.widthPixels;
- attrs.gravity |= Gravity.CENTER_HORIZONTAL;
- mWindowAttributesChanged = attrs == mWindowAttributes;
- }
- if (attrs.height == ViewGroup.LayoutParams.FILL_PARENT) {
- attrs.height = metrics.heightPixels;
- attrs.gravity |= Gravity.TOP;
- mWindowAttributesChanged = attrs == mWindowAttributes;
- }
- if (DEBUG_LAYOUT) {
- Log.d(TAG, "Adjusted Attributes for compatibility : " + attrs);
- }
- }
- }
-
- /**
* {@inheritDoc}
*/
public void playSoundEffect(int effectId) {
@@ -2518,16 +2492,14 @@
+ " visibleInsets=" + visibleInsets.toShortString()
+ " reportDraw=" + reportDraw);
Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
- if (mCompatibilityInfo.mScalingRequired) {
- float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
- coveredInsets.scale(invertedScale);
- visibleInsets.scale(invertedScale);
- msg.arg1 = (int) (w * invertedScale);
- msg.arg2 = (int) (h * invertedScale);
- } else {
- msg.arg1 = w;
- msg.arg2 = h;
+ if (mTranslator != null) {
+ mTranslator.translateRectInScreenToAppWindow(coveredInsets);
+ mTranslator.translateRectInScreenToAppWindow(visibleInsets);
+ w *= mTranslator.applicationInvertedScale;
+ h *= mTranslator.applicationInvertedScale;
}
+ msg.arg1 = w;
+ msg.arg2 = h;
msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
sendMessage(msg);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e295d15..bdb86d7 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -483,6 +483,12 @@
* {@hide} */
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
+ /** Window flag: special flag to let a window ignore the compatibility scaling.
+ * This is used by SurfaceView to create a window that does not scale the content.
+ *
+ * {@hide} */
+ public static final int FLAG_NO_COMPATIBILITY_SCALING = 0x00100000;
+
/** Window flag: a special option intended for system dialogs. When
* this flag is set, the window will demand focus unconditionally when
* it is created.
@@ -978,8 +984,9 @@
/**
* Scale the layout params' coordinates and size.
+ * @hide
*/
- void scale(float scale) {
+ public void scale(float scale) {
x *= scale;
y *= scale;
if (width > 0) {
@@ -997,14 +1004,13 @@
void backup() {
int[] backup = mCompatibilityParamsBackup;
if (backup == null) {
- // we backup 5 elements, x, y, width, height and gravity.
- backup = mCompatibilityParamsBackup = new int[5];
+ // we backup 4 elements, x, y, width, height
+ backup = mCompatibilityParamsBackup = new int[4];
}
backup[0] = x;
backup[1] = y;
backup[2] = width;
backup[3] = height;
- backup[4] = gravity;
}
/**
@@ -1018,7 +1024,6 @@
y = backup[1];
width = backup[2];
height = backup[3];
- gravity = backup[4];
}
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 6532125..f8a6f89 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3264,9 +3264,13 @@
if (mChoiceMode == CHOICE_MODE_MULTIPLE) {
mCheckStates.put(position, value);
} else {
- boolean oldValue = mCheckStates.get(position, false);
+ // Clear the old value: if something was selected and value == false
+ // then it is unselected
mCheckStates.clear();
- if (!oldValue) {
+ // If value == true, select the appropriate position
+ // this may end up selecting the value we just cleared but this way
+ // we don't have to first to a get(position)
+ if (value) {
mCheckStates.put(position, true);
}
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index bd6edfb..0c2cd55 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -990,7 +990,7 @@
int bottomEdge = displayFrame.bottom;
if (ignoreBottomDecorations) {
- bottomEdge = WindowManagerImpl.getDefault().getDefaultDisplay().getHeight();
+ bottomEdge = anchor.getContext().getResources().getDisplayMetrics().heightPixels;
}
final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 68dafa1..955475e4 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -40,7 +40,6 @@
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.LinkedList;
-import java.util.ArrayList;
import java.util.HashSet;
/**
@@ -279,6 +278,17 @@
graph.getSortedViews(mSortedVerticalChildren, ABOVE, BELOW, ALIGN_BASELINE,
ALIGN_TOP, ALIGN_BOTTOM);
graph.getSortedViews(mSortedHorizontalChildren, LEFT_OF, RIGHT_OF, ALIGN_LEFT, ALIGN_RIGHT);
+
+ if (DEBUG_GRAPH) {
+ d(LOG_TAG, "=== Ordered list of vertical children");
+ for (View view : mSortedVerticalChildren) {
+ DependencyGraph.printViewId(getResources(), view);
+ }
+ d(LOG_TAG, "=== Ordered list of horizontal children");
+ for (View view : mSortedHorizontalChildren) {
+ DependencyGraph.printViewId(getResources(), view);
+ }
+ }
}
@Override
@@ -333,16 +343,16 @@
ignore = findViewById(mIgnoreGravity);
}
-
View[] views = mSortedVerticalChildren;
int count = views.length;
for (int i = 0; i < count; i++) {
View child = views[i];
if (child.getVisibility() != GONE) {
LayoutParams params = (LayoutParams) child.getLayoutParams();
- applyVerticalSizeRules(params, myHeight);
- measureChildVertical(child, params, myHeight);
- positionChildVertical(child, params, myHeight);
+
+ applyHorizontalSizeRules(params, myWidth);
+ measureChildHorizontal(child, params, myWidth);
+ positionChildHorizontal(child, params, myWidth);
}
}
@@ -352,9 +362,10 @@
View child = views[i];
if (child.getVisibility() != GONE) {
LayoutParams params = (LayoutParams) child.getLayoutParams();
- applyHorizontalSizeRules(params, myWidth);
+
+ applyVerticalSizeRules(params, myHeight);
measureChild(child, params, myWidth, myHeight);
- positionChildHorizontal(child, params, myWidth);
+ positionChildVertical(child, params, myHeight);
if (widthMode != MeasureSpec.EXACTLY) {
width = Math.max(width, params.mRight);
@@ -499,13 +510,13 @@
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
- private void measureChildVertical(View child, LayoutParams params, int myHeight) {
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- int childHeightMeasureSpec = getChildMeasureSpec(params.mTop,
- params.mBottom, params.height,
- params.topMargin, params.bottomMargin,
- mPaddingTop, mPaddingBottom,
- myHeight);
+ private void measureChildHorizontal(View child, LayoutParams params, int myWidth) {
+ int childWidthMeasureSpec = getChildMeasureSpec(params.mLeft,
+ params.mRight, params.width,
+ params.leftMargin, params.rightMargin,
+ mPaddingLeft, mPaddingRight,
+ myWidth);
+ int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
@@ -755,18 +766,16 @@
private View getRelatedView(int[] rules, int relation) {
int id = rules[relation];
if (id != 0) {
- View v = findViewById(id);
- if (v == null) {
- return null;
- }
+ DependencyGraph.Node node = mGraph.mNodes.get(id);
+ if (node == null) return null;
+ View v = node.view;
// Find the first non-GONE view up the chain
while (v.getVisibility() == View.GONE) {
rules = ((LayoutParams) v.getLayoutParams()).getRules();
- v = v.findViewById(rules[relation]);
- if (v == null) {
- return null;
- }
+ node = mGraph.mNodes.get((rules[relation]));
+ if (node == null) return null;
+ v = node.view;
}
return v;
@@ -1100,12 +1109,6 @@
private static class DependencyGraph {
/**
- * List of views with no id. These views cannot be dependencies of
- * other views, so treat the apart for faster processing.
- */
- private ArrayList<View> mNakedRoots = new ArrayList<View>();
-
- /**
* List of nodes in the graph. Each node is identified by its
* view id (see View#getId()).
*/
@@ -1129,7 +1132,6 @@
}
nodes.clear();
- mNakedRoots.clear();
mRoots.clear();
}
@@ -1139,13 +1141,7 @@
* @param view The view to be added as a node to the graph.
*/
void add(View view) {
- final int id = view.getId();
-
- if (id != View.NO_ID) {
- mNodes.put(id, Node.acquire(view));
- } else {
- mNakedRoots.add(view);
- }
+ mNodes.put(view.getId(), Node.acquire(view));
}
/**
@@ -1162,12 +1158,6 @@
final LinkedList<Node> roots = findRoots(rules);
int index = 0;
- final ArrayList<View> nakedRoots = mNakedRoots;
- final int count = nakedRoots.size();
- for ( ; index < count; index++) {
- sorted[index] = nakedRoots.get(index);
- }
-
while (roots.size() > 0) {
final Node node = roots.removeFirst();
final View view = node.view;
@@ -1259,17 +1249,13 @@
* @param rules The list of rules to take into account.
*/
void log(Resources resources, int... rules) {
- for (View view : mNakedRoots) {
- printViewId(resources, view);
- }
-
final LinkedList<Node> roots = findRoots(rules);
for (Node node : roots) {
printNode(resources, node);
}
}
- private static void printViewId(Resources resources, View view) {
+ static void printViewId(Resources resources, View view) {
if (view.getId() != View.NO_ID) {
d(LOG_TAG, resources.getResourceEntryName(view.getId()));
} else {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9479f9e..d8ed4f0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3681,12 +3681,13 @@
@Override
protected boolean isPaddingOffsetRequired() {
- return mShadowRadius != 0;
+ return mShadowRadius != 0 || mDrawables != null;
}
@Override
protected int getLeftPaddingOffset() {
- return (int) Math.min(0, mShadowDx - mShadowRadius);
+ return getCompoundPaddingLeft() - mPaddingLeft +
+ (int) Math.min(0, mShadowDx - mShadowRadius);
}
@Override
@@ -3701,7 +3702,8 @@
@Override
protected int getRightPaddingOffset() {
- return (int) Math.max(0, mShadowDx + mShadowRadius);
+ return -(getCompoundPaddingRight() - mPaddingRight) +
+ (int) Math.max(0, mShadowDx + mShadowRadius);
}
@Override
@@ -6665,9 +6667,10 @@
} else if (getLineCount() == 1) {
switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.LEFT:
- return (mLayout.getLineRight(0) - mScrollX - (mRight - mLeft) -
- getCompoundPaddingLeft() - getCompoundPaddingRight()) /
- getHorizontalFadingEdgeLength();
+ final int textWidth = (mRight - mLeft) - getCompoundPaddingLeft() -
+ getCompoundPaddingRight();
+ final float lineWidth = mLayout.getLineWidth(0);
+ return (lineWidth - textWidth) / getHorizontalFadingEdgeLength();
case Gravity.RIGHT:
return 0.0f;
case Gravity.CENTER_HORIZONTAL:
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index ce32754..4bac593 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -37,6 +37,7 @@
void notePhoneOff();
void notePhoneSignalStrength(in SignalStrength signalStrength);
void notePhoneDataConnectionState(int dataType, boolean hasData);
+ void noteAirplaneMode(boolean isAirplaneMode);
void noteWifiOn(int uid);
void noteWifiOff(int uid);
void noteWifiRunning();
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 84ed729..ec63528 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -54,63 +54,70 @@
long requestBackupTime();
/**
- * Establish a connection to the back-end data repository, if necessary. If the transport
- * needs to initialize state that is not tied to individual applications' backup operations,
- * this is where it should be done.
- *
- * @return Zero on success; a nonzero error code on failure.
- */
- int startSession();
-
- /**
- * Send one application's data to the backup destination.
+ * Send one application's data to the backup destination. The transport may send
+ * the data immediately, or may buffer it. After this is called, {@link #finishBackup}
+ * must be called to ensure the data is sent and recorded successfully.
*
* @param packageInfo The identity of the application whose data is being backed up.
* This specifically includes the signature list for the package.
* @param data The data stream that resulted from invoking the application's
* BackupService.doBackup() method. This may be a pipe rather than a file on
* persistent media, so it may not be seekable.
- * @return Zero on success; a nonzero error code on failure.
+ * @return false if errors occurred (the backup should be aborted and rescheduled),
+ * true if everything is OK so far (but {@link #finishBackup} must be called).
*/
- int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor data);
+ boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
+
+ /**
+ * Finish sending application data to the backup destination. This must be
+ * called after {@link #performBackup} to ensure that all data is sent. Only
+ * when this method returns true can the backup be assumed to have succeeded.
+ *
+ * @return false if errors occurred (the backup should be aborted and rescheduled),
+ * true if everything is OK so far (but {@link #finishBackup} must be called).
+ */
+ boolean finishBackup();
/**
* Get the set of backups currently available over this transport.
*
- * @return Descriptions of the set of restore images available for this device.
+ * @return Descriptions of the set of restore images available for this device,
+ * or null if an error occurred (the attempt should be rescheduled).
**/
RestoreSet[] getAvailableRestoreSets();
/**
- * Get the set of applications from a given restore image.
+ * Start restoring application data from backup. After calling this function,
+ * alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData}
+ * to walk through the actual application data.
*
* @param token A backup token as returned by {@link #getAvailableRestoreSets}.
- * @return An array of PackageInfo objects describing all of the applications
- * available for restore from this restore image. This should include the list
- * of signatures for each package so that the Backup Manager can filter using that
- * information.
+ * @param packages List of applications to restore (if data is available).
+ * Application data will be restored in the order given.
+ * @return false if errors occurred (the restore should be aborted and rescheduled),
+ * true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
*/
- PackageInfo[] getAppSet(int token);
+ boolean startRestore(long token, in PackageInfo[] packages);
/**
- * Retrieve one application's data from the backing store.
- *
- * @param token The backup record from which a restore is being requested.
- * @param packageInfo The identity of the application whose data is being restored.
- * This must include the signature list for the package; it is up to the transport
- * to verify that the requested app's signatures match the saved backup record
- * because the transport cannot necessarily trust the client device.
- * @param data An open, writable file into which the backup image should be stored.
- * @return Zero on success; a nonzero error code on failure.
+ * Get the package name of the next application with data in the backup store.
+ * @return The name of one of the packages supplied to {@link #startRestore},
+ * or "" (the empty string) if no more backup data is available,
+ * or null if an error occurred (the restore should be aborted and rescheduled).
*/
- int getRestoreData(int token, in PackageInfo packageInfo, in ParcelFileDescriptor data);
+ String nextRestorePackage();
/**
- * Terminate the backup session, closing files, freeing memory, and cleaning up whatever
- * other state the transport required.
- *
- * @return Zero on success; a nonzero error code on failure. Even on failure, the session
- * is torn down and must be restarted if another backup is attempted.
+ * Get the data for the application returned by {@link #nextRestorePackage}.
+ * @param data An open, writable file into which the backup data should be stored.
+ * @return false if errors occurred (the restore should be aborted and rescheduled),
+ * true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
*/
- int endSession();
+ boolean getRestoreData(in ParcelFileDescriptor outFd);
+
+ /**
+ * End a restore session (aborting any in-process data transfer as necessary),
+ * freeing any resources and connections used during the restore process.
+ */
+ void finishRestore();
}
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 3dd71f3..0fbbb3f 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -33,11 +33,8 @@
private Context mContext;
private PackageManager mPackageManager;
private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
- private FileFilter mDirFileFilter = new FileFilter() {
- public boolean accept(File f) {
- return f.isDirectory();
- }
- };
+ private PackageInfo[] mRestorePackages = null;
+ private int mRestorePackage = -1; // Index into mRestorePackages
public LocalTransport(Context context) {
@@ -51,21 +48,9 @@
return 0;
}
- public int startSession() throws RemoteException {
- if (DEBUG) Log.v(TAG, "session started");
- mDataDir.mkdirs();
- return 0;
- }
-
- public int endSession() throws RemoteException {
- if (DEBUG) Log.v(TAG, "session ended");
- return 0;
- }
-
- public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
+ public boolean performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
throws RemoteException {
if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
- int err = 0;
File packageDir = new File(mDataDir, packageInfo.packageName);
packageDir.mkdirs();
@@ -101,9 +86,8 @@
try {
entity.write(buf, 0, dataSize);
} catch (IOException e) {
- Log.e(TAG, "Unable to update key file "
- + entityFile.getAbsolutePath());
- err = -1;
+ Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath());
+ return false;
} finally {
entity.close();
}
@@ -111,14 +95,17 @@
entityFile.delete();
}
}
+ return true;
} catch (IOException e) {
// oops, something went wrong. abort the operation and return error.
- Log.v(TAG, "Exception reading backup input:");
- e.printStackTrace();
- err = -1;
+ Log.v(TAG, "Exception reading backup input:", e);
+ return false;
}
+ }
- return err;
+ public boolean finishBackup() throws RemoteException {
+ if (DEBUG) Log.v(TAG, "finishBackup()");
+ return true;
}
// Restore handling
@@ -129,72 +116,66 @@
return array;
}
- public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
- if (DEBUG) Log.v(TAG, "getting app set " + token);
- // the available packages are the extant subdirs of mDatadir
- File[] packageDirs = mDataDir.listFiles(mDirFileFilter);
- ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>();
- for (File dir : packageDirs) {
- try {
- PackageInfo pkg = mPackageManager.getPackageInfo(dir.getName(),
- PackageManager.GET_SIGNATURES);
- if (pkg != null) {
- packages.add(pkg);
- }
- } catch (NameNotFoundException e) {
- // restore set contains data for a package not installed on the
- // phone -- just ignore it.
- }
- }
-
- if (DEBUG) {
- Log.v(TAG, "Built app set of " + packages.size() + " entries:");
- for (PackageInfo p : packages) {
- Log.v(TAG, " + " + p.packageName);
- }
- }
-
- PackageInfo[] result = new PackageInfo[packages.size()];
- return packages.toArray(result);
+ public boolean startRestore(long token, PackageInfo[] packages) {
+ if (DEBUG) Log.v(TAG, "start restore " + token);
+ mRestorePackages = packages;
+ mRestorePackage = -1;
+ return true;
}
- public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor outFd)
- throws android.os.RemoteException {
- if (DEBUG) Log.v(TAG, "getting restore data " + token + " : " + packageInfo.packageName);
- // we only support one hardcoded restore set
- if (token != 0) return -1;
+ public String nextRestorePackage() {
+ if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
+ while (++mRestorePackage < mRestorePackages.length) {
+ String name = mRestorePackages[mRestorePackage].packageName;
+ if (new File(mDataDir, name).isDirectory()) {
+ if (DEBUG) Log.v(TAG, " nextRestorePackage() = " + name);
+ return name;
+ }
+ }
- // the data for a given package is at a known location
- File packageDir = new File(mDataDir, packageInfo.packageName);
+ if (DEBUG) Log.v(TAG, " no more packages to restore");
+ return "";
+ }
+
+ public boolean getRestoreData(ParcelFileDescriptor outFd) {
+ if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
+ if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
+ File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName);
// The restore set is the concatenation of the individual record blobs,
// each of which is a file in the package's directory
File[] blobs = packageDir.listFiles();
- if (DEBUG) Log.v(TAG, " found " + blobs.length + " key files");
- int err = 0;
- if (blobs != null && blobs.length > 0) {
- BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
- try {
- for (File f : blobs) {
- copyToRestoreData(f, out);
- }
- } catch (Exception e) {
- Log.e(TAG, "Unable to read backup records");
- err = -1;
- }
+ if (blobs == null) {
+ Log.e(TAG, "Error listing directory: " + packageDir);
+ return false; // nextRestorePackage() ensures the dir exists, so this is an error
}
- return err;
+
+ // We expect at least some data if the directory exists in the first place
+ if (DEBUG) Log.v(TAG, " getRestoreData() found " + blobs.length + " key files");
+ BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
+ try {
+ for (File f : blobs) {
+ FileInputStream in = new FileInputStream(f);
+ try {
+ int size = (int) f.length();
+ byte[] buf = new byte[size];
+ in.read(buf);
+ String key = new String(Base64.decode(f.getName()));
+ if (DEBUG) Log.v(TAG, " ... key=" + key + " size=" + size);
+ out.writeEntityHeader(key, size);
+ out.writeEntityData(buf, size);
+ } finally {
+ in.close();
+ }
+ }
+ return true;
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to read backup records", e);
+ return false;
+ }
}
- private void copyToRestoreData(File f, BackupDataOutput out) throws IOException {
- FileInputStream in = new FileInputStream(f);
- int size = (int) f.length();
- byte[] buf = new byte[size];
- in.read(buf);
- String key = new String(Base64.decode(f.getName()));
- if (DEBUG) Log.v(TAG, " ... copy to stream: key=" + key
- + " size=" + size);
- out.writeEntityHeader(key, size);
- out.writeEntityData(buf, size);
+ public void finishRestore() {
+ if (DEBUG) Log.v(TAG, "finishRestore()");
}
}
diff --git a/core/java/com/android/internal/backup/SystemBackupAgent.java b/core/java/com/android/internal/backup/SystemBackupAgent.java
new file mode 100644
index 0000000..6b396d7
--- /dev/null
+++ b/core/java/com/android/internal/backup/SystemBackupAgent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 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.internal.backup;
+
+import android.backup.AbsoluteFileBackupHelper;
+import android.backup.BackupHelperAgent;
+
+/**
+ * Backup agent for various system-managed data
+ */
+public class SystemBackupAgent extends BackupHelperAgent {
+ // the set of files that we back up whole, as absolute paths
+ String[] mFiles = {
+ /* WallpaperService.WALLPAPER_FILE */
+ "/data/data/com.android.settings/files/wallpaper",
+ };
+
+ public void onCreate() {
+ addHelper("system_files", new AbsoluteFileBackupHelper(this, mFiles));
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 58a3a83..fc4a9c4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -191,6 +191,8 @@
private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
new HashMap<String, KernelWakelockStats>();
+ private HashMap<String, Integer> mUidCache = new HashMap<String, Integer>();
+
// For debugging
public BatteryStatsImpl() {
mFile = mBackupFile = null;
@@ -714,6 +716,10 @@
}
}
+ boolean isRunningLocked() {
+ return mNesting > 0;
+ }
+
void stopRunningLocked(BatteryStatsImpl stats) {
// Ignore attempt to stop a timer that isn't running
if (mNesting == 0) {
@@ -1048,7 +1054,24 @@
mPhoneOnTimer.stopRunningLocked(this);
}
}
-
+
+ public void noteAirplaneModeLocked(boolean isAirplaneMode) {
+ final int bin = mPhoneSignalStrengthBin;
+ if (bin >= 0) {
+ if (!isAirplaneMode) {
+ if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
+ mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
+ }
+ } else {
+ for (int i = 0; i < NUM_SIGNAL_STRENGTH_BINS; i++) {
+ while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
+ mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
+ }
+ }
+ }
+ }
+ }
+
public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
// Bin the strength.
int bin;
@@ -2797,7 +2820,7 @@
public void removeUidStatsLocked(int uid) {
mUidStats.remove(uid);
}
-
+
/**
* Retrieve the statistics object for a particular process, creating
* if needed.
@@ -2808,6 +2831,26 @@
}
/**
+ * Retrieve the statistics object for a particular process, given
+ * the name of the process.
+ * @param name process name
+ * @return the statistics object for the process
+ */
+ public Uid.Proc getProcessStatsLocked(String name) {
+ int uid;
+ if (mUidCache.containsKey(name)) {
+ uid = mUidCache.get(name);
+ } else {
+ // TODO: Find the actual uid from /proc/pid/status. For now use the hashcode of the
+ // process name
+ uid = name.hashCode();
+ mUidCache.put(name, uid);
+ }
+ Uid u = getUidStatsLocked(uid);
+ return u.getProcessStatsLocked(name);
+ }
+
+ /**
* Retrieve the statistics object for a particular process, creating
* if needed.
*/
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index a37bf6e..4a8d8b1 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -219,12 +219,12 @@
public double getAveragePower(String type, int level) {
if (sPowerMap.containsKey(type)) {
Object data = sPowerMap.get(type);
- if (data instanceof double[]) {
- final double[] values = (double[]) data;
- if (values.length > level) {
+ if (data instanceof Double[]) {
+ final Double[] values = (Double[]) data;
+ if (values.length > level && level >= 0) {
return values[level];
- } else if (values.length < 0) {
- return values[0];
+ } else if (level < 0) {
+ return 0;
} else {
return values[values.length - 1];
}
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 9b92bc5..b07ba7d 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -53,19 +53,33 @@
static fields_t fields;
static Mutex sLock;
-struct camera_context_t {
+// provides persistent context for calls from native code to Java
+class JNICameraContext: public CameraListener
+{
+public:
+ JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera);
+ ~JNICameraContext() { release(); }
+ virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
+ virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
+ sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
+ void release();
+
+private:
+ void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType);
+
jobject mCameraJObjectWeak; // weak reference to java object
jclass mCameraJClass; // strong reference to java class
sp<Camera> mCamera; // strong reference to native object
+ Mutex mLock;
};
-sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext)
+sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
{
sp<Camera> camera;
Mutex::Autolock _l(sLock);
- camera_context_t* context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
+ JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
if (context != NULL) {
- camera = context->mCamera;
+ camera = context->getCamera();
}
LOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
if (camera == 0) {
@@ -76,30 +90,140 @@
return camera;
}
-static void err_callback(status_t err, void *cookie)
+JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera)
{
- camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
- if ((context == NULL) || (context->mCamera == 0)) return;
+ mCameraJObjectWeak = env->NewGlobalRef(weak_this);
+ mCameraJClass = (jclass)env->NewGlobalRef(clazz);
+ mCamera = camera;
+}
- LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get());
-
- int error;
- switch (err) {
- case DEAD_OBJECT:
- error = kCameraErrorMediaServer;
- break;
- default:
- error = kCameraErrorUnknown;
- break;
- }
-
+void JNICameraContext::release()
+{
+ LOGV("release");
+ Mutex::Autolock _l(mLock);
JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- LOGE("err_callback on dead VM");
+
+ if (mCameraJObjectWeak != NULL) {
+ env->DeleteGlobalRef(mCameraJObjectWeak);
+ mCameraJObjectWeak = NULL;
+ }
+ if (mCameraJClass != NULL) {
+ env->DeleteGlobalRef(mCameraJClass);
+ mCameraJClass = NULL;
+ }
+ mCamera.clear();
+}
+
+void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2)
+{
+ LOGV("notify");
+
+ // VM pointer will be NULL if object is released
+ Mutex::Autolock _l(mLock);
+ if (mCameraJObjectWeak == NULL) {
+ LOGW("callback on dead camera object");
return;
}
- env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
- context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL);
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ // parse message
+ switch (msgType) {
+ case CAMERA_MSG_ERROR:
+ LOGV("errorCallback");
+ int error;
+ switch (ext1) {
+ case DEAD_OBJECT:
+ error = kCameraErrorMediaServer;
+ break;
+ default:
+ error = kCameraErrorUnknown;
+ break;
+ }
+ env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+ mCameraJObjectWeak, kErrorCallback, error, 0, NULL);
+ break;
+ case CAMERA_MSG_FOCUS:
+ LOGV("autoFocusCallback");
+ env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+ mCameraJObjectWeak, kAutoFocusCallback, ext1, 0, NULL);
+ break;
+ case CAMERA_MSG_SHUTTER:
+ LOGV("shutterCallback");
+ env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+ mCameraJObjectWeak, kShutterCallback, 0, 0, NULL);
+ break;
+ default:
+ LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2);
+ break;
+ }
+}
+
+void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
+{
+ jbyteArray obj = NULL;
+
+ // allocate Java byte array and copy data
+ if (dataPtr != NULL) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
+ LOGV("postData: off=%d, size=%d", offset, size);
+ uint8_t *heapBase = (uint8_t*)heap->base();
+
+ if (heapBase != NULL) {
+ uint8_t *data = heapBase + offset;
+ obj = env->NewByteArray(size);
+ if (obj == NULL) {
+ LOGE("Couldn't allocate byte array for JPEG data");
+ env->ExceptionClear();
+ } else {
+ jbyte *bytes = env->GetByteArrayElements(obj, NULL);
+ memcpy(bytes, data, size);
+ env->ReleaseByteArrayElements(obj, bytes, 0);
+
+ }
+ } else {
+ LOGE("image heap is NULL");
+ }
+ }
+
+ // post image data to Java
+ env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+ mCameraJObjectWeak, msgType, 0, 0, obj);
+ if (obj) {
+ env->DeleteLocalRef(obj);
+ }
+}
+
+void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
+{
+ // VM pointer will be NULL if object is released
+ Mutex::Autolock _l(mLock);
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ // return data based on callback type
+ switch(msgType) {
+ case CAMERA_MSG_PREVIEW_FRAME:
+ LOGV("previewCallback");
+ copyAndPost(env, dataPtr, kPreviewCallback);
+ break;
+ case CAMERA_MSG_VIDEO_FRAME:
+ LOGV("recordingCallback");
+ break;
+ case CAMERA_MSG_RAW_IMAGE:
+ LOGV("rawCallback");
+ env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
+ mCameraJObjectWeak, kRawCallback, 0, 0, NULL);
+ break;
+ case CAMERA_MSG_COMPRESSED_IMAGE:
+ LOGV("jpegCallback");
+ copyAndPost(env, dataPtr, kJpegCallback);
+ break;
+ default:
+ LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
+ break;
+ }
+
}
// connect to camera service
@@ -127,19 +251,12 @@
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
- camera_context_t* context = new camera_context_t;
- context->mCameraJObjectWeak = env->NewGlobalRef(weak_this);
- context->mCameraJClass = (jclass)env->NewGlobalRef(clazz);
- context->mCamera = camera;
+ sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
+ context->incStrong(thiz);
+ camera->setListener(context);
// save context in opaque field
- env->SetIntField(thiz, fields.context, (int)context);
-
- LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p",
- (int)context->mCameraJObjectWeak, (int)thiz, context);
-
- // set error callback
- camera->setErrorCallback(err_callback, context);
+ env->SetIntField(thiz, fields.context, (int)context.get());
}
// disconnect from camera service
@@ -148,11 +265,11 @@
// finalizer is invoked later.
static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
{
- camera_context_t* context = NULL;
+ JNICameraContext* context = NULL;
sp<Camera> camera;
{
Mutex::Autolock _l(sLock);
- context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
+ context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
// Make sure we do not attempt to callback on a deleted Java object.
env->SetIntField(thiz, fields.context, 0);
@@ -160,21 +277,18 @@
// clean up if release has not been called before
if (context != NULL) {
- camera = context->mCamera;
- context->mCamera.clear();
+ camera = context->getCamera();
+ context->release();
LOGV("native_release: context=%p camera=%p", context, camera.get());
// clear callbacks
if (camera != NULL) {
- camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP);
- camera->setErrorCallback(NULL, NULL);
+ camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
camera->disconnect();
- env->DeleteGlobalRef(context->mCameraJObjectWeak);
- env->DeleteGlobalRef(context->mCameraJClass);
}
// remove context to prevent further Java access
- delete context;
+ context->decStrong(thiz);
}
}
@@ -190,48 +304,6 @@
}
}
-static void preview_callback(const sp<IMemory>& mem, void *cookie)
-{
- LOGV("preview_callback");
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- LOGE("preview_callback on dead VM");
- return;
- }
- camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
- if ((context == NULL) || (context->mCamera == 0)) {
- LOGW("context or camera is NULL in preview_callback");
- return;
- }
- LOGV("native_release: context=%p camera=%p", context, context->mCamera.get());
-
- int arg1 = 0, arg2 = 0;
- jobject obj = NULL;
-
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
- uint8_t *data = ((uint8_t *)heap->base()) + offset;
-
- jbyteArray array = env->NewByteArray(size);
- if (array == NULL) {
- LOGE("Couldn't allocate byte array for YUV data");
- env->ExceptionClear();
- return;
- }
-
- jbyte *bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, data, size);
- env->ReleaseByteArrayElements(array, bytes, 0);
-
- obj = array;
-
- env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
- context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj);
- env->DeleteLocalRef(array);
-}
-
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
LOGV("startPreview");
@@ -267,7 +339,7 @@
// Important: Only install preview_callback if the Java code has called
// setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
// each preview frame for nothing.
- camera_context_t* context;
+ JNICameraContext* context;
sp<Camera> camera = get_native_camera(env, thiz, &context);
if (camera == 0) return;
@@ -277,130 +349,32 @@
} else {
callback_flag = FRAME_CALLBACK_FLAG_NOOP;
}
- camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag);
-}
-
-static void autofocus_callback_impl(bool success, void *cookie)
-{
- LOGV("autoFocusCallback");
- camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- LOGE("autofocus_callback on dead VM");
- return;
- }
- env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
- context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL);
+ camera->setPreviewCallbackFlags(callback_flag);
}
static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
{
LOGV("autoFocus");
- camera_context_t* context;
+ JNICameraContext* context;
sp<Camera> c = get_native_camera(env, thiz, &context);
if (c == 0) return;
- c->setAutoFocusCallback(autofocus_callback_impl, context);
if (c->autoFocus() != NO_ERROR) {
jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed");
}
}
-static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
-{
- LOGV("jpegCallback");
- camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- LOGE("jpeg`_callback on dead VM");
- return;
- }
- int arg1 = 0, arg2 = 0;
- jobject obj = NULL;
-
- if (mem == NULL) {
- env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
- context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL);
- return;
- }
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- LOGV("jpeg_callback: mem off=%d, size=%d", offset, size);
-
- uint8_t *heap_base = (uint8_t *)heap->base();
- if (heap_base == NULL) {
- LOGE("YUV heap is NULL");
- return;
- }
-
- uint8_t *data = heap_base + offset;
-
- jbyteArray array = env->NewByteArray(size);
- if (array == NULL) {
- LOGE("Couldn't allocate byte array for JPEG data");
- env->ExceptionClear();
- return;
- }
-
- jbyte *bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, data, size);
- env->ReleaseByteArrayElements(array, bytes, 0);
-
- obj = array;
-
- env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
- context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj);
- env->DeleteLocalRef(array);
-}
-
-static void shutter_callback_impl(void *cookie)
-{
- LOGV("shutterCallback");
- camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- LOGE("shutter_callback on dead VM");
- return;
- }
- env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
- context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL);
-}
-
-static void raw_callback(const sp<IMemory>& mem __attribute__((unused)),
- void *cookie)
-{
- LOGV("rawCallback");
- camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
-
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (env == NULL) {
- LOGE("raw_callback on dead VM");
- return;
- }
- env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
- context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL);
-}
-
static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
{
LOGV("takePicture");
- camera_context_t* context;
+ JNICameraContext* context;
sp<Camera> camera = get_native_camera(env, thiz, &context);
if (camera == 0) return;
- camera->setShutterCallback(shutter_callback_impl, context);
- camera->setRawCallback(raw_callback, context);
- camera->setJpegCallback(jpeg_callback, context);
if (camera->takePicture() != NO_ERROR) {
jniThrowException(env, "java/lang/RuntimeException", "takePicture failed");
return;
}
-
- return;
}
static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index df6151d..7f24dcc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1000,6 +1000,7 @@
android:hasCode="false"
android:label="@string/android_system_label"
android:allowClearUserData="false"
+ android:backupAgent="com.android.internal.backup.SystemBackupAgent"
android:icon="@drawable/ic_launcher_android">
<activity android:name="com.android.internal.app.ChooserActivity"
android:theme="@style/Theme.Dialog.Alert"
diff --git a/core/res/res/drawable/search_dropdown_background.9.png b/core/res/res/drawable/search_dropdown_background.9.png
old mode 100755
new mode 100644
index a6923b7..804260a
--- a/core/res/res/drawable/search_dropdown_background.9.png
+++ b/core/res/res/drawable/search_dropdown_background.9.png
Binary files differ
diff --git a/core/res/res/drawable/search_dropdown_background_apps.9.png b/core/res/res/drawable/search_dropdown_background_apps.9.png
deleted file mode 100644
index 804260a..0000000
--- a/core/res/res/drawable/search_dropdown_background_apps.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values-de-rAT/donottranslate-cldr.xml b/core/res/res/values-de-rAT/donottranslate-cldr.xml
index cd7cba8..27624a3 100644
--- a/core/res/res/values-de-rAT/donottranslate-cldr.xml
+++ b/core/res/res/values-de-rAT/donottranslate-cldr.xml
@@ -2,10 +2,43 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="month_long_standalone_january">Jänner</string>
+ <string name="month_long_standalone_february">Februar</string>
+ <string name="month_long_standalone_march">März</string>
+ <string name="month_long_standalone_april">April</string>
+ <string name="month_long_standalone_may">Mai</string>
+ <string name="month_long_standalone_june">Juni</string>
+ <string name="month_long_standalone_july">Juli</string>
+ <string name="month_long_standalone_august">August</string>
+ <string name="month_long_standalone_september">September</string>
+ <string name="month_long_standalone_october">Oktober</string>
+ <string name="month_long_standalone_november">November</string>
+ <string name="month_long_standalone_december">Dezember</string>
<string name="month_long_january">Jänner</string>
+ <string name="month_long_february">Februar</string>
+ <string name="month_long_march">März</string>
+ <string name="month_long_april">April</string>
+ <string name="month_long_may">Mai</string>
+ <string name="month_long_june">Juni</string>
+ <string name="month_long_july">Juli</string>
+ <string name="month_long_august">August</string>
+ <string name="month_long_september">September</string>
+ <string name="month_long_october">Oktober</string>
+ <string name="month_long_november">November</string>
+ <string name="month_long_december">Dezember</string>
<string name="month_medium_january">Jän</string>
+ <string name="month_medium_february">Feb</string>
+ <string name="month_medium_march">Mär</string>
+ <string name="month_medium_april">Apr</string>
+ <string name="month_medium_may">Mai</string>
+ <string name="month_medium_june">Jun</string>
+ <string name="month_medium_july">Jul</string>
+ <string name="month_medium_august">Aug</string>
+ <string name="month_medium_september">Sep</string>
+ <string name="month_medium_october">Okt</string>
+ <string name="month_medium_november">Nov</string>
+ <string name="month_medium_december">Dez</string>
<string name="month_shortest_january">J</string>
<string name="month_shortest_february">F</string>
diff --git a/docs/html/guide/topics/resources/res-selection-flowchart.png b/docs/html/guide/topics/resources/res-selection-flowchart.png
new file mode 100755
index 0000000..d738b3f
--- /dev/null
+++ b/docs/html/guide/topics/resources/res-selection-flowchart.png
Binary files differ
diff --git a/docs/html/guide/topics/resources/res-selection-flowchart.vsd b/docs/html/guide/topics/resources/res-selection-flowchart.vsd
new file mode 100755
index 0000000..65bfcdb
--- /dev/null
+++ b/docs/html/guide/topics/resources/res-selection-flowchart.vsd
Binary files differ
diff --git a/docs/html/guide/topics/resources/resources-i18n.jd b/docs/html/guide/topics/resources/resources-i18n.jd
old mode 100644
new mode 100755
index 4bbb44a..6900704
--- a/docs/html/guide/topics/resources/resources-i18n.jd
+++ b/docs/html/guide/topics/resources/resources-i18n.jd
@@ -1,713 +1,716 @@
-page.title=Resources and Internationalization
-parent.title=Resources and Assets
-parent.link=index.html
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
- <h2>Key classes</h2>
- <ol>
- <li>{@link android.content.res.Resources}</li>
- </ol>
-
- <h2>In this document</h2>
- <ol>
- <li><a href="#intro">Introduction</a></li>
- <li><a href="#CreatingResources">Creating Resources</a></li>
- <li><a href="#UsingResources">Using Resources</a>
- <ol>
- <li><a href="#ResourcesInCode">Using Resources in Code</a></li>
- <li><a href="#ReferencesToResources">References to Resources</a></li>
- <li><a href="#ReferencesToThemeAttributes">References to Theme Attributes</a></li>
- <li><a href="#UsingSystemResources">Using System Resources</a></li>
- </ol>
- </li>
- <li><a href="#AlternateResources">Alternate Resources</a></li>
- <li><a href="#ResourcesTerminology">Terminology</a></li>
- <li><a href="#i18n">Internationalization (I18N)</a></li>
- </ol>
-</div>
-</div>
-
-<p>Resources are external files (that is, non-code files) that are used by
-your code and compiled into your application at build time. Android
-supports a number of different kinds of resource files, including XML,
-PNG, and JPEG files. The XML files have very different formats depending
-on what they describe. This document describes what kinds of files are
-supported, and the syntax or format of each.</p>
-<p>Resources are externalized from source code, and XML files are compiled into
-a binary, fast loading format for efficiency reasons. Strings, likewise are compressed
-into a more efficient storage form. It is for these reasons that we have these
-different resource types in the Android platform.</p>
-
-<p>This is a fairly technically dense document, and together with the
-<a href="available-resources.html">Available Resources</a>
-document, they cover a lot of information about resources. It is not necessary
-to know this document by heart to use Android, but rather to know that the
-information is here when you need it.</p>
-
-<a name="intro"></a>
-<h2>Introduction</h2>
-
-<p>This topic includes a terminology list associated with resources, and a series
- of examples of using resources in code. For a complete guide to the supported
- Android resource types, see
- <a href="available-resources.html">Available Resources</a>.
- </p>
-<p>The Android resource system keeps track of all non-code
- assets associated with an application. You use the
- {@link android.content.res.Resources Resources} class to access your
- application's resources; the Resources instance associated with your
- application can generally be found through
- {@link android.content.Context#getResources Context.getResources()}.</p>
-<p>An application's resources are compiled into the application
-binary at build time for you by the build system. To use a resource,
-you must install it correctly in the source tree and build your
-application. As part of the build process, symbols for each
-of the resources are generated that you can use in your source
-code -- this allows the compiler to verify that your application code matches
-up with the resources you defined.</p>
-
-<p>The rest of this section is organized as a tutorial on how to
-use resources in an application.</p>
-
-<a name="CreatingResources" id="CreatingResources"></a>
-<h2>Creating Resources</h2>
-
-<p>Android supports string, bitmap, and many other types of resource. The syntax and format
-of each, and where they're stored, depends upon the type of object. In
-general, though, you create resources from three types of files: XML files
-(everything but bitmaps and raw), bitmap files(for images) and Raw files (anything
-else, for example sound files, etc.). In fact, there are two different types of
-XML file as well, those that get compiled as-is into the package, and those that
-are used to generate resources by aapt. Here is a list of each
-resource type, the format of the file, a description of the file, and details
-of any XML files. </p>
-
-<p>You will create and store your resource files under the appropriate
-subdirectory under the <code>res/</code> directory in your project. Android
-has a resource compiler (aapt) that compiles resources according to which
-subfolder they are in, and the format of the file. Here is a list of the file
-types for each resource. See the
-<a href="available-resources.html">Available Resources</a> for
-descriptions of each type of object, the syntax, and the format or syntax of
-the containing file.</p>
-
-<table width="100%" border="1">
- <tr>
- <th scope="col">Directory</th>
- <th scope="col">Resource Types </th>
- </tr>
- <tr>
- <td><code>res/anim/</code></td>
- <td>XML files that are compiled into
- <a href="available-resources.html#animationdrawable">frame by
- frame animation</a> or
- <a href="available-resources.html#tweenedanimation">tweened
- animation</a> objects </td>
- </tr>
- <tr>
- <td><code>res/drawable/</code></td>
- <td><p>.png, .9.png, .jpg files that are compiled into the following
- Drawable resource subtypes:</p>
- <ul class="nolist">
- <li><a href="available-resources.html#imagefileresources">bitmap files</a></li>
- <li><a href="available-resources.html#ninepatch">9-patches (resizable bitmaps)</a></li>
- </ul>
- <p>To get a resource of this type, use <code>mContext.getResources().getDrawable(R.drawable.<em>imageId</em>)</code></p>
- <p class="note"><strong>Note:</strong> Image resources placed in here may
- be automatically optimized with lossless image compression by the
- <a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For example, a true-color PNG
- that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette.
- This will result in an image of equal quality but which requires less memory. So be aware that the
- image binaries placed in this directory can change during the build. If you plan on reading
- an image as a bit stream in order to convert it to a bitmap, put your images in the
- <code>res/raw/</code> folder instead, where they will not be optimized.</p>
- </td>
- </tr>
- <tr>
- <td><code>res/layout/</code></td>
- <td>XML files that are compiled into screen layouts (or part of a screen).
- See <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a>.</td>
- </tr>
- <tr>
- <td><code>res/values/</code></td>
- <td><p>XML files that can be compiled into many kinds of resource.</p>
- <p class="note"><strong>Note:</strong> Unlike the other res/ folders, this one
- can hold any number of files that hold descriptions of resources to create
- rather than the resources themselves. The XML element types control
- where these resources are placed under the R class.</p>
- <p>While the files can be named anything, these are
- the typical files in this folder (the convention is to name
- the file after the type of elements defined within):</p>
- <ul>
- <li><strong>arrays.xml</strong> to define arrays </li>
- <!-- TODO: add section on arrays -->
- <li><strong>colors.xml</strong> to define <a href="available-resources.html#colordrawableresources">color
- drawables</a> and <a href="#colorvals">color string values</a>.
- Use <code>Resources.getDrawable()</code> and
- <code>Resources.getColor(), respectively,</code>
- to get these resources.</li>
- <li><strong>dimens.xml</strong> to define <a href="available-resources.html#dimension">dimension value</a>. Use <code>Resources.getDimension()</code> to get
- these resources.</li>
- <li><strong>strings.xml</strong> to define <a href="available-resources.html#stringresources">string</a> values (use either
- <code>Resources.getString</code> or preferably <code>Resources.getText()</code>
- to get
- these resources. <code>getText()</code> will retain any rich text styling
- which is usually desirable for UI strings.</li>
- <li><strong>styles.xml</strong> to define <a href="available-resources.html#stylesandthemes">style</a> objects.</li>
- </ul></td>
- </tr>
- <tr>
- <td><code>res/xml/</code></td>
- <td>Arbitrary XML files that are compiled and can be read at run time by
- calling {@link android.content.res.Resources#getXml(int) Resources.getXML()}.</td>
- </tr>
- <tr>
- <td><code>res/raw/</code></td>
- <td>Arbitrary files to copy directly to the device. They are added uncompiled
- to the compressed file that your application build produces. To use these
- resources in your application, call {@link android.content.res.Resources#openRawResource(int)
- Resources.openRawResource()} with the resource ID, which is R.raw.<em>somefilename</em>.</td>
- </tr>
-</table>
-<p>Resources are compiled into the final APK file. Android creates a wrapper class,
- called R, that you can use to refer to these resources in your code. R contains subclasses
- named according to the path and file name of the source file</p>
-<a name="colorvals" id="colorvals"></a>
-<h3>Global Resource Notes</h3>
-<ul>
- <li>Several resources allow you to define colors. Android accepts color values
- written in various web-style formats -- a hexadecimal constant in any of the
- following forms: #RGB, #ARGB, #RRGGBB, #AARRGGBB. </li>
- <li>All color values support setting an alpha channel value, where the first
- two hexadecimal numbers specify the transparency. Zero in the alpha channel
- means transparent. The default value is opaque. </li>
-</ul>
-<a name="UsingResources" id="UsingResources"></a>
-<h2>Using Resources </h2>
-<p>This section describes how to use the resources you've created. It includes the
- following topics:</p>
-<ul>
- <li><a href="#ResourcesInCode">Using resources in code</a> - How to call
- resources in your code to instantiate them. </li>
- <li><a href="#ReferencesToResources">Referring to resources from other resources</a> -
- You can reference resources from other resources. This lets you reuse common
- resource values inside resources. </li>
- <li><a href="#AlternateResources">Supporting Alternate Resources for Alternate
- Configurations</a> - You can specify different resources
- to load, depending on the language or display configuration of the host
- hardware. </li>
-</ul>
-<p>At compile time, Android generates a class named R that contains resource identifiers
- to all the resources in your program. This class contains several subclasses,
- one for each type of resource supported by Android, and for which you provided
- a resource file. Each class contains one or more identifiers for the compiled resources,
- that you use in your code to load the resource. Here is a small resource file
- that contains string, layout (screens or parts of screens), and image resources.</p>
-<p class="note"><strong>Note:</strong> the R class is an auto-generated file and is not
-designed to be edited by hand. It will be automatically re-created as needed when
-the resources are updated.</p>
-<pre class="prettyprint">package com.android.samples;
-public final class R {
- public static final class string {
- public static final int greeting=0x0204000e;
- public static final int start_button_text=0x02040001;
- public static final int submit_button_text=0x02040008;
- public static final int main_screen_title=0x0204000a;
- };
- public static final class layout {
- public static final int start_screen=0x02070000;
- public static final int new_user_pane=0x02070001;
- public static final int select_user_list=0x02070002;
-
- };
- public static final class drawable {
- public static final int company_logo=0x02020005;
- public static final int smiling_cat=0x02020006;
- public static final int yellow_fade_background=0x02020007;
- public static final int stretch_button_1=0x02020008;
-
- };
-};
-</pre>
-<a name="ResourcesInCode" id="ResourcesInCode"></a>
-<h3>Using Resources in Code </h3>
-
-<p>Using resources in code is just a matter of knowing the full resource ID
-and what type of object your resource has been compiled into. Here is the
-syntax for referring to a resource:</p>
-<p><code>R.<em>resource_type</em>.<em>resource_name</em></code></p>
-<p>or</p>
-<p><code>android.R.<em>resource_type</em>.<em>resource_name</em></code></p>
-
-<p>Where <code>resource_type</code> is the R subclass that holds a specific type
-of resource. <code>resource_name</code> is the <em>name</em> attribute for resources
-defined in XML files, or the file name (without the extension) for resources
-defined by other file types. Each type of resource will be added to a specific
-R subclass, depending on the type of resource it is; to learn which R subclass
-hosts your compiled resource type, consult the
-<a href="available-resources.html">Available Resources</a> document. Resources compiled by your own application can
-be referred to without a package name (simply as
-<code>R.<em>resource_type</em>.<em>resource_name</em></code>). Android contains
-a number of standard resources, such as screen styles and button backgrounds. To
-refer to these in code, you must qualify them with <code>android</code>, as in
-<code>android.R.drawable.button_background</code>.</p>
-
-<p>Here are some good and bad examples of using compiled resources in code:</p>
-
-<pre class="prettyprint">// Load a background for the current screen from a drawable resource.
-this.getWindow().setBackgroundDrawableResource(R.drawable.my_background_image);
-
-// WRONG Sending a string resource reference into a
-// method that expects a string.
-this.getWindow().setTitle(R.string.main_title);
-
-// RIGHT Need to get the title from the Resources wrapper.
-this.getWindow().setTitle(Resources.getText(R.string.main_title));
-
-// Load a custom layout for the current screen.
-setContentView(R.layout.main_screen);
-
-// Set a slide in animation for a ViewFlipper object.
-mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
- R.anim.hyperspace_in));
-
-// Set the text on a TextView object.
-TextView msgTextView = (TextView)findViewByID(R.id.msg);
-msgTextView.setText(R.string.hello_message); </pre>
-
-<a name="ReferencesToResources" id="ReferencesToResources"></a>
-<h3>References to Resources</h3>
-
-<p>A value supplied in an attribute (or resource) can also be a reference to
-a resource. This is often used in layout files to supply strings (so they
-can be localized) and images (which exist in another file), though a reference
-can be any resource type including colors and integers.</p>
-
-<p>For example, if we have
-<a href="available-resources.html#colordrawableresources">color
-resources</a>, we can write a layout file that sets the text color size to be
-the value contained in one of those resources:</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<EditText id="text"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- <strong>android:textColor="@color/opaque_red"</strong>
- android:text="Hello, World!" />
-</pre>
-
-<p>Note here the use of the '@' prefix to introduce a resource reference -- the
-text following that is the name of a resource in the form
-of <code>@[package:]type/name</code>. In this case we didn't need to specify
-the package because we are referencing a resource in our own package. To
-reference a system resource, you would need to write:</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<EditText id="text"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:textColor="@<strong>android:</strong>color/opaque_red"
- android:text="Hello, World!" />
-</pre>
-
-<p>As another example, you should always use resource references when supplying
-strings in a layout file so that they can be localized:</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<EditText id="text"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- android:textColor="@android:color/opaque_red"
- android:text="@string/hello_world" />
-</pre>
-
-<p>This facility can also be used to create references between resources.
-For example, we can create new drawable resources that are aliases for
-existing images:</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <drawable id="my_background">@android:drawable/theme2_background</drawable>
-</resources>
-</pre>
-
-<a name="ReferencesToThemeAttributes"></a>
-<h3>References to Theme Attributes</h3>
-
-<p>Another kind of resource value allows you to reference the value of an
-attribute in the current theme. This attribute reference can <em>only</em>
-be used in style resources and XML attributes; it allows you to customize the
-look of UI elements by changing them to standard variations supplied by the
-current theme, instead of supplying more concrete values.</p>
-
-<p>As an example, we can use this in our layout to set the text color to
-one of the standard colors defined in the base system theme:</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<EditText id="text"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent" android:layout_height="fill_parent"
- <strong>android:textColor="?android:textDisabledColor"</strong>
- android:text="@string/hello_world" />
-</pre>
-
-<p>Note that this is very similar to a resource reference, except we are using
-an '?' prefix instead of '@'. When you use this markup, you are supplying
-the name of an attribute resource that will be looked up in the theme --
-because the resource tool knows that an attribute resource is expected,
-you do not need to explicitly state the type (which would be
-<code>?android:attr/android:textDisabledColor</code>).</p>
-
-<p>Other than using this resource identifier to find the value in the
-theme instead of raw resources, the name syntax is identical to the '@' format:
-<code>?[namespace:]type/name</code> with the type here being optional.</p>
-
-<a name="UsingSystemResources"></a>
-<h3>Using System Resources</h3>
-
-<p>Many resources included with the system are available to applications.
-All such resources are defined under the class "android.R". For example,
-you can display the standard application icon in a screen with the following
-code:</p>
-
-<pre class="prettyprint">
-public class MyActivity extends Activity
-{
- public void onStart()
- {
- requestScreenFeatures(FEATURE_BADGE_IMAGE);
-
- super.onStart();
-
- setBadgeResource(android.R.drawable.sym_def_app_icon);
- }
-}
-</pre>
-
-<p>In a similar way, this code will apply to your screen the standard
-"green background" visual treatment defined by the system:</p>
-
-<pre class="prettyprint">
-public class MyActivity extends Activity
-{
- public void onStart()
- {
- super.onStart();
-
- setTheme(android.R.style.Theme_Black);
- }
-}
-</pre>
-
-<a name="AlternateResources" id="AlternateResources"></a>
-<h2>Alternate Resources (for alternate languages and configurations)</h2>
-
-<p>You can supply different resources for your product according to the UI
-language or hardware configuration on the device. Note that although you can
-include different string, layout, and other resources, the SDK does not expose
-methods to let you specify which alternate resource set to load. Android
-detects the proper set for the hardware and location, and loads them as
-appropriate. Users can select alternate language settings using the settings
-panel on the device. </p>
-<p>To include alternate resources, create parallel resource folders with
-qualifiers appended to the folder names, indicating the configuration it
-applies to (language, screen orientation, and so on). For example, here is a
-project that holds one string resource file for English, and another for
-French:</p>
-
-<pre>
-MyApp/
- res/
- values-en/
- strings.xml
- values-fr/
- strings.xml
-</pre>
-
-<p>Android supports several types of qualifiers, with various values for each.
-Append these to the end of the resource folder name, separated by dashes. You
-can add multiple qualifiers to each folder name, but they must appear in the
-order they are listed here. For example, a folder containing drawable
-resources for a fully specified configuration would look like:</p>
-
-<pre>
-MyApp/
- res/
- drawable-en-rUS-port-160dpi-finger-keysexposed-qwerty-dpad-480x320/
-</pre>
-
-<p>More typically, you will only specify a few specific configuration options
-that a resource is defined for. You may drop any of the values from the
-complete list, as long as the remaining values are still in the same
-order:</p>
-
-<pre>
-MyApp/
- res/
- drawable-en-rUS-finger/
- drawable-port/
- drawable-port-160dpi/
- drawable-qwerty/
-</pre>
-
-<table border="1">
- <tr>
- <th> Qualifier </th>
- <th> Values </th>
- </tr>
- <tr>
- <td>Language</td>
- <td>The two letter <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO
- 639-1</a> language code in lowercase. For example:
- <code>en</code>, <code>fr</code>, <code>es</code> </td>
- </tr>
- <tr>
- <td>Region</td>
- <td>The two letter
- <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO
- 3166-1-alpha-2</a> language code in uppercase preceded by a lowercase
- "r". For example: <code>rUS</code>, <code>rFR</code>, <code>rES</code></td>
- </tr>
- <tr>
- <td>Screen orientation</td>
- <td><code>port</code>, <code>land</code>, <code>square</code> </td>
- </tr>
- <tr>
- <td>Screen pixel density</td>
- <td><code>92dpi</code>, <code>108dpi</code>, etc. </td>
- </tr>
- <tr>
- <td>Touchscreen type</td>
- <td><code>notouch</code>, <code>stylus</code>, <code>finger</code></td>
- </tr>
- <tr>
- <td>Whether the keyboard is available to the user</td>
- <td><code>keysexposed</code>, <code>keyshidden</code> </td>
- </tr>
- <tr>
- <td>Primary text input method</td>
- <td><code>nokeys</code>, <code>qwerty</code>, <code>12key</code> </td>
- </tr>
- <tr>
- <td>Primary non-touchscreen<br />
- navigation method</td>
- <td><code>nonav</code>, <code>dpad</code>, <code>trackball</code>, <code>wheel</code> </td>
- </tr>
- <tr>
- <td>Screen dimensions</td>
- <td><code>320x240</code>, <code>640x480</code>, etc. The larger dimension
- must be specified first. </td>
- </tr>
-</table>
-
-<p>This list does not include device-specific parameters such as carrier,
-branding, device/hardware, or manufacturer. Everything that an application
-needs to know about the device that it is running on is encoded via the
-resource qualifiers in the table above.</p>
-
-<p>Here are some general guidelines on qualified resource directory names:</p>
-
-<ul>
- <li>Values are separated by a dash (as well as a dash after the base directory
- name) </li>
- <li>Values are case-sensitive (even though they must be unique across all folder
- names in a case-insensitive way)<br />For example,</li>
- <ul>
- <li>A portrait-specific <code>drawable</code> directory must be named
- <code>drawable-port</code>, not <code>drawable-PORT</code>.</li>
- <li>You may not have two directories named <code>drawable-port</code>
- and <code>drawable-PORT</code>, even if you had intended "port" and
- "PORT" to refer to different parameter values.</li>
- </ul>
- <li>Only one value for each qualifier type is supported (that is, you cannot
- specify <code>drawable-rEN-rFR/</code>)</li>
- <li>You can specify multiple parameters to define specific configurations,
- but they must always be in the order listed above.
- For example, <code>drawable-en-rUS-land</code> will apply to landscape view,
- US-English devices. </li>
- <li>Android will try to find the most specific matching directory for the current
- configuration, as described below</li>
- <li>The order of parameters listed in this table is used to break a tie in case
- of multiple qualified directories (see the example given below) </li>
- <li>All directories, both qualified and unqualified, live under the <code>res/</code> folder.
- Qualified directories cannot be nested (you cannot have <code>res/drawable/drawable-en</code>) </li>
- <li>All resources will be referenced in code or resource reference syntax by
- their simple, undecorated name. So if a resource is named this:<br />
- <code>MyApp/res/drawable-port-92dp/myimage.png</code><br />
- It would be referenced as this:<br />
- <code>R.drawable.myimage</code> (code)<br />
- <code>@drawable/myimage</code> (XML)</li>
-</ul>
-
-<h3>How Android finds the best matching directory </h3>
-
-<p>Android will pick which of the various underlying resource files should be
-used at runtime, depending on the current configuration. The selection process
-is as follows:</p>
-
-<ol>
- <li>
- Eliminate any resources whose configuration does not match the current
- device configuration. For example, if the screen pixel density is 108dpi,
- this would eliminate only <code>MyApp/res/drawable-port-92dpi/</code>.
- <blockquote>
- <pre>
-MyApp/res/drawable/myimage.png
-MyApp/res/drawable-en/myimage.png
-MyApp/res/drawable-port/myimage.png
-<strike>MyApp/res/drawable-port-92dpi/myimage.png</strike>
-</pre>
- </blockquote>
- </li>
- <li>
- Pick the resources with the highest number of matching configurations.
- For example, if our locale is en-GB and orientation is port, then we
- have two candidates with one matching configuration each:
- <code>MyApp/res/drawable-en/</code> and <code>MyApp/res/drawable-port/</code>.
- The directory <code>MyApp/res/drawable/</code> is eliminated because
- it has zero matching configurations, while the others have one matching
- configuration.
- <blockquote>
- <pre>
-<strike>MyApp/res/drawable/myimage.png</strike>
-MyApp/res/drawable-en/myimage.png
-MyApp/res/drawable-port/myimage.png
-</pre>
- </blockquote>
- </li>
- <li>
- Pick the final matching file based on configuration precedence, which
- is the order of parameters listed in the table above. That is, it is
- more important to match the language than the orientation, so we break
- the tie by picking the language-specific file, <code>MyApp/res/drawable-en/</code>.
- <blockquote>
- <pre>MyApp/res/drawable-en/myimage.png
-<strike>MyApp/res/drawable-port/myimage.png</strike>
-</pre>
- </blockquote>
- </li>
-</ol>
-
-<a name="ResourcesTerminology"></a>
-<h2>Terminology</h2>
-
-<p>The resource system brings a number of different pieces together to
-form the final complete resource functionality. To help understand the
-overall system, here are some brief definitions of the core concepts and
-components you will encounter in using it:</p>
-
-<p><strong>Asset</strong>: A single blob of data associated with an application. This
-includes object files compiled from the Java source code, graphics (such as PNG
-images), XML files, etc. These files are organized in a directory hierarchy
-that, during final packaging of the application, is bundled together into a
-single ZIP file.</p>
-
-<p><strong>aapt</strong>: Android Asset Packaging Tool. The tool that generates the
-final ZIP file of application assets. In addition to collecting raw assets
-together, it also parses resource definitions into binary asset data.</p>
-
-<p><strong>Resource Table</strong>: A special asset that aapt generates for you,
-describing all of the resources contained in an application/package.
-This file is accessed for you by the Resources class; it is not touched
-directly by applications.</p>
-
-<p><strong>Resource</strong>: An entry in the Resource Table describing a single
-named value. Broadly, there are two types of resources: primitives and
-bags.</p>
-
-<p><strong>Resource Identifier</strong>: In the Resource Table all resources are
-identified by a unique integer number. In source code (resource descriptions,
-XML files, Java source code) you can use symbolic names that stand as constants for
-the actual resource identifier integer.</p>
-
-<p><strong>Primitive Resource</strong>: All primitive resources can be written as a
-simple string, using formatting to describe a variety of primitive types
-included in the resource system: integers, colors, strings, references to
-other resources, etc. Complex resources, such as bitmaps and XML
-describes, are stored as a primitive string resource whose value is the path
-of the underlying Asset holding its actual data.</p>
-
-<p><strong>Bag Resource</strong>: A special kind of resource entry that, instead of a
-simple string, holds an arbitrary list of name/value pairs. Each name is
-itself a resource identifier, and each value can hold
-the same kinds of string formatted data as a normal resource. Bags also
-support inheritance: a bag can inherit the values from another bag, selectively
-replacing or extending them to generate its own contents.</p>
-
-<p><strong>Kind</strong>: The resource kind is a way to organize resource identifiers
-for various purposes. For example, drawable resources are used to
-instantiate Drawable objects, so their data is a primitive resource containing
-either a color constant or string path to a bitmap or XML asset. Other
-common resource kinds are string (localized string primitives), color
-(color primitives), layout (a string path to an XML asset describing a view
-layout), and style (a bag resource describing user interface attributes).
-There is also a standard "attr" resource kind, which defines the resource
-identifiers to be used for naming bag items and XML attributes</p>
-
-<p><strong>Style</strong>: The name of the resource kind containing bags that are used
-to supply a set of user interface attributes. For example, a TextView class may
-be given a style resource that defines its text size, color, and alignment.
-In a layout XML file, you associate a style with a bag using the "style"
-attribute, whose value is the name of the style resource.</p>
-
-<p><strong>Style Class</strong>: Specifies a related set of attribute resources.
-This data is not placed in the resource table itself, but used to generate
-constants in the source code that make it easier for you to retrieve values out of
-a style resource and/or XML tag's attributes. For example, the
-Android platform defines a "View" style class that
-contains all of the standard view attributes: padding, visibility,
-background, etc.; when View is inflated it uses this style class to
-retrieve those values from the XML file (at which point style and theme
-information is applied as approriate) and load them into its instance.</p>
-
-<p><strong>Configuration</strong>: For any particular resource identifier, there may be
-multiple different available values depending on the current configuration.
-The configuration includes the locale (language and country), screen
-orientation, screen density, etc. The current configuration is used to
-select which resource values are in effect when the resource table is
-loaded.</p>
-
-<p><strong>Theme</strong>: A standard style resource that supplies global
-attribute values for a particular context. For example, when writing an
-Activity the application developer can select a standard theme to use, such
-as the Theme.White or Theme.Black styles; this style supplies information
-such as the screen background image/color, default text color, button style,
-text editor style, text size, etc. When inflating a layout resource, most
-values for widgets (the text color, selector, background) if not explicitly
-set will come from the current theme; style and attribute
-values supplied in the layout can also assign their value from explicitly
-named values in the theme attributes if desired.</p>
-
-<p><strong>Overlay</strong>: A resource table that does not define a new set of resources,
-but instead replaces the values of resources that are in another resource table.
-Like a configuration, this is applied at load time
-to the resource data; it can add new configuration values (for example
-strings in a new locale), replace existing values (for example change
-the standard white background image to a "Hello Kitty" background image),
-and modify resource bags (for example change the font size of the Theme.White
-style to have an 18 pt font size). This is the facility that allows the
-user to select between different global appearances of their device, or
-download files with new appearances.</p>
-
-<h2>Resource Reference</h2>
-<p>The <a href="available-resources.html">Available Resources</a>
-document provides a detailed list of the various types of resource and how to use them
-from within the Java source code, or from other references.</p>
-
-<a name="i18n" id="i18n"></a>
-<h2>Internationalization and Localization</h2>
-<p class="note"><strong>Coming Soon:</strong> Internationalization and Localization are
-critical, but are also not quite ready yet in the current SDK. As the
-SDK matures, this section will contain information on the Internationalization
-and Localization features of the Android platform. In the meantime, it is a good
-idea to start by externalizing all strings, and practicing good structure in
-creating and using resources.</p>
-
+page.title=Resources and Internationalization
+parent.title=Resources and Assets
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.content.res.Resources}</li>
+ </ol>
+
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#intro">Introduction</a></li>
+ <li><a href="#CreatingResources">Creating Resources</a></li>
+ <li><a href="#UsingResources">Using Resources</a>
+ <ol>
+ <li><a href="#ResourcesInCode">Using Resources in Code</a></li>
+ <li><a href="#ReferencesToResources">References to Resources</a></li>
+ <li><a href="#ReferencesToThemeAttributes">References to Theme Attributes</a></li>
+ <li><a href="#UsingSystemResources">Using System Resources</a></li>
+ </ol>
+ </li>
+ <li><a href="#AlternateResources">Alternate Resources</a></li>
+ <li><a href="#ResourcesTerminology">Terminology</a></li>
+ <li><a href="#i18n">Internationalization (I18N)</a></li>
+ </ol>
+</div>
+</div>
+
+<p>Resources are external files (that is, non-code files) that are used by
+your code and compiled into your application at build time. Android
+supports a number of different kinds of resource files, including XML,
+PNG, and JPEG files. The XML files have very different formats depending
+on what they describe. This document describes what kinds of files are
+supported, and the syntax or format of each.</p>
+<p>Resources are externalized from source code, and XML files are compiled into
+a binary, fast loading format for efficiency reasons. Strings, likewise, are compressed
+into a more efficient storage form. It is for these reasons that we have these
+different resource types in the Android platform.</p>
+
+<p>This is a fairly technically dense document, and together with the
+<a href="available-resources.html">Available Resources</a>
+document, they cover a lot of information about resources. It is not necessary
+to know this document by heart to use Android, but rather to know that the
+information is here when you need it.</p>
+
+<a name="intro"></a>
+<h2>Introduction</h2>
+
+<p>This topic includes a terminology list associated with resources, and a series
+ of examples of using resources in code. For a complete guide to the supported
+ Android resource types, see
+ <a href="available-resources.html">Available Resources</a>.
+ </p>
+<p>The Android resource system keeps track of all non-code
+ assets associated with an application. You use the
+ {@link android.content.res.Resources Resources} class to access your
+ application's resources; the Resources instance associated with your
+ application can generally be found through
+ {@link android.content.Context#getResources Context.getResources()}.</p>
+<p>An application's resources are compiled into the application
+binary at build time for you by the build system. To use a resource,
+you must install it correctly in the source tree and build your
+application. As part of the build process, symbols for each
+of the resources are generated that you can use in your source
+code -- this allows the compiler to verify that your application code matches
+up with the resources you defined.</p>
+
+<p>The rest of this section is organized as a tutorial on how to
+use resources in an application.</p>
+
+<a name="CreatingResources" id="CreatingResources"></a>
+<h2>Creating Resources</h2>
+
+<p>Android supports string, bitmap, and many other types of resource. The syntax and format
+of each, and where they're stored, depends upon the type of object. In
+general, though, you create resources from three types of files: XML files
+(everything but bitmaps and raw), bitmap files(for images) and Raw files (anything
+else, for example sound files, etc.). In fact, there are two different types of
+XML file as well, those that get compiled as-is into the package, and those that
+are used to generate resources by aapt. Here is a list of each
+resource type, the format of the file, a description of the file, and details
+of any XML files. </p>
+
+<p>You will create and store your resource files under the appropriate
+subdirectory under the <code>res/</code> directory in your project. Android
+has a resource compiler (aapt) that compiles resources according to which
+subfolder they are in, and the format of the file. Table 1 shows a llist of the file
+types for each resource. See the
+<a href="available-resources.html">Available Resources</a> for
+descriptions of each type of object, the syntax, and the format or syntax of
+the containing file.</p>
+<p class="caption">Table 1</p>
+<table width="100%" border="1">
+ <tr>
+ <th scope="col">Directory</th>
+ <th scope="col">Resource Types </th>
+ </tr>
+ <tr>
+ <td><code>res/anim/</code></td>
+ <td>XML files that are compiled into
+ <a href="available-resources.html#animationdrawable">frame by
+ frame animation</a> or
+ <a href="available-resources.html#tweenedanimation">tweened
+ animation</a> objects </td>
+ </tr>
+ <tr>
+ <td><code>res/drawable/</code></td>
+ <td><p>.png, .9.png, .jpg files that are compiled into the following
+ Drawable resource subtypes:</p>
+ <ul class="nolist">
+ <li><a href="available-resources.html#imagefileresources">bitmap files</a></li>
+ <li><a href="available-resources.html#ninepatch">9-patches (resizable bitmaps)</a></li>
+ </ul>
+ <p>To get a resource of this type, use <code>mContext.getResources().getDrawable(R.drawable.<em>imageId</em>)</code></p>
+ <p class="note"><strong>Note:</strong> Image resources placed in here may
+ be automatically optimized with lossless image compression by the
+ <a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For example, a true-color PNG
+ that does not require more than 256 colors may be converted to an 8-bit PNG with a color palette.
+ This will result in an image of equal quality but which requires less memory. So be aware that the
+ image binaries placed in this directory can change during the build. If you plan on reading
+ an image as a bit stream in order to convert it to a bitmap, put your images in the
+ <code>res/raw/</code> folder instead, where they will not be optimized.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>res/layout/</code></td>
+ <td>XML files that are compiled into screen layouts (or part of a screen).
+ See <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout</a>.</td>
+ </tr>
+ <tr>
+ <td><code>res/values/</code></td>
+ <td><p>XML files that can be compiled into many kinds of resource.</p>
+ <p class="note"><strong>Note:</strong> Unlike the other res/ folders, this one
+ can hold any number of files that hold descriptions of resources to create
+ rather than the resources themselves. The XML element types control
+ where these resources are placed under the R class.</p>
+ <p>While the files can be named anything, these are
+ the typical files in this folder (the convention is to name
+ the file after the type of elements defined within):</p>
+ <ul>
+ <li><strong>arrays.xml</strong> to define arrays </li>
+ <!-- TODO: add section on arrays -->
+ <li><strong>colors.xml</strong> to define <a href="available-resources.html#colordrawableresources">color
+ drawables</a> and <a href="#colorvals">color string values</a>.
+ Use <code>Resources.getDrawable()</code> and
+ <code>Resources.getColor(), respectively,</code>
+ to get these resources.</li>
+ <li><strong>dimens.xml</strong> to define <a href="available-resources.html#dimension">dimension value</a>. Use <code>Resources.getDimension()</code> to get
+ these resources.</li>
+ <li><strong>strings.xml</strong> to define <a href="available-resources.html#stringresources">string</a> values (use either
+ <code>Resources.getString</code> or preferably <code>Resources.getText()</code>
+ to get
+ these resources. <code>getText()</code> will retain any rich text styling
+ which is usually desirable for UI strings.</li>
+ <li><strong>styles.xml</strong> to define <a href="available-resources.html#stylesandthemes">style</a> objects.</li>
+ </ul></td>
+ </tr>
+ <tr>
+ <td><code>res/xml/</code></td>
+ <td>Arbitrary XML files that are compiled and can be read at run time by
+ calling {@link android.content.res.Resources#getXml(int) Resources.getXML()}.</td>
+ </tr>
+ <tr>
+ <td><code>res/raw/</code></td>
+ <td>Arbitrary files to copy directly to the device. They are added uncompiled
+ to the compressed file that your application build produces. To use these
+ resources in your application, call {@link android.content.res.Resources#openRawResource(int)
+ Resources.openRawResource()} with the resource ID, which is R.raw.<em>somefilename</em>.</td>
+ </tr>
+</table>
+<p>Resources are compiled into the final APK file. Android creates a wrapper class,
+ called R, that you can use to refer to these resources in your code. R contains subclasses
+ named according to the path and file name of the source file</p>
+<a name="colorvals" id="colorvals"></a>
+<h3>Global Resource Notes</h3>
+<ul>
+ <li>Several resources allow you to define colors. Android accepts color values
+ written in various web-style formats -- a hexadecimal constant in any of the
+ following forms: #RGB, #ARGB, #RRGGBB, #AARRGGBB. </li>
+ <li>All color values support setting an alpha channel value, where the first
+ two hexadecimal numbers specify the transparency. Zero in the alpha channel
+ means transparent. The default value is opaque. </li>
+</ul>
+<a name="UsingResources" id="UsingResources"></a>
+<h2>Using Resources </h2>
+<p>This section describes how to use the resources you've created. It includes the
+ following topics:</p>
+<ul>
+ <li><a href="#ResourcesInCode">Using resources in code</a> - How to call
+ resources in your code to instantiate them. </li>
+ <li><a href="#ReferencesToResources">Referring to resources from other resources</a> -
+ You can reference resources from other resources. This lets you reuse common
+ resource values inside resources. </li>
+ <li><a href="#AlternateResources">Supporting Alternate Resources for Alternate
+ Configurations</a> - You can specify different resources
+ to load, depending on the language or display configuration of the host
+ hardware. </li>
+</ul>
+<p>At compile time, Android generates a class named R that contains resource identifiers
+ to all the resources in your program. This class contains several subclasses,
+ one for each type of resource supported by Android, and for which you provided
+ a resource file. Each class contains one or more identifiers for the compiled resources,
+ that you use in your code to load the resource. Here is a small resource file
+ that contains string, layout (screens or parts of screens), and image resources.</p>
+<p class="note"><strong>Note:</strong> the R class is an auto-generated file and is not
+designed to be edited by hand. It will be automatically re-created as needed when
+the resources are updated.</p>
+<pre class="prettyprint">package com.android.samples;
+public final class R {
+ public static final class string {
+ public static final int greeting=0x0204000e;
+ public static final int start_button_text=0x02040001;
+ public static final int submit_button_text=0x02040008;
+ public static final int main_screen_title=0x0204000a;
+ };
+ public static final class layout {
+ public static final int start_screen=0x02070000;
+ public static final int new_user_pane=0x02070001;
+ public static final int select_user_list=0x02070002;
+
+ };
+ public static final class drawable {
+ public static final int company_logo=0x02020005;
+ public static final int smiling_cat=0x02020006;
+ public static final int yellow_fade_background=0x02020007;
+ public static final int stretch_button_1=0x02020008;
+
+ };
+};
+</pre>
+<a name="ResourcesInCode" id="ResourcesInCode"></a>
+<h3>Using Resources in Code </h3>
+
+<p>Using resources in code is just a matter of knowing the full resource ID
+and what type of object your resource has been compiled into. Here is the
+syntax for referring to a resource:</p>
+<p><code>R.<em>resource_type</em>.<em>resource_name</em></code></p>
+<p>or</p>
+<p><code>android.R.<em>resource_type</em>.<em>resource_name</em></code></p>
+
+<p>Where <code>resource_type</code> is the R subclass that holds a specific type
+of resource. <code>resource_name</code> is the <em>name</em> attribute for resources
+defined in XML files, or the file name (without the extension) for resources
+defined by other file types. Each type of resource will be added to a specific
+R subclass, depending on the type of resource it is; to learn which R subclass
+hosts your compiled resource type, consult the
+<a href="available-resources.html">Available Resources</a> document. Resources compiled by your own application can
+be referred to without a package name (simply as
+<code>R.<em>resource_type</em>.<em>resource_name</em></code>). Android contains
+a number of standard resources, such as screen styles and button backgrounds. To
+refer to these in code, you must qualify them with <code>android</code>, as in
+<code>android.R.drawable.button_background</code>.</p>
+
+<p>Here are some good and bad examples of using compiled resources in code:</p>
+
+<pre class="prettyprint">// Load a background for the current screen from a drawable resource.
+this.getWindow().setBackgroundDrawableResource(R.drawable.my_background_image);
+
+// WRONG Sending a string resource reference into a
+// method that expects a string.
+this.getWindow().setTitle(R.string.main_title);
+
+// RIGHT Need to get the title from the Resources wrapper.
+this.getWindow().setTitle(Resources.getText(R.string.main_title));
+
+// Load a custom layout for the current screen.
+setContentView(R.layout.main_screen);
+
+// Set a slide in animation for a ViewFlipper object.
+mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
+ R.anim.hyperspace_in));
+
+// Set the text on a TextView object.
+TextView msgTextView = (TextView)findViewByID(R.id.msg);
+msgTextView.setText(R.string.hello_message); </pre>
+
+<a name="ReferencesToResources" id="ReferencesToResources"></a>
+<h3>References to Resources</h3>
+
+<p>A value supplied in an attribute (or resource) can also be a reference to
+a resource. This is often used in layout files to supply strings (so they
+can be localized) and images (which exist in another file), though a reference
+can be any resource type including colors and integers.</p>
+
+<p>For example, if we have
+<a href="available-resources.html#colordrawableresources">color
+resources</a>, we can write a layout file that sets the text color size to be
+the value contained in one of those resources:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<EditText id="text"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"
+ <strong>android:textColor="@color/opaque_red"</strong>
+ android:text="Hello, World!" />
+</pre>
+
+<p>Note here the use of the '@' prefix to introduce a resource reference -- the
+text following that is the name of a resource in the form
+of <code>@[package:]type/name</code>. In this case we didn't need to specify
+the package because we are referencing a resource in our own package. To
+reference a system resource, you would need to write:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<EditText id="text"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"
+ android:textColor="@<strong>android:</strong>color/opaque_red"
+ android:text="Hello, World!" />
+</pre>
+
+<p>As another example, you should always use resource references when supplying
+strings in a layout file so that they can be localized:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<EditText id="text"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"
+ android:textColor="@android:color/opaque_red"
+ android:text="@string/hello_world" />
+</pre>
+
+<p>This facility can also be used to create references between resources.
+For example, we can create new drawable resources that are aliases for
+existing images:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <drawable id="my_background">@android:drawable/theme2_background</drawable>
+</resources>
+</pre>
+
+<a name="ReferencesToThemeAttributes"></a>
+<h3>References to Theme Attributes</h3>
+
+<p>Another kind of resource value allows you to reference the value of an
+attribute in the current theme. This attribute reference can <em>only</em>
+be used in style resources and XML attributes; it allows you to customize the
+look of UI elements by changing them to standard variations supplied by the
+current theme, instead of supplying more concrete values.</p>
+
+<p>As an example, we can use this in our layout to set the text color to
+one of the standard colors defined in the base system theme:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<EditText id="text"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"
+ <strong>android:textColor="?android:textDisabledColor"</strong>
+ android:text="@string/hello_world" />
+</pre>
+
+<p>Note that this is very similar to a resource reference, except we are using
+an '?' prefix instead of '@'. When you use this markup, you are supplying
+the name of an attribute resource that will be looked up in the theme --
+because the resource tool knows that an attribute resource is expected,
+you do not need to explicitly state the type (which would be
+<code>?android:attr/android:textDisabledColor</code>).</p>
+
+<p>Other than using this resource identifier to find the value in the
+theme instead of raw resources, the name syntax is identical to the '@' format:
+<code>?[namespace:]type/name</code> with the type here being optional.</p>
+
+<a name="UsingSystemResources"></a>
+<h3>Using System Resources</h3>
+
+<p>Many resources included with the system are available to applications.
+All such resources are defined under the class "android.R". For example,
+you can display the standard application icon in a screen with the following
+code:</p>
+
+<pre class="prettyprint">
+public class MyActivity extends Activity
+{
+ public void onStart()
+ {
+ requestScreenFeatures(FEATURE_BADGE_IMAGE);
+
+ super.onStart();
+
+ setBadgeResource(android.R.drawable.sym_def_app_icon);
+ }
+}
+</pre>
+
+<p>In a similar way, this code will apply to your screen the standard
+"green background" visual treatment defined by the system:</p>
+
+<pre class="prettyprint">
+public class MyActivity extends Activity
+{
+ public void onStart()
+ {
+ super.onStart();
+
+ setTheme(android.R.style.Theme_Black);
+ }
+}
+</pre>
+
+<a name="AlternateResources" id="AlternateResources"></a>
+<h2>Alternate Resources (for alternate languages and configurations)</h2>
+
+<p>You can supply different resources for your application to use depending on the UI
+language or hardware configuration on the device. Note that although you can
+include different string, layout, and other resources, the SDK does not expose
+methods to let you specify which alternate resource set to load. Android
+detects the proper set for the hardware and location, and loads them as
+appropriate. Users can select alternate language settings using the settings
+panel on the device. </p>
+<p>To include alternate resources, create parallel resource folders with
+qualifiers appended to the folder names, indicating the configuration it
+applies to (language, screen orientation, and so on). For example, here is a
+project that holds one string resource file for English, and another for
+French:</p>
+
+<pre>
+MyApp/
+ res/
+ values-en/
+ strings.xml
+ values-fr/
+ strings.xml
+</pre>
+
+<p>Android supports several types of qualifiers, with various values for each.
+Append these to the end of the resource folder name, separated by dashes. You
+can add multiple qualifiers to each folder name, but they must appear in the
+order they are listed here. For example, a folder containing drawable
+resources for a fully specified configuration would look like this:</p>
+
+<pre>
+MyApp/
+ res/
+ drawable-en-rUS-port-160dpi-finger-keysexposed-qwerty-dpad-480x320/
+</pre>
+
+<p>More typically, you will only specify a few specific configuration options. You may drop any of the values from the
+complete list, as long as the remaining values are still in the same
+order:</p>
+
+<pre>
+MyApp/
+ res/
+ drawable-en-rUS-finger/
+ drawable-port/
+ drawable-port-160dpi/
+ drawable-qwerty/
+</pre>
+<p>Table 2 lists the valid folder-name qualifiers, in order of precedence. Qualifiers that are listed higher in the table take precedence over those listed lower, as described in <a href="#best-match">How Android finds the best matching directory</a>. </p>
+<p class="caption" id="table2">Table 2</p>
+<table border="1">
+ <tr>
+ <th> Qualifier </th>
+ <th> Values </th>
+ </tr>
+ <tr>
+ <td>MCC and MNC</td>
+ <td>The <a href="http://en.wikipedia.org/wiki/Mobile_country_code">mobile country code</a> and <a href="http://en.wikipedia.org/wiki/Mobile_Network_Code">mobile network code</a> from the SIM in the device. For example <code>mcc310-mnc004</code> (U.S., Verizon brand); <code>mcc208-mnc00</code> (France, Orange brand); <code>mcc234-mnc00</code> (U.K., BT brand). <br>
+ <br>
+ If the device uses a radio connection (GSM phone), the MCC will come from the SIM, and the MNC will come from the network to which the device is attached. You might sometimes use the MCC alone, for example to include country-specific legal resources in your application. If your application specifies resources for a MCC/MNC combination, those resources can only be used if both the MCC and the MNC match. </td>
+ </tr>
+ <tr>
+ <td>Language and region</td>
+ <td>The two letter <a href="http://www.loc.gov/standards/iso639-2/php/code_list.php">ISO
+ 639-1</a> language code and two letter
+ <a href="http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html">ISO
+ 3166-1-alpha-2</a> region code (preceded by lowercase "r"). For example
+ <code>en-rUS</code>, <code>fr-rFR</code>, <code>es-rES</code>. <br>
+ <br>
+ The codes are case-sensitive: The language code is lowercase, and the country code is uppercase. You cannot specify a region alone, but you can specify a language alone, for example <code>en</code>, <code>fr</code>, <code>es</code>. </td>
+ </tr>
+ <tr>
+ <td>Screen orientation</td>
+ <td><code>port</code>, <code>land</code>, <code>square</code> </td>
+ </tr>
+ <tr>
+ <td>Screen pixel density</td>
+ <td><code>92dpi</code>, <code>108dpi</code>, etc. When Android selects which resource files to use, it handles screen density differently than the other qualifiers. In step 1 of <a href="#best-match">How Android finds the best matching directory</a> (below), screen density is always considered to be a match. In step 4, if the qualifier being considered is screen density, Android will select the best final match at that point, without any need to move on to step 5. </td>
+ </tr>
+ <tr>
+ <td>Touchscreen type</td>
+ <td><code>notouch</code>, <code>stylus</code>, <code>finger</code></td>
+ </tr>
+ <tr>
+ <td>Whether the keyboard is available to the user</td>
+ <td><code>keysexposed</code>, <code>keyshidden</code>, <code>keyssoft</code> <br>
+ If your application has specific resources that should only be used with a soft keyboard, use the <code>keyssoft</code> value. If no <code>keyssoft</code> resources are available (only <code>keysexposed</code> and <code>keyshidden</code>) and the device shows a soft keyboard, the system will use <code>keysexposed</code> resources. </td>
+ </tr>
+ <tr>
+ <td>Primary text input method</td>
+ <td><code>nokeys</code>, <code>qwerty</code>, <code>12key</code> </td>
+ </tr>
+ <tr>
+ <td>Primary non-touchscreen<br />
+ navigation method</td>
+ <td><code>nonav</code>, <code>dpad</code>, <code>trackball</code>, <code>wheel</code> </td>
+ </tr>
+ <tr>
+ <td>Screen dimensions</td>
+ <td><code>320x240</code>, <code>640x480</code>, etc. The larger dimension
+ must be specified first. </td>
+ </tr>
+ <tr>
+ <td>SDK version</td>
+ <td>The SDK version supported by the device, for example <code>v3</code>. The Android 1.0 SDK is <code>v1, </code> the 1.1 SDK is <code>v2</code>, and the 1.5 SDK is <code>v3</code>.</td>
+ </tr>
+ <tr>
+ <td>(Minor version)</td>
+ <td>(You cannot currently specify minor version. It is always set to 0.)</td>
+ </tr>
+</table>
+
+<p>This list does not include device-specific parameters such as carrier,
+branding, device/hardware, or manufacturer. Everything that an application
+needs to know about the device that it is running on is encoded via the
+resource qualifiers in the table above.</p>
+
+<p>All resource directories, qualified and unqualified, live under the <code>res/</code> folder. Here are some guidelines on qualified resource directory names:</p>
+
+<ul>
+ <li>You can specify multiple qualifiers, separated by dashes. For example, <code>drawable-en-rUS-land</code> will apply to US-English
+ devices in landscape orientation. </li>
+ <li>The qualifiers must be in the order listed in <a href="#table2">Table 2</a> above. For example:
+ <ul>
+ <li>Correct: <code>values-mcc460-nokeys/</code></li>
+ <li>Incorrect: <code>values-nokeys-mcc460/</code></li>
+ </ul>
+ </li>
+ <li>Values are case-sensitive. For example, a portrait-specific <code>drawable</code> directory must be named
+ <code>drawable-port</code>, not <code>drawable-PORT</code> or <code>drawable-Port</code>.</li>
+ <li>Only one value for each qualifier type is supported. For example, if you want to use exactly the same drawable files for Spain and France, you will need two resource directories, such as <code>drawable-rES/</code> and <code>drawable-rFR/</code>, containing identical files. You cannot
+ have a directory named <code>drawable-rES-rFR/</code>. </li>
+ <li>Qualified directories cannot be nested. For example, you cannot have <code>res/drawable/drawable-en</code>. </li>
+</ul>
+
+<h3>How resources are referenced in code</h3>
+<p>All resources will be referenced in code or resource reference syntax by
+ their simple, undecorated names. So if a resource were named this:<br />
+ <code>MyApp/res/drawable-port-92dpi/myimage.png</code><br />
+ It would be referenced as this:<br />
+ <code>R.drawable.myimage</code> (code)<br />
+ <code>@drawable/myimage</code> (XML)</p>
+<p>If several drawable directories are available, Android will select one of them (as described below) and load <code>myimage.png</code> from it.</p>
+<h3 id="best-match">How Android finds the best matching directory </h3>
+
+<p>Android will pick which of the various underlying resource files should be
+used at runtime, depending on the current configuration of the device. The example used here assumes the following device configuration:</p>
+<blockquote>
+ <p>Locale = <code>en-GB</code><br>
+ Screen orientation = <code>port</code><br>
+ Screen pixel density = <code>108dpi</code><br>
+ Touchscreen type = <code>notouch</code><br>
+ Primary text input method = <code>12key</code><br>
+ </p>
+</blockquote>
+<p>Here is how Android makes the selection: </p>
+<ol>
+ <li>
+ Eliminate resource files that contradict the
+ device configuration. For example, assume that the following resource directories are available for drawables. The <code>drawable-fr-rCA/</code> directory will be eliminated, because it contradicts the locale of the device.<br>
+<pre>MyApp/res/drawable/
+MyApp/res/drawable-en/
+<strike>MyApp/res/drawable-fr-rCA/</strike>
+MyApp/res/drawable-en-port/
+MyApp/res/drawable-en-notouch-12key/
+MyApp/res/drawable-port-92dpi/
+MyApp/res/drawable-port-notouch-12key</pre>
+ <strong>Exception: </strong>Screen pixel density is the one qualifier that is not used to eliminate files. Even though the screen density of the device is 108 dpi, <code>drawable-port-92dpi/</code> is not eliminated from the list, because every screen density is considered to be a
+ match at this point.</li>
+ <li>From <a href="#table2">Table 2</a>, pick the highest-precedence qualifier that remains in the list. (Start with MCC, then move down through the list.) </li>
+ <li>Do any of the available resource directories include this qualifier? </li>
+ <ul>
+ <li>If No, return to step 2 and look at the next qualifier listed in Table 2. In our example, the answer is "no" until we reach Language.</li>
+ <li>If Yes, move on to step 4.</li>
+ </ul>
+ <li>Eliminate resource directories that do not include this qualifier. In our example, we eliminate all the directories that do not include a language qualifier. </li>
+ <pre><strike>MyApp/res/drawable/</strike>
+MyApp/res/drawable-en/
+MyApp/res/drawable-en-port/
+MyApp/res/drawable-en-notouch-12key/
+<strike>MyApp/res/drawable-port-92dpi/</strike>
+<strike>MyApp/res/drawable-port-notouch-12key</strike></pre>
+ <strong>Exception:</strong> If the qualifier in question is screen pixel density, Android will select the option that most closely matches the device, and the selection process will be complete. In general, Android will prefer scaling down a larger original image to scaling up a smaller original image.<br><br></li>
+
+<li>Go back and repeat steps 2, 3, and 4 until only one choice remains. In the example, screen orientation is the next qualifier in the table for which we have any matches.
+ Eliminate resources that do not specify a screen orientation. </p>
+ <pre><strike>MyApp/res/drawable-en/</strike>
+MyApp/res/drawable-en-port/
+<strike>MyApp/res/drawable-en-notouch-12key/</strike></pre>
+ Only one choice remains, so that's it. When drawables are called for in this example application, the Android system will load resources from the <code>MyApp/res/drawable-en-port/</code> directory.
+</ol>
+<p class="note"><strong>Tip:</strong> The <em>precedence</em> of the qualifiers is more important than the number of qualifiers that exactly match the device. For example, in step 4 above, the last choice on the list includes three qualifiers that exactly match the device (orientation, touchscreen type, and input method), while <code>drawable-en</code> has only one parameter that matches (language). However, language has a higher precedence, so <code>drawable-port-notouch-12key</code> is out.</p>
+<p>This flowchart summarizes how Android selects resource directories to load.</p>
+<p><img src="res-selection-flowchart.png" alt="resource-selection" width="461" height="471" style="margin:15px"></p>
+<h3>Terminology</h3>
+<p>The resource system brings a number of different pieces together to
+form the final complete resource functionality. To help understand the
+overall system, here are some brief definitions of the core concepts and
+components you will encounter in using it:</p>
+
+<p><strong>Asset</strong>: A single blob of data associated with an application. This
+includes object files compiled from the Java source code, graphics (such as PNG
+images), XML files, etc. These files are organized in a directory hierarchy
+that, during final packaging of the application, is bundled together into a
+single ZIP file.</p>
+
+<p><strong>aapt</strong>: Android Asset Packaging Tool. The tool that generates the
+final ZIP file of application assets. In addition to collecting raw assets
+together, it also parses resource definitions into binary asset data.</p>
+
+<p><strong>Resource Table</strong>: A special asset that aapt generates for you,
+describing all of the resources contained in an application/package.
+This file is accessed for you by the Resources class; it is not touched
+directly by applications.</p>
+
+<p><strong>Resource</strong>: An entry in the Resource Table describing a single
+named value. Broadly, there are two types of resources: primitives and
+bags.</p>
+
+<p><strong>Resource Identifier</strong>: In the Resource Table all resources are
+identified by a unique integer number. In source code (resource descriptions,
+XML files, Java source code) you can use symbolic names that stand as constants for
+the actual resource identifier integer.</p>
+
+<p><strong>Primitive Resource</strong>: All primitive resources can be written as a
+simple string, using formatting to describe a variety of primitive types
+included in the resource system: integers, colors, strings, references to
+other resources, etc. Complex resources, such as bitmaps and XML
+describes, are stored as a primitive string resource whose value is the path
+of the underlying Asset holding its actual data.</p>
+
+<p><strong>Bag Resource</strong>: A special kind of resource entry that, instead of a
+simple string, holds an arbitrary list of name/value pairs. Each name is
+itself a resource identifier, and each value can hold
+the same kinds of string formatted data as a normal resource. Bags also
+support inheritance: a bag can inherit the values from another bag, selectively
+replacing or extending them to generate its own contents.</p>
+
+<p><strong>Kind</strong>: The resource kind is a way to organize resource identifiers
+for various purposes. For example, drawable resources are used to
+instantiate Drawable objects, so their data is a primitive resource containing
+either a color constant or string path to a bitmap or XML asset. Other
+common resource kinds are string (localized string primitives), color
+(color primitives), layout (a string path to an XML asset describing a view
+layout), and style (a bag resource describing user interface attributes).
+There is also a standard "attr" resource kind, which defines the resource
+identifiers to be used for naming bag items and XML attributes</p>
+
+<p><strong>Style</strong>: The name of the resource kind containing bags that are used
+to supply a set of user interface attributes. For example, a TextView class may
+be given a style resource that defines its text size, color, and alignment.
+In a layout XML file, you associate a style with a bag using the "style"
+attribute, whose value is the name of the style resource.</p>
+
+<p><strong>Style Class</strong>: Specifies a related set of attribute resources.
+This data is not placed in the resource table itself, but used to generate
+constants in the source code that make it easier for you to retrieve values out of
+a style resource and/or XML tag's attributes. For example, the
+Android platform defines a "View" style class that
+contains all of the standard view attributes: padding, visibility,
+background, etc.; when View is inflated it uses this style class to
+retrieve those values from the XML file (at which point style and theme
+information is applied as approriate) and load them into its instance.</p>
+
+<p><strong>Configuration</strong>: For any particular resource identifier, there may be
+multiple different available values depending on the current configuration.
+The configuration includes the locale (language and country), screen
+orientation, etc. The current configuration is used to
+select which resource values are in effect when the resource table is
+loaded.</p>
+
+<p><strong>Theme</strong>: A standard style resource that supplies global
+attribute values for a particular context. For example, when writing an
+Activity the application developer can select a standard theme to use, such
+as the Theme.White or Theme.Black styles; this style supplies information
+such as the screen background image/color, default text color, button style,
+text editor style, text size, etc. When inflating a layout resource, most
+values for widgets (the text color, selector, background) if not explicitly
+set will come from the current theme; style and attribute
+values supplied in the layout can also assign their value from explicitly
+named values in the theme attributes if desired.</p>
+
+<p><strong>Overlay</strong>: A resource table that does not define a new set of resources,
+but instead replaces the values of resources that are in another resource table.
+Like a configuration, this is applied at load time
+to the resource data; it can add new configuration values (for example
+strings in a new locale), replace existing values (for example change
+the standard white background image to a "Hello Kitty" background image),
+and modify resource bags (for example change the font size of the Theme.White
+style to have an 18 pt font size). This is the facility that allows the
+user to select between different global appearances of their device, or
+download files with new appearances.</p>
+
+<h2>Resource Reference</h2>
+<p>The <a href="available-resources.html">Available Resources</a>
+document provides a detailed list of the various types of resource and how to use them
+from within the Java source code, or from other references.</p>
+
+<a name="i18n" id="i18n"></a>
+<h2>Internationalization and Localization</h2>
+<p class="note"><strong>Coming Soon:</strong> Internationalization and Localization are
+critical, but are also not quite ready yet in the current SDK. As the
+SDK matures, this section will contain information on the Internationalization
+and Localization features of the Android platform. In the meantime, it is a good
+idea to start by externalizing all strings, and practicing good structure in
+creating and using resources.</p>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 3db45f0..a7a8708 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -880,7 +880,9 @@
mShape = state.mShape;
mGradient = state.mGradient;
mOrientation = state.mOrientation;
- mColors = state.mColors.clone();
+ if (state.mColors != null) {
+ mColors = state.mColors.clone();
+ }
if (state.mPositions != null) {
mPositions = state.mPositions.clone();
}
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index 048bdd5..bbc21c4 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -86,10 +86,13 @@
class Mutex;
class String8;
-typedef void (*shutter_callback)(void *cookie);
-typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
-typedef void (*autofocus_callback)(bool focused, void *cookie);
-typedef void (*error_callback)(status_t err, void *cookie);
+// ref-counted object for callbacks
+class CameraListener: virtual public RefBase
+{
+public:
+ virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+ virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+};
class Camera : public BnCameraClient, public IBinder::DeathRecipient
{
@@ -144,13 +147,8 @@
// get preview/capture parameters - key/value pairs
String8 getParameters() const;
- void setShutterCallback(shutter_callback cb, void *cookie);
- void setRawCallback(frame_callback cb, void *cookie);
- void setJpegCallback(frame_callback cb, void *cookie);
- void setRecordingCallback(frame_callback cb, void *cookie);
- void setPreviewCallback(frame_callback cb, void *cookie, int preview_callback_flag = FRAME_CALLBACK_FLAG_NOOP);
- void setErrorCallback(error_callback cb, void *cookie);
- void setAutoFocusCallback(autofocus_callback cb, void *cookie);
+ void setListener(const sp<CameraListener>& listener);
+ void setPreviewCallbackFlags(int preview_callback_flag);
// ICameraClient interface
virtual void notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
@@ -160,6 +158,8 @@
private:
Camera();
+ Camera(const Camera&);
+ Camera& operator=(const Camera);
virtual void binderDied(const wp<IBinder>& who);
class DeathNotifier: public IBinder::DeathRecipient
@@ -179,20 +179,7 @@
sp<ICamera> mCamera;
status_t mStatus;
- shutter_callback mShutterCallback;
- void *mShutterCallbackCookie;
- frame_callback mRawCallback;
- void *mRawCallbackCookie;
- frame_callback mJpegCallback;
- void *mJpegCallbackCookie;
- frame_callback mPreviewCallback;
- void *mPreviewCallbackCookie;
- frame_callback mRecordingCallback;
- void *mRecordingCallbackCookie;
- error_callback mErrorCallback;
- void *mErrorCallbackCookie;
- autofocus_callback mAutoFocusCallback;
- void *mAutoFocusCallbackCookie;
+ sp<CameraListener> mListener;
friend class DeathNotifier;
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index 759a0cc..b1f5045 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -137,6 +137,7 @@
private:
void* m_buf;
+ bool m_loggedUnknownMetadata;
KeyedVector<String8,FileRec> m_files;
};
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 6613700..bb22dab 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -85,20 +85,6 @@
void Camera::init()
{
mStatus = UNKNOWN_ERROR;
- mShutterCallback = 0;
- mShutterCallbackCookie = 0;
- mRawCallback = 0;
- mRawCallbackCookie = 0;
- mJpegCallback = 0;
- mJpegCallbackCookie = 0;
- mPreviewCallback = 0;
- mPreviewCallbackCookie = 0;
- mRecordingCallback = 0;
- mRecordingCallbackCookie = 0;
- mErrorCallback = 0;
- mErrorCallbackCookie = 0;
- mAutoFocusCallback = 0;
- mAutoFocusCallbackCookie = 0;
}
Camera::~Camera()
@@ -127,7 +113,6 @@
{
LOGV("disconnect");
if (mCamera != 0) {
- mErrorCallback = 0;
mCamera->disconnect();
mCamera = 0;
}
@@ -285,125 +270,49 @@
return params;
}
-void Camera::setAutoFocusCallback(autofocus_callback cb, void *cookie)
+void Camera::setListener(const sp<CameraListener>& listener)
{
- LOGV("setAutoFocusCallback");
- mAutoFocusCallback = cb;
- mAutoFocusCallbackCookie = cookie;
+ Mutex::Autolock _l(mLock);
+ mListener = listener;
}
-void Camera::setShutterCallback(shutter_callback cb, void *cookie)
+void Camera::setPreviewCallbackFlags(int flag)
{
- LOGV("setShutterCallback");
- mShutterCallback = cb;
- mShutterCallbackCookie = cookie;
-}
-
-void Camera::setRawCallback(frame_callback cb, void *cookie)
-{
- LOGV("setRawCallback");
- mRawCallback = cb;
- mRawCallbackCookie = cookie;
-}
-
-void Camera::setJpegCallback(frame_callback cb, void *cookie)
-{
- LOGV("setJpegCallback");
- mJpegCallback = cb;
- mJpegCallbackCookie = cookie;
-}
-
-void Camera::setPreviewCallback(frame_callback cb, void *cookie, int flag)
-{
- LOGV("setPreviewCallback");
- mPreviewCallback = cb;
- mPreviewCallbackCookie = cookie;
+ LOGV("setPreviewCallbackFlags");
sp <ICamera> c = mCamera;
if (c == 0) return;
mCamera->setPreviewCallbackFlag(flag);
}
-void Camera::setRecordingCallback(frame_callback cb, void *cookie)
-{
- LOGV("setRecordingCallback");
- mRecordingCallback = cb;
- mRecordingCallbackCookie = cookie;
-}
-
-void Camera::setErrorCallback(error_callback cb, void *cookie)
-{
- LOGV("setErrorCallback");
- mErrorCallback = cb;
- mErrorCallbackCookie = cookie;
-}
-
// callback from camera service
void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
{
- switch(msgType) {
- case CAMERA_MSG_ERROR:
- LOGV("errorCallback");
- if (mErrorCallback) {
- mErrorCallback((status_t)ext1, mErrorCallbackCookie);
- }
- break;
- case CAMERA_MSG_FOCUS:
- LOGV("autoFocusCallback");
- if (mAutoFocusCallback) {
- mAutoFocusCallback((bool)ext1, mAutoFocusCallbackCookie);
- }
- break;
- case CAMERA_MSG_SHUTTER:
- LOGV("shutterCallback");
- if (mShutterCallback) {
- mShutterCallback(mShutterCallbackCookie);
- }
- break;
- default:
- LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2);
- break;
+ sp<CameraListener> listener;
+ {
+ Mutex::Autolock _l(mLock);
+ listener = mListener;
+ }
+ if (listener != NULL) {
+ listener->notify(msgType, ext1, ext2);
}
}
// callback from camera service when frame or image is ready
void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
{
- switch(msgType) {
- case CAMERA_MSG_PREVIEW_FRAME:
- LOGV("previewCallback");
- if (mPreviewCallback) {
- mPreviewCallback(dataPtr, mPreviewCallbackCookie);
- }
- break;
- case CAMERA_MSG_VIDEO_FRAME:
- LOGV("recordingCallback");
- if (mRecordingCallback) {
- mRecordingCallback(dataPtr, mRecordingCallbackCookie);
- }
- break;
- case CAMERA_MSG_RAW_IMAGE:
- LOGV("rawCallback");
- if (mRawCallback) {
- mRawCallback(dataPtr, mRawCallbackCookie);
- }
- break;
- case CAMERA_MSG_COMPRESSED_IMAGE:
- LOGV("jpegCallback");
- if (mJpegCallback) {
- mJpegCallback(dataPtr, mJpegCallbackCookie);
- }
- break;
- default:
- LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
- break;
+ sp<CameraListener> listener;
+ {
+ Mutex::Autolock _l(mLock);
+ listener = mListener;
+ }
+ if (listener != NULL) {
+ listener->postData(msgType, dataPtr);
}
}
void Camera::binderDied(const wp<IBinder>& who) {
LOGW("ICamera died");
- if (mErrorCallback) {
- mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
- }
+ notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0);
}
void Camera::DeathNotifier::binderDied(const wp<IBinder>& who) {
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 67d07fe..99a4abc 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -41,6 +41,33 @@
#define MAGIC0 0x70616e53 // Snap
#define MAGIC1 0x656c6946 // File
+/*
+ * File entity data format (v1):
+ *
+ * - 4-byte version number of the metadata, little endian (0x00000001 for v1)
+ * - 12 bytes of metadata
+ * - the file data itself
+ *
+ * i.e. a 16-byte metadata header followed by the raw file data. If the
+ * restore code does not recognize the metadata version, it can still
+ * interpret the file data itself correctly.
+ *
+ * file_metadata_v1:
+ *
+ * - 4 byte version number === 0x00000001 (little endian)
+ * - 4-byte access mode (little-endian)
+ * - undefined (8 bytes)
+ */
+
+struct file_metadata_v1 {
+ int version;
+ int mode;
+ int undefined_1;
+ int undefined_2;
+};
+
+const static int CURRENT_METADATA_VERSION = 1;
+
#if 1 // TEST_BACKUP_HELPERS
#define LOGP(f, x...) printf(f "\n", x)
#else
@@ -181,29 +208,48 @@
}
static int
-write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
+write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
char const* realFilename)
{
- LOGP("write_update_file %s (%s)\n", realFilename, key.string());
+ LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
const int bufsize = 4*1024;
int err;
int amt;
int fileSize;
int bytesLeft;
+ file_metadata_v1 metadata;
char* buf = (char*)malloc(bufsize);
int crc = crc32(0L, Z_NULL, 0);
- bytesLeft = fileSize = lseek(fd, 0, SEEK_END);
+ fileSize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
+ if (sizeof(metadata) != 16) {
+ LOGE("ERROR: metadata block is the wrong size!");
+ }
+
+ bytesLeft = fileSize + sizeof(metadata);
err = dataStream->WriteEntityHeader(key, bytesLeft);
if (err != 0) {
+ free(buf);
return err;
}
+ // store the file metadata first
+ metadata.version = tolel(CURRENT_METADATA_VERSION);
+ metadata.mode = tolel(mode);
+ metadata.undefined_1 = metadata.undefined_2 = 0;
+ err = dataStream->WriteEntityData(&metadata, sizeof(metadata));
+ if (err != 0) {
+ free(buf);
+ return err;
+ }
+ bytesLeft -= sizeof(metadata); // bytesLeft should == fileSize now
+
+ // now store the file content
while ((amt = read(fd, buf, bufsize)) != 0 && bytesLeft > 0) {
bytesLeft -= amt;
if (bytesLeft < 0) {
@@ -211,6 +257,7 @@
}
err = dataStream->WriteEntityData(buf, amt);
if (err != 0) {
+ free(buf);
return err;
}
}
@@ -224,6 +271,7 @@
bytesLeft -= amt;
err = dataStream->WriteEntityData(buf, amt);
if (err != 0) {
+ free(buf);
return err;
}
}
@@ -233,7 +281,6 @@
}
free(buf);
-
return NO_ERROR;
}
@@ -241,11 +288,19 @@
write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
{
int err;
+ struct stat st;
+
+ err = stat(realFilename, &st);
+ if (err < 0) {
+ return errno;
+ }
+
int fd = open(realFilename, O_RDONLY);
if (fd == -1) {
return errno;
}
- err = write_update_file(dataStream, fd, key, realFilename);
+
+ err = write_update_file(dataStream, fd, st.st_mode, key, realFilename);
close(fd);
return err;
}
@@ -266,7 +321,6 @@
}
free(buf);
-
return crc;
}
@@ -356,7 +410,7 @@
g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
|| f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
- write_update_file(dataStream, fd, p, g.file.string());
+ write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
}
close(fd);
@@ -390,6 +444,7 @@
RestoreHelperBase::RestoreHelperBase()
{
m_buf = malloc(RESTORE_BUF_SIZE);
+ m_loggedUnknownMetadata = false;
}
RestoreHelperBase::~RestoreHelperBase()
@@ -416,8 +471,25 @@
return err;
}
- // TODO: World readable/writable for now.
- mode = 0666;
+ // Get the metadata block off the head of the file entity and use that to
+ // set up the output file
+ file_metadata_v1 metadata;
+ amt = in->ReadEntityData(&metadata, sizeof(metadata));
+ if (amt != sizeof(metadata)) {
+ LOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
+ (long)amt, strerror(errno));
+ return EIO;
+ }
+ metadata.version = fromlel(metadata.version);
+ metadata.mode = fromlel(metadata.mode);
+ if (metadata.version > CURRENT_METADATA_VERSION) {
+ if (!m_loggedUnknownMetadata) {
+ m_loggedUnknownMetadata = true;
+ LOGW("Restoring file with unsupported metadata version %d (currently %d)",
+ metadata.version, CURRENT_METADATA_VERSION);
+ }
+ }
+ mode = metadata.mode;
// Write the file and compute the crc
crc = crc32(0L, Z_NULL, 0);
@@ -538,6 +610,7 @@
}
}
+ free(contents);
return contentsMatch && sizesMatch ? 0 : 1;
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 7bfeb83..0273a5a 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -41,7 +41,7 @@
// ----------------------------------------------------------------------------
// helper function to extract a native Camera object from a Camera Java object
-extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct camera_context_t** context);
+extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct JNICameraContext** context);
struct fields_t {
jfieldID context;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b2f3557..660b469 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -592,6 +592,21 @@
loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
R.integer.def_screen_off_timeout);
+ // Set default cdma emergency tone
+ loadSetting(stmt, Settings.System.EMERGENCY_TONE, 0);
+
+ // Set default cdma call auto retry
+ loadSetting(stmt, Settings.System.CALL_AUTO_RETRY, 0);
+
+ // Set default cdma DTMF type
+ loadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);
+
+ // Set default hearing aid
+ loadSetting(stmt, Settings.System.HEARING_AID, 0);
+
+ // Set default tty mode
+ loadSetting(stmt, Settings.System.TTY_MODE, 0);
+
loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
R.bool.def_airplane_mode_on);
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 0aa4fa5..0dafcc1 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#define LOG_NDEBUG 0
#include <stdio.h>
#include <unistd.h>
@@ -168,7 +168,7 @@
static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
AudioSystem::audio_format format, int channel,
int8_t *&wav, size_t &bufferSize, tts_synth_status status) {
- LOGI("ttsSynthDoneCallback: %d bytes", bufferSize);
+ LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
if (userdata == NULL){
LOGE("userdata == NULL");
@@ -178,7 +178,7 @@
SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage);
if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){
- LOGI("Direct speech");
+ LOGV("Direct speech");
if (wav == NULL) {
delete pForAfter;
@@ -189,16 +189,16 @@
prepAudioTrack(pJniData, rate, format, channel);
if (pJniData->mAudioOut) {
pJniData->mAudioOut->write(wav, bufferSize);
- LOGI("AudioTrack wrote: %d bytes", bufferSize);
+ //LOGV("AudioTrack wrote: %d bytes", bufferSize);
} else {
- LOGI("Can't play, null audiotrack");
+ LOGE("Can't play, null audiotrack");
}
}
} else if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) {
- LOGI("Save to file");
+ LOGV("Save to file");
if (wav == NULL) {
delete pForAfter;
- LOGI("Null: speech has completed");
+ LOGV("Null: speech has completed");
}
if (bufferSize > 0){
fwrite(wav, 1, bufferSize, pForAfter->outputFile);
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 21f56f8..6fa3141 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -170,6 +170,39 @@
}
+ private String getDefaultLanguage() {
+ String defaultLang = android.provider.Settings.Secure.getString(mResolver,
+ android.provider.Settings.Secure.TTS_DEFAULT_LANG);
+ if (defaultLang == null) {
+ return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG;
+ } else {
+ return defaultLang;
+ }
+ }
+
+
+ private String getDefaultCountry() {
+ String defaultCountry = android.provider.Settings.Secure.getString(mResolver,
+ android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY);
+ if (defaultCountry == null) {
+ return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
+ } else {
+ return defaultCountry;
+ }
+ }
+
+
+ private String getDefaultLocVariant() {
+ String defaultVar = android.provider.Settings.Secure.getString(mResolver,
+ android.provider.Settings.Secure.TTS_DEFAULT_VARIANT);
+ if (defaultVar == null) {
+ return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+ } else {
+ return defaultVar;
+ }
+ }
+
+
private void setSpeechRate(int rate) {
if (isDefaultEnforced()) {
nativeSynth.setSpeechRate(getDefaultRate());
@@ -185,15 +218,16 @@
private void setLanguage(String lang, String country, String variant) {
- Log.v("TTS", "TtsService.setLanguage("+lang+", "+country+", "+variant+")");
+ Log.v("TTS", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
if (isDefaultEnforced()) {
- nativeSynth.setLanguage(lang, country, variant);
+ nativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
+ getDefaultLocVariant());
} else {
- // TODO handle default language
- nativeSynth.setLanguage("eng", "USA", "");
+ nativeSynth.setLanguage(lang, country, variant);
}
}
+
/**
* Adds a sound resource to the TTS.
*
@@ -368,6 +402,7 @@
if (synthAvailable) {
synthesizerLock.unlock();
}
+ processSpeechQueue();
}
}
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 197404e..efa6179 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -76,8 +76,7 @@
private static final boolean DEBUG = true;
// Default time to wait after data changes before we back up the data
- private static final long COLLECTION_INTERVAL = 1000;
- //private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
+ private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
private static final int MSG_RUN_BACKUP = 1;
private static final int MSG_RUN_FULL_BACKUP = 2;
@@ -351,28 +350,29 @@
void addPackageParticipantsLocked(String packageName) {
// Look for apps that define the android:backupAgent attribute
if (DEBUG) Log.v(TAG, "addPackageParticipantsLocked: " + packageName);
- List<ApplicationInfo> targetApps = allAgentApps();
+ List<PackageInfo> targetApps = allAgentPackages();
addPackageParticipantsLockedInner(packageName, targetApps);
}
private void addPackageParticipantsLockedInner(String packageName,
- List<ApplicationInfo> targetApps) {
+ List<PackageInfo> targetPkgs) {
if (DEBUG) {
- Log.v(TAG, "Adding " + targetApps.size() + " backup participants:");
- for (ApplicationInfo a : targetApps) {
- Log.v(TAG, " " + a + " agent=" + a.backupAgentName);
+ Log.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
+ for (PackageInfo p : targetPkgs) {
+ Log.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName
+ + " uid=" + p.applicationInfo.uid);
}
}
- for (ApplicationInfo app : targetApps) {
- if (packageName == null || app.packageName.equals(packageName)) {
- int uid = app.uid;
+ for (PackageInfo pkg : targetPkgs) {
+ if (packageName == null || pkg.packageName.equals(packageName)) {
+ int uid = pkg.applicationInfo.uid;
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
if (set == null) {
set = new HashSet<ApplicationInfo>();
mBackupParticipants.put(uid, set);
}
- set.add(app);
+ set.add(pkg.applicationInfo);
backUpPackageManagerData();
}
}
@@ -382,67 +382,67 @@
// 'packageName' is null, *all* participating apps will be removed.
void removePackageParticipantsLocked(String packageName) {
if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
- List<ApplicationInfo> allApps = null;
+ List<PackageInfo> allApps = null;
if (packageName != null) {
- allApps = new ArrayList<ApplicationInfo>();
+ allApps = new ArrayList<PackageInfo>();
try {
- ApplicationInfo app = mPackageManager.getApplicationInfo(packageName, 0);
- allApps.add(app);
+ int flags = PackageManager.GET_SIGNATURES;
+ allApps.add(mPackageManager.getPackageInfo(packageName, flags));
} catch (Exception e) {
- // just skip it
+ // just skip it (???)
}
} else {
// all apps with agents
- allApps = allAgentApps();
+ allApps = allAgentPackages();
}
removePackageParticipantsLockedInner(packageName, allApps);
}
private void removePackageParticipantsLockedInner(String packageName,
- List<ApplicationInfo> agents) {
+ List<PackageInfo> agents) {
if (DEBUG) {
Log.v(TAG, "removePackageParticipantsLockedInner (" + packageName
+ ") removing " + agents.size() + " entries");
- for (ApplicationInfo a : agents) {
- Log.v(TAG, " - " + a);
+ for (PackageInfo p : agents) {
+ Log.v(TAG, " - " + p);
}
}
- for (ApplicationInfo app : agents) {
- if (packageName == null || app.packageName.equals(packageName)) {
- int uid = app.uid;
+ for (PackageInfo pkg : agents) {
+ if (packageName == null || pkg.packageName.equals(packageName)) {
+ int uid = pkg.applicationInfo.uid;
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
if (set != null) {
// Find the existing entry with the same package name, and remove it.
// We can't just remove(app) because the instances are different.
for (ApplicationInfo entry: set) {
- if (entry.packageName.equals(app.packageName)) {
+ if (entry.packageName.equals(pkg.packageName)) {
set.remove(entry);
backUpPackageManagerData();
break;
}
}
if (set.size() == 0) {
- mBackupParticipants.delete(uid); }
+ mBackupParticipants.delete(uid);
+ }
}
}
}
}
// Returns the set of all applications that define an android:backupAgent attribute
- private List<ApplicationInfo> allAgentApps() {
+ private List<PackageInfo> allAgentPackages() {
// !!! TODO: cache this and regenerate only when necessary
- List<ApplicationInfo> allApps = mPackageManager.getInstalledApplications(0);
- int N = allApps.size();
- if (N > 0) {
- for (int a = N-1; a >= 0; a--) {
- ApplicationInfo app = allApps.get(a);
- if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
- || app.backupAgentName == null) {
- allApps.remove(a);
- }
+ int flags = PackageManager.GET_SIGNATURES;
+ List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
+ int N = packages.size();
+ for (int a = N-1; a >= 0; a--) {
+ ApplicationInfo app = packages.get(a).applicationInfo;
+ if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
+ || app.backupAgentName == null) {
+ packages.remove(a);
}
}
- return allApps;
+ return packages;
}
// Reset the given package's known backup participants. Unlike add/remove, the update
@@ -455,7 +455,7 @@
if (DEBUG) Log.v(TAG, "updatePackageParticipantsLocked: " + packageName);
// brute force but small code size
- List<ApplicationInfo> allApps = allAgentApps();
+ List<PackageInfo> allApps = allAgentPackages();
removePackageParticipantsLockedInner(packageName, allApps);
addPackageParticipantsLockedInner(packageName, allApps);
}
@@ -578,17 +578,7 @@
public void run() {
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
- // start up the transport
- try {
- mTransport.startSession();
- } catch (Exception e) {
- Log.e(TAG, "Error session transport");
- e.printStackTrace();
- return;
- }
-
- // The transport is up and running. First, back up the package manager
- // metadata if necessary
+ // First, back up the package manager metadata if necessary
boolean doPackageManager;
synchronized (BackupManagerService.this) {
doPackageManager = mDoPackageManager;
@@ -601,7 +591,7 @@
if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
- mPackageManager, allAgentApps());
+ mPackageManager, allAgentPackages());
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
processOneBackup(pmRequest,
@@ -614,10 +604,12 @@
// Finally, tear down the transport
try {
- mTransport.endSession();
- } catch (Exception e) {
- Log.e(TAG, "Error ending transport");
- e.printStackTrace();
+ if (!mTransport.finishBackup()) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in finishBackup()");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in finishBackup()", e);
}
if (!mJournal.delete()) {
@@ -712,24 +704,18 @@
if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
backupData =
ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
- int error = transport.performBackup(packInfo, backupData);
+ if (!transport.performBackup(packInfo, backupData)) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in performBackup()");
+ }
// !!! TODO: After successful transport, delete the now-stale data
// and juggle the files so that next time the new state is passed
//backupDataName.delete();
newStateName.renameTo(savedStateName);
}
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Package not found on backup: " + packageName);
- } catch (FileNotFoundException fnf) {
- Log.w(TAG, "File not found on backup: ");
- fnf.printStackTrace();
- } catch (RemoteException e) {
- Log.d(TAG, "Remote target " + request.appInfo.packageName + " threw during backup:");
- e.printStackTrace();
} catch (Exception e) {
- Log.w(TAG, "Final exception guard in backup: ");
- e.printStackTrace();
+ Log.e(TAG, "Error backing up " + packageName, e);
}
}
}
@@ -737,25 +723,6 @@
// ----- Restore handling -----
- // Is the given package restorable on this device? Returns the on-device app's
- // ApplicationInfo struct if it is; null if not.
- //
- // !!! TODO: also consider signatures
- PackageInfo isRestorable(PackageInfo packageInfo) {
- if (packageInfo.packageName != null) {
- try {
- PackageInfo app = mPackageManager.getPackageInfo(packageInfo.packageName,
- PackageManager.GET_SIGNATURES);
- if ((app.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
- return app;
- }
- } catch (Exception e) {
- // doesn't exist on this device, or other error -- just ignore it.
- }
- }
- return null;
- }
-
private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
// Allow unsigned apps, but not signed on one device and unsigned on the other
// !!! TODO: is this the right policy?
@@ -816,130 +783,141 @@
/**
* Restore sequence:
*
- * 1. start up the transport session
- * 2. get the restore set description for our identity
- * 3. for each app in the restore set:
+ * 1. get the restore set description for our identity
+ * 2. for each app in the restore set:
* 3.a. if it's restorable on this device, add it to the restore queue
- * 4. for each app in the restore queue:
- * 4.a. clear the app data
- * 4.b. get the restore data for the app from the transport
- * 4.c. launch the backup agent for the app
- * 4.d. agent.doRestore() with the data from the server
- * 4.e. unbind the agent [and kill the app?]
- * 5. shut down the transport
+ * 3. for each app in the restore queue:
+ * 3.a. clear the app data
+ * 3.b. get the restore data for the app from the transport
+ * 3.c. launch the backup agent for the app
+ * 3.d. agent.doRestore() with the data from the server
+ * 3.e. unbind the agent [and kill the app?]
+ * 4. shut down the transport
*/
- int err = -1;
+ // build the set of apps to restore
try {
- err = mTransport.startSession();
- } catch (Exception e) {
- Log.e(TAG, "Error starting transport for restore");
- e.printStackTrace();
- }
+ RestoreSet[] images = mTransport.getAvailableRestoreSets();
+ if (images == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting restore sets");
+ return;
+ }
- if (err == 0) {
- // build the set of apps to restore
- try {
- RestoreSet[] images = mTransport.getAvailableRestoreSets();
- if (images.length > 0) {
- // !!! TODO: pick out the set for this token
- mImage = images[0];
+ if (images.length == 0) {
+ Log.i(TAG, "No restore sets available");
+ return;
+ }
- // Pull the Package Manager metadata from the restore set first
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
- mPackageManager, allAgentApps());
- PackageInfo pmApp = new PackageInfo();
- pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
- // !!! TODO: version currently ignored when 'restoring' the PM metadata
- processOneRestore(pmApp, 0,
- IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+ mImage = images[0];
- // build the set of apps we will attempt to restore
- PackageInfo[] packages = mTransport.getAppSet(mImage.token);
- HashSet<RestoreRequest> appsToRestore = new HashSet<RestoreRequest>();
- for (PackageInfo pkg: packages) {
- // get the real PackageManager idea of the package
- PackageInfo app = isRestorable(pkg);
- if (app != null) {
- // Validate against the backed-up signature block, too
- Metadata info = pmAgent.getRestoredMetadata(app.packageName);
- if (info != null) {
- if (app.versionCode >= info.versionCode) {
- if (DEBUG) Log.v(TAG, "Restore version "
- + info.versionCode
- + " compatible with app version "
- + app.versionCode);
- if (signaturesMatch(info.signatures, app.signatures)) {
- appsToRestore.add(
- new RestoreRequest(app, info.versionCode));
- } else {
- Log.w(TAG, "Sig mismatch restoring "
- + app.packageName);
- }
- } else {
- Log.i(TAG, "Restore set for " + app.packageName
- + " is too new [" + info.versionCode
- + "] for installed app version "
- + app.versionCode);
- }
- } else {
- Log.d(TAG, "Unable to get metadata for "
- + app.packageName);
- }
- }
- }
+ // Get the list of all packages which have backup enabled.
+ // (Include the Package Manager metadata pseudo-package first.)
+ ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
+ PackageInfo omPackage = new PackageInfo();
+ omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
+ restorePackages.add(omPackage);
- // now run the restore queue
- doQueuedRestores(appsToRestore);
+ List<PackageInfo> agentPackages = allAgentPackages();
+ restorePackages.addAll(agentPackages);
+
+ // STOPSHIP TODO: pick out the set for this token (instead of images[0])
+ long token = images[0].token;
+ if (!mTransport.startRestore(token, restorePackages.toArray(new PackageInfo[0]))) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error starting restore operation");
+ return;
+ }
+
+ String packageName = mTransport.nextRestorePackage();
+ if (packageName == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting first restore package");
+ return;
+ } else if (packageName.equals("")) {
+ Log.i(TAG, "No restore data available");
+ return;
+ } else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
+ + "\", found only \"" + packageName + "\"");
+ return;
+ }
+
+ // Pull the Package Manager metadata from the restore set first
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, agentPackages);
+ processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+
+ for (;;) {
+ packageName = mTransport.nextRestorePackage();
+ if (packageName == null) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error getting next restore package");
+ return;
+ } else if (packageName.equals("")) {
+ break;
}
- } catch (RemoteException e) {
- // can't happen; transports run locally
- }
- // done; shut down the transport
- try {
- mTransport.endSession();
- } catch (Exception e) {
- Log.e(TAG, "Error ending transport for restore");
- e.printStackTrace();
- }
- }
+ Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
+ if (metaInfo == null) {
+ Log.e(TAG, "Missing metadata for " + packageName);
+ continue;
+ }
- // even if the initial session startup failed, report that we're done here
- }
+ int flags = PackageManager.GET_SIGNATURES;
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+ if (metaInfo.versionCode > packageInfo.versionCode) {
+ Log.w(TAG, "Package " + packageName
+ + " restore version [" + metaInfo.versionCode
+ + "] is too new for installed version ["
+ + packageInfo.versionCode + "]");
+ continue;
+ }
- // restore each app in the queue
- void doQueuedRestores(HashSet<RestoreRequest> appsToRestore) {
- for (RestoreRequest req : appsToRestore) {
- PackageInfo app = req.app;
- Log.d(TAG, "starting agent for restore of " + app);
+ if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
+ Log.w(TAG, "Signature mismatch restoring " + packageName);
+ continue;
+ }
- try {
- // Remove the app's data first
- clearApplicationDataSynchronous(app.packageName);
+ if (DEBUG) Log.v(TAG, "Package " + packageName
+ + " restore version [" + metaInfo.versionCode
+ + "] is compatible with installed version ["
+ + packageInfo.versionCode + "]");
- // Now perform the restore into the clean app
- IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo,
+ // Now perform the actual restore
+ clearApplicationDataSynchronous(packageName);
+ IBackupAgent agent = bindToAgentSynchronous(
+ packageInfo.applicationInfo,
IApplicationThread.BACKUP_MODE_RESTORE);
- if (agent != null) {
- processOneRestore(app, req.storedAppVersion, agent);
+ if (agent == null) {
+ Log.w(TAG, "Can't find backup agent for " + packageName);
+ continue;
}
- // unbind even on timeout, just in case
- mActivityManager.unbindBackupAgent(app.applicationInfo);
- } catch (SecurityException ex) {
- // Try for the next one.
- Log.d(TAG, "error in bind", ex);
- } catch (RemoteException e) {
- // can't happen
+ try {
+ processOneRestore(packageInfo, metaInfo.versionCode, agent);
+ } finally {
+ // unbind even on timeout or failure, just in case
+ mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
+ }
}
-
+ } catch (NameNotFoundException e) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Invalid paackage restoring data", e);
+ } catch (RemoteException e) {
+ // STOPSHIP TODO: Handle the failure somehow?
+ Log.e(TAG, "Error restoring data", e);
+ } finally {
+ try {
+ mTransport.finishRestore();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error finishing restore", e);
+ }
}
}
- // Do the guts of a restore of one application, derived from the 'mImage'
- // restore set via the 'mTransport' transport.
- void processOneRestore(PackageInfo app, int storedAppVersion, IBackupAgent agent) {
+ // Do the guts of a restore of one application, using mTransport.getRestoreData().
+ void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent) {
// !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName;
@@ -954,11 +932,12 @@
// Run the transport's restore pass
// Run the target's backup pass
- int err = -1;
try {
- err = mTransport.getRestoreData(mImage.token, app, backupData);
- } catch (RemoteException e) {
- // can't happen
+ if (!mTransport.getRestoreData(backupData)) {
+ // STOPSHIP TODO: Handle this error somehow?
+ Log.e(TAG, "Error getting restore data for " + packageName);
+ return;
+ }
} finally {
backupData.close();
}
@@ -973,30 +952,18 @@
backupData = ParcelFileDescriptor.open(backupDataName,
ParcelFileDescriptor.MODE_READ_ONLY);
- boolean success = false;
try {
- agent.doRestore(backupData, storedAppVersion, newState);
- success = true;
- } catch (Exception e) {
- Log.e(TAG, "Restore failed for " + packageName);
- e.printStackTrace();
+ agent.doRestore(backupData, appVersionCode, newState);
} finally {
newState.close();
backupData.close();
}
// if everything went okay, remember the recorded state now
- if (success) {
- File savedStateName = new File(mStateDir, packageName);
- newStateName.renameTo(savedStateName);
- }
- } catch (FileNotFoundException fnfe) {
- Log.v(TAG, "Couldn't open file for restore: " + fnfe);
- } catch (IOException ioe) {
- Log.e(TAG, "Unable to process restore file: " + ioe);
+ File savedStateName = new File(mStateDir, packageName);
+ newStateName.renameTo(savedStateName);
} catch (Exception e) {
- Log.e(TAG, "Final exception guard in restore:");
- e.printStackTrace();
+ Log.e(TAG, "Error restoring data for " + packageName, e);
}
}
}
@@ -1206,7 +1173,7 @@
mContext.enforceCallingPermission("android.permission.BACKUP",
"endRestoreSession");
- mRestoreTransport.endSession();
+ mRestoreTransport.finishRestore();
mRestoreTransport = null;
synchronized(BackupManagerService.this) {
if (BackupManagerService.this.mActiveRestoreSession == this) {
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index d620eb1..66fb86d 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -57,7 +57,7 @@
// is stored using the package name as a key)
private static final String GLOBAL_METADATA_KEY = "@meta@";
- private List<ApplicationInfo> mAllApps;
+ private List<PackageInfo> mAllPackages;
private PackageManager mPackageManager;
private HashMap<String, Metadata> mRestoredSignatures;
@@ -73,9 +73,9 @@
// We're constructed with the set of applications that are participating
// in backup. This set changes as apps are installed & removed.
- PackageManagerBackupAgent(PackageManager packageMgr, List<ApplicationInfo> apps) {
+ PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
mPackageManager = packageMgr;
- mAllApps = apps;
+ mAllPackages = packages;
mRestoredSignatures = null;
}
@@ -118,8 +118,8 @@
// For each app we have on device, see if we've backed it up yet. If not,
// write its signature block to the output, keyed on the package name.
- for (ApplicationInfo app : mAllApps) {
- String packName = app.packageName;
+ for (PackageInfo pkg : mAllPackages) {
+ String packName = pkg.packageName;
if (!existing.contains(packName)) {
// We haven't stored this app's signatures yet, so we do that now
try {
@@ -186,7 +186,7 @@
}
// Finally, write the new state blob -- just the list of all apps we handled
- writeStateFile(mAllApps, newState);
+ writeStateFile(mAllPackages, newState);
}
// "Restore" here is a misnomer. What we're really doing is reading back the
@@ -327,7 +327,7 @@
}
// Util: write out our new backup state file
- private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) {
+ private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
DataOutputStream out = new DataOutputStream(outstream);
@@ -338,8 +338,8 @@
out.write(metaNameBuf);
// now write all the app names too
- for (ApplicationInfo app : apps) {
- byte[] pkgNameBuf = app.packageName.getBytes();
+ for (PackageInfo pkg : pkgs) {
+ byte[] pkgNameBuf = pkg.packageName.getBytes();
out.writeInt(pkgNameBuf.length);
out.write(pkgNameBuf);
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 048669a..972aa98 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -968,35 +968,7 @@
if (Config.LOGV) Log.v(TAG, "getActivityInfo " + component + ": " + a);
if (a != null && mSettings.isEnabledLP(a.info, flags)) {
- ActivityInfo ainfo = PackageParser.generateActivityInfo(a, flags);
- if (ainfo != null) {
- ApplicationInfo appInfo = getApplicationInfo(component.getPackageName(),
- PackageManager.GET_SUPPORTS_DENSITIES);
- if (appInfo != null &&
- (appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) == 0) {
- // Check if the screen size is same as what the application expect.
- CompatibilityInfo info = new CompatibilityInfo(appInfo);
- DisplayMetrics metrics = new DisplayMetrics();
- metrics.setTo(mMetrics);
- int orientation = mMetrics.widthPixels > mMetrics.heightPixels ?
- Configuration.ORIENTATION_LANDSCAPE :
- Configuration.ORIENTATION_PORTRAIT;
- metrics.updateMetrics(info, orientation);
- if (!info.mExpandable) {
- // Don't allow an app that cannot expand to handle rotation.
- ainfo.configChanges &= ~ ActivityInfo.CONFIG_ORIENTATION;
- } else {
- appInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS;
- }
- if (DEBUG_SETTINGS) {
- Log.d(TAG, "component=" + component +
- ", expandable:" +
- ((appInfo.flags &
- ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0));
- }
- }
- }
- return ainfo;
+ return PackageParser.generateActivityInfo(a, flags);
}
if (mResolveComponentName.equals(component)) {
return mResolveActivity;
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index b601ece..9f2856c 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -462,6 +462,15 @@
//
private void broadcastServiceStateChanged(ServiceState state) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mBatteryStats.noteAirplaneMode(state.getState() == ServiceState.STATE_POWER_OFF);
+ } catch (RemoteException re) {
+ // Can't do much
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
diff --git a/services/java/com/android/server/WallpaperService.java b/services/java/com/android/server/WallpaperService.java
index 5532894..d921baf 100644
--- a/services/java/com/android/server/WallpaperService.java
+++ b/services/java/com/android/server/WallpaperService.java
@@ -18,8 +18,10 @@
import static android.os.FileObserver.*;
import static android.os.ParcelFileDescriptor.*;
+
import android.app.IWallpaperService;
import android.app.IWallpaperServiceCallback;
+import android.backup.BackupManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -154,7 +156,16 @@
public ParcelFileDescriptor setWallpaper() {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
try {
- return ParcelFileDescriptor.open(WALLPAPER_FILE, MODE_CREATE|MODE_READ_WRITE);
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+ MODE_CREATE|MODE_READ_WRITE);
+
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
+ return fd;
} catch (FileNotFoundException e) {
if (Config.LOGD) Log.d(TAG, "Error setting wallpaper", e);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 16bb29d..0d9d2b0 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -61,6 +61,7 @@
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -1517,7 +1518,9 @@
}
}
- synchronized(mBatteryStatsService.getActiveStatistics()) {
+ final BatteryStatsImpl bstats =
+ (BatteryStatsImpl) mBatteryStatsService.getActiveStatistics();
+ synchronized(bstats) {
synchronized(mPidsSelfLocked) {
if (haveNewCpuStats) {
if (mBatteryStatsService.isOnBattery()) {
@@ -1529,12 +1532,18 @@
if (pr != null) {
BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+ } else {
+ BatteryStatsImpl.Uid.Proc ps =
+ bstats.getProcessStatsLocked(st.name);
+ if (ps != null) {
+ ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+ }
}
}
}
}
}
-
+
if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
mLastWriteTime = now;
mBatteryStatsService.getActiveStatistics().writeLocked();
@@ -12592,51 +12601,63 @@
}
public boolean profileControl(String process, boolean start,
- String path) throws RemoteException {
+ String path, ParcelFileDescriptor fd) throws RemoteException {
- synchronized (this) {
- // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
- // its own permission.
- if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires permission "
- + android.Manifest.permission.SET_ACTIVITY_WATCHER);
- }
-
- ProcessRecord proc = null;
- try {
- int pid = Integer.parseInt(process);
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(pid);
+ try {
+ synchronized (this) {
+ // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+ // its own permission.
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
}
- } catch (NumberFormatException e) {
- }
-
- if (proc == null) {
- HashMap<String, SparseArray<ProcessRecord>> all
- = mProcessNames.getMap();
- SparseArray<ProcessRecord> procs = all.get(process);
- if (procs != null && procs.size() > 0) {
- proc = procs.valueAt(0);
+
+ if (start && fd == null) {
+ throw new IllegalArgumentException("null fd");
}
- }
-
- if (proc == null || proc.thread == null) {
- throw new IllegalArgumentException("Unknown process: " + process);
- }
-
- boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
- if (isSecure) {
- if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
- throw new SecurityException("Process not debuggable: " + proc);
+
+ ProcessRecord proc = null;
+ try {
+ int pid = Integer.parseInt(process);
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ } catch (NumberFormatException e) {
}
- }
+
+ if (proc == null) {
+ HashMap<String, SparseArray<ProcessRecord>> all
+ = mProcessNames.getMap();
+ SparseArray<ProcessRecord> procs = all.get(process);
+ if (procs != null && procs.size() > 0) {
+ proc = procs.valueAt(0);
+ }
+ }
+
+ if (proc == null || proc.thread == null) {
+ throw new IllegalArgumentException("Unknown process: " + process);
+ }
+
+ boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
+ if (isSecure) {
+ if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + proc);
+ }
+ }
- try {
- proc.thread.profilerControl(start, path);
+ proc.thread.profilerControl(start, path, fd);
+ fd = null;
return true;
- } catch (RemoteException e) {
- throw new IllegalStateException("Process disappeared");
+ }
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Process disappeared");
+ } finally {
+ if (fd != null) {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ }
}
}
}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 9a4b642..39a1ee0 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -16,9 +16,6 @@
package com.android.server.am;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.os.BatteryStatsImpl;
-
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
@@ -26,8 +23,12 @@
import android.os.Process;
import android.os.ServiceManager;
import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
import android.util.Log;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsImpl;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -191,7 +192,14 @@
mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
}
}
-
+
+ public void noteAirplaneMode(boolean airplaneMode) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteAirplaneModeLocked(airplaneMode);
+ }
+ }
+
public void noteWifiOn(int uid) {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index 1dedd04..aec2164 100755
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -5,6 +5,7 @@
#include <vector>
#include <set>
#include <stdarg.h>
+#include <stdio.h>
using namespace std;
diff --git a/tools/localize/Perforce.cpp b/tools/localize/Perforce.cpp
index 3425668..1c644ed 100644
--- a/tools/localize/Perforce.cpp
+++ b/tools/localize/Perforce.cpp
@@ -1,6 +1,7 @@
#include "Perforce.h"
#include "log.h"
#include <string.h>
+#include <cstdio>
#include <stdlib.h>
#include <sstream>
#include <sys/types.h>
diff --git a/tools/localize/SourcePos.cpp b/tools/localize/SourcePos.cpp
index 9d7c5c6..2533f0a 100644
--- a/tools/localize/SourcePos.cpp
+++ b/tools/localize/SourcePos.cpp
@@ -1,6 +1,7 @@
#include "SourcePos.h"
#include <stdarg.h>
+#include <cstdio>
#include <set>
using namespace std;
diff --git a/tools/localize/Values.cpp b/tools/localize/Values.cpp
index e396f8b..8623b97 100644
--- a/tools/localize/Values.cpp
+++ b/tools/localize/Values.cpp
@@ -1,5 +1,6 @@
#include "Values.h"
#include <stdlib.h>
+#include <cstdio>
// =====================================================================================
diff --git a/tools/localize/XLIFFFile.cpp b/tools/localize/XLIFFFile.cpp
index 51f81de..4e217d9 100644
--- a/tools/localize/XLIFFFile.cpp
+++ b/tools/localize/XLIFFFile.cpp
@@ -3,6 +3,7 @@
#include <algorithm>
#include <sys/time.h>
#include <time.h>
+#include <cstdio>
const char* const XLIFF_XMLNS = "urn:oasis:names:tc:xliff:document:1.2";
diff --git a/tools/localize/file_utils.cpp b/tools/localize/file_utils.cpp
index 8792b9e..293e50e 100644
--- a/tools/localize/file_utils.cpp
+++ b/tools/localize/file_utils.cpp
@@ -1,4 +1,5 @@
#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "file_utils.h"
diff --git a/tools/localize/localize_test.cpp b/tools/localize/localize_test.cpp
index 63d904c..678cad8 100644
--- a/tools/localize/localize_test.cpp
+++ b/tools/localize/localize_test.cpp
@@ -1,6 +1,7 @@
#include "XLIFFFile.h"
#include "ValuesFile.h"
#include "localize.h"
+#include <stdio.h>
int pseudolocalize_xliff(XLIFFFile* xliff, bool expand);
diff --git a/tools/localize/merge_res_and_xliff.cpp b/tools/localize/merge_res_and_xliff.cpp
index 58a6554..1fdaa0e 100644
--- a/tools/localize/merge_res_and_xliff.cpp
+++ b/tools/localize/merge_res_and_xliff.cpp
@@ -3,6 +3,7 @@
#include "file_utils.h"
#include "Perforce.h"
#include "log.h"
+#include <stdio.h>
static set<StringResource>::const_iterator
find_id(const set<StringResource>& s, const string& id, int index)
diff --git a/tools/localize/merge_res_and_xliff_test.cpp b/tools/localize/merge_res_and_xliff_test.cpp
index 5a2b0f4..e4ab562 100644
--- a/tools/localize/merge_res_and_xliff_test.cpp
+++ b/tools/localize/merge_res_and_xliff_test.cpp
@@ -1,5 +1,5 @@
#include "merge_res_and_xliff.h"
-
+#include <stdio.h>
int
merge_test()
diff --git a/tools/localize/xmb.cpp b/tools/localize/xmb.cpp
index 236705f..d8f6ff0 100644
--- a/tools/localize/xmb.cpp
+++ b/tools/localize/xmb.cpp
@@ -7,6 +7,7 @@
#include "XLIFFFile.h"
#include <map>
+#include <cstdio>
using namespace std;