diff options
48 files changed, 1289 insertions, 757 deletions
@@ -108,7 +108,6 @@ LOCAL_SRC_FILES += \ core/java/android/hardware/ISensorService.aidl \ core/java/android/net/IConnectivityManager.aidl \ core/java/android/os/ICheckinService.aidl \ - core/java/android/os/IDropBox.aidl \ core/java/android/os/IHardwareService.aidl \ core/java/android/os/IMessenger.aidl \ core/java/android/os/IMountService.aidl \ @@ -137,6 +136,7 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/appwidget/IAppWidgetService.aidl \ core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \ core/java/com/android/internal/backup/IBackupTransport.aidl \ + core/java/com/android/internal/os/IDropBoxService.aidl \ core/java/com/android/internal/os/IResultReceiver.aidl \ core/java/com/android/internal/view/IInputContext.aidl \ core/java/com/android/internal/view/IInputContextCallback.aidl \ @@ -217,7 +217,7 @@ aidl_files := \ frameworks/base/core/java/android/appwidget/AppWidgetProviderInfo.aidl \ frameworks/base/core/java/android/net/Uri.aidl \ frameworks/base/core/java/android/os/Bundle.aidl \ - frameworks/base/core/java/android/os/DropBoxEntry.aidl \ + frameworks/base/core/java/android/os/DropBox.aidl \ frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \ frameworks/base/core/java/android/os/ParcelUuid.aidl \ frameworks/base/core/java/android/view/KeyEvent.aidl \ @@ -491,6 +491,8 @@ LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk include $(BUILD_DROIDDOC) +# explicitly specify that online-sdk depends on framework-res. +$(full_target): framework-res-package-target # ==== docs that have all of the stuff that's @hidden ======================= include $(CLEAR_VARS) diff --git a/api/current.xml b/api/current.xml index 4cd9718..6ba1199 100644 --- a/api/current.xml +++ b/api/current.xml @@ -99410,6 +99410,17 @@ visibility="public" > </field> +<field name="ECLAIR_MR1" + type="int" + transient="false" + volatile="false" + value="6" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="Bundle" extends="java.lang.Object" diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index f48f150..305ee6a 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -70,6 +70,7 @@ import android.net.wifi.IWifiManager; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Bundle; +import android.os.DropBox; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; @@ -93,6 +94,8 @@ import android.view.inputmethod.InputMethodManager; import android.accounts.AccountManager; import android.accounts.IAccountManager; +import com.android.internal.os.IDropBoxService; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -182,6 +185,7 @@ class ApplicationContext extends Context { private ClipboardManager mClipboardManager = null; private boolean mRestricted; private AccountManager mAccountManager; // protected by mSync + private DropBox mDropBox = null; private final Object mSync = new Object(); @@ -896,6 +900,8 @@ class ApplicationContext extends Context { return getClipboardManager(); } else if (WALLPAPER_SERVICE.equals(name)) { return getWallpaperManager(); + } else if (DROPBOX_SERVICE.equals(name)) { + return getDropBox(); } return null; @@ -1045,7 +1051,7 @@ class ApplicationContext extends Context { } return mVibrator; } - + private AudioManager getAudioManager() { if (mAudioManager == null) { @@ -1054,6 +1060,17 @@ class ApplicationContext extends Context { return mAudioManager; } + private DropBox getDropBox() { + synchronized (mSync) { + if (mDropBox == null) { + IBinder b = ServiceManager.getService(DROPBOX_SERVICE); + IDropBoxService service = IDropBoxService.Stub.asInterface(b); + mDropBox = new DropBox(service); + } + } + return mDropBox; + } + @Override public int checkPermission(String permission, int pid, int uid) { if (permission == null) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 8f1c671..b4ab408 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1309,7 +1309,7 @@ public abstract class Context { * @see #getSystemService */ public static final String APPWIDGET_SERVICE = "appwidget"; - + /** * Use with {@link #getSystemService} to retrieve an * {@blink android.backup.IBackupManager IBackupManager} for communicating @@ -1319,7 +1319,16 @@ public abstract class Context { * @see #getSystemService */ public static final String BACKUP_SERVICE = "backup"; - + + /** + * Use with {@link #getSystemService} to retrieve a + * {@blink android.os.DropBox DropBox} instance for recording + * diagnostic logs. + * @hide + * @see #getSystemService + */ + public static final String DROPBOX_SERVICE = "dropbox"; + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 0f8bc08..d4aaba3 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -103,16 +103,19 @@ public class Build { * October 2008: The original, first, version of Android. Yay! */ public static final int BASE = 1; + /** * February 2009: First Android update, officially called 1.1. */ public static final int BASE_1_1 = 2; + /** * May 2009: Android 1.5. */ public static final int CUPCAKE = 3; + /** - * Current work on "Donut" development branch. + * September 2009: Android 1.6. * * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> @@ -133,8 +136,9 @@ public class Build { * </ul> */ public static final int DONUT = 4; + /** - * Current work on "Eclair" development branch. + * November 2009: Android 2.0 * * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> @@ -152,6 +156,11 @@ public class Build { * </ul> */ public static final int ECLAIR = 5; + + /** + * Current work on Eclair MR1. + */ + public static final int ECLAIR_MR1 = 6; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/DropBoxEntry.aidl b/core/java/android/os/DropBox.aidl index 225eee1..77abd22 100644 --- a/core/java/android/os/DropBoxEntry.aidl +++ b/core/java/android/os/DropBox.aidl @@ -16,4 +16,4 @@ package android.os; -parcelable DropBoxEntry; +parcelable DropBox.Entry; diff --git a/core/java/android/os/DropBox.java b/core/java/android/os/DropBox.java new file mode 100644 index 0000000..0551dc1 --- /dev/null +++ b/core/java/android/os/DropBox.java @@ -0,0 +1,276 @@ +/* + * 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.os; + +import android.util.Log; + +import com.android.internal.os.IDropBoxService; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.GZIPInputStream; + +/** + * Enqueues chunks of data (from various sources -- application crashes, kernel + * log records, etc.). The queue is size bounded and will drop old data if the + * enqueued data exceeds the maximum size. You can think of this as a + * persistent, system-wide, blob-oriented "logcat". + * + * <p>You can obtain an instance of this class by calling + * {@link android.content.Context#getSystemService} + * with {@link android.content.Context#DROPBOX_SERVICE}. + * + * <p>DropBox entries are not sent anywhere directly, but other system services + * and debugging tools may scan and upload entries for processing. + * + * {@pending} + */ +public class DropBox { + private static final String TAG = "DropBox"; + private final IDropBoxService mService; + + /** Flag value: Entry's content was deleted to save space. */ + public static final int IS_EMPTY = 1; + + /** Flag value: Content is human-readable UTF-8 text (can be combined with IS_GZIPPED). */ + public static final int IS_TEXT = 2; + + /** Flag value: Content can be decompressed with {@link GZIPOutputStream}. */ + public static final int IS_GZIPPED = 4; + + /** + * A single entry retrieved from the drop box. + * This may include a reference to a stream, so you must call + * {@link #close()} when you are done using it. + */ + public static class Entry implements Parcelable { + private final String mTag; + private final long mTimeMillis; + + private final byte[] mData; + private final ParcelFileDescriptor mFileDescriptor; + private final int mFlags; + + /** Create a new empty Entry with no contents. */ + public Entry(String tag, long millis) { + this(tag, millis, (Object) null, IS_EMPTY); + } + + /** Create a new Entry with plain text contents. */ + public Entry(String tag, long millis, String text) { + this(tag, millis, (Object) text.getBytes(), IS_TEXT); + } + + /** + * Create a new Entry with byte array contents. + * The data array must not be modified after creating this entry. + */ + public Entry(String tag, long millis, byte[] data, int flags) { + this(tag, millis, (Object) data, flags); + } + + /** + * Create a new Entry with streaming data contents. + * Takes ownership of the ParcelFileDescriptor. + */ + public Entry(String tag, long millis, ParcelFileDescriptor data, int flags) { + this(tag, millis, (Object) data, flags); + } + + /** + * Create a new Entry with the contents read from a file. + * The file will be read when the entry's contents are requested. + */ + public Entry(String tag, long millis, File data, int flags) throws IOException { + this(tag, millis, (Object) ParcelFileDescriptor.open( + data, ParcelFileDescriptor.MODE_READ_ONLY), flags); + } + + /** Internal constructor for CREATOR.createFromParcel(). */ + private Entry(String tag, long millis, Object value, int flags) { + if (tag == null) throw new NullPointerException(); + if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException(); + + mTag = tag; + mTimeMillis = millis; + mFlags = flags; + + if (value == null) { + mData = null; + mFileDescriptor = null; + } else if (value instanceof byte[]) { + mData = (byte[]) value; + mFileDescriptor = null; + } else if (value instanceof ParcelFileDescriptor) { + mData = null; + mFileDescriptor = (ParcelFileDescriptor) value; + } else { + throw new IllegalArgumentException(); + } + } + + /** Close the input stream associated with this entry. */ + public void close() { + try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { } + } + + /** @return the tag originally attached to the entry. */ + public String getTag() { return mTag; } + + /** @return time when the entry was originally created. */ + public long getTimeMillis() { return mTimeMillis; } + + /** @return flags describing the content returned by @{link #getInputStream()}. */ + public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses. + + /** + * @param maxBytes of string to return (will truncate at this length). + * @return the uncompressed text contents of the entry, null if the entry is not text. + */ + public String getText(int maxBytes) { + if ((mFlags & IS_TEXT) == 0) return null; + if (mData != null) return new String(mData, 0, Math.min(maxBytes, mData.length)); + + InputStream is = null; + try { + is = getInputStream(); + byte[] buf = new byte[maxBytes]; + return new String(buf, 0, Math.max(0, is.read(buf))); + } catch (IOException e) { + return null; + } finally { + try { if (is != null) is.close(); } catch (IOException e) {} + } + } + + /** @return the uncompressed contents of the entry, or null if the contents were lost */ + public InputStream getInputStream() throws IOException { + InputStream is; + if (mData != null) { + is = new ByteArrayInputStream(mData); + } else if (mFileDescriptor != null) { + is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor); + } else { + return null; + } + return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is; + } + + public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator() { + public Entry[] newArray(int size) { return new Entry[size]; } + public Entry createFromParcel(Parcel in) { + return new Entry( + in.readString(), in.readLong(), in.readValue(null), in.readInt()); + } + }; + + public int describeContents() { + return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; + } + + public void writeToParcel(Parcel out, int flags) { + out.writeString(mTag); + out.writeLong(mTimeMillis); + if (mFileDescriptor != null) { + out.writeValue(mFileDescriptor); + } else { + out.writeValue(mData); + } + out.writeInt(mFlags); + } + } + + /** {@hide} */ + public DropBox(IDropBoxService service) { mService = service; } + + /** + * Create a dummy instance for testing. All methods will fail unless + * overridden with an appropriate mock implementation. To obtain a + * functional instance, use {@link android.content.Context#getSystemService}. + */ + protected DropBox() { mService = null; } + + /** + * Stores human-readable text. The data may be discarded eventually (or even + * immediately) if space is limited, or ignored entirely if the tag has been + * blocked (see {@link #isTagEnabled}). + * + * @param tag describing the type of entry being stored + * @param data value to store + */ + public void addText(String tag, String data) { + try { mService.add(new Entry(tag, 0, data)); } catch (RemoteException e) {} + } + + /** + * Stores binary data, which may be ignored or discarded as with {@link #addText}. + * + * @param tag describing the type of entry being stored + * @param data value to store + * @param flags describing the data + */ + public void addData(String tag, byte[] data, int flags) { + if (data == null) throw new NullPointerException(); + try { mService.add(new Entry(tag, 0, data, flags)); } catch (RemoteException e) {} + } + + /** + * Stores data read from a file descriptor. The data may be ignored or + * discarded as with {@link #addText}. You must close your + * ParcelFileDescriptor object after calling this method! + * + * @param tag describing the type of entry being stored + * @param fd file descriptor to read from + * @param flags describing the data + */ + public void addFile(String tag, ParcelFileDescriptor fd, int flags) { + if (fd == null) throw new NullPointerException(); + try { mService.add(new Entry(tag, 0, fd, flags)); } catch (RemoteException e) {} + } + + /** + * Checks any blacklists (set in system settings) to see whether a certain + * tag is allowed. Entries with disabled tags will be dropped immediately, + * so you can save the work of actually constructing and sending the data. + * + * @param tag that would be used in {@link #addText} or {@link #addFile} + * @return whether events with that tag would be accepted + */ + public boolean isTagEnabled(String tag) { + try { return mService.isTagEnabled(tag); } catch (RemoteException e) { return false; } + } + + /** + * Gets the next entry from the drop box *after* the specified time. + * Requires android.permission.READ_LOGS. You must always call + * {@link Entry#close()} on the return value! + * + * @param tag of entry to look for, null for all tags + * @param msec time of the last entry seen + * @return the next entry, or null if there are no more entries + */ + public Entry getNextEntry(String tag, long msec) { + try { return mService.getNextEntry(tag, msec); } catch (RemoteException e) { return null; } + } + + // TODO: It may be useful to have some sort of notification mechanism + // when data is added to the dropbox, for demand-driven readers -- + // for now readers need to poll the dropbox to find new data. +} diff --git a/core/java/android/os/DropBoxEntry.java b/core/java/android/os/DropBoxEntry.java deleted file mode 100644 index e3816a8..0000000 --- a/core/java/android/os/DropBoxEntry.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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.os; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.util.zip.GZIPInputStream; - -/** - * A single entry retrieved from an {@link IDropBox} implementation. - * This may include a reference to a stream, so you must call - * {@link #close()} when you are done using it. - * - * {@pending} - */ -public class DropBoxEntry implements Parcelable { - private final String mTag; - private final long mTimeMillis; - - private final String mText; - private final ParcelFileDescriptor mFileDescriptor; - private final int mFlags; - - /** Flag value: Entry's content was deleted to save space. */ - public static final int IS_EMPTY = 1; - - /** Flag value: Content is human-readable UTF-8 text (possibly compressed). */ - public static final int IS_TEXT = 2; - - /** Flag value: Content can been decompressed with {@link GZIPOutputStream}. */ - public static final int IS_GZIPPED = 4; - - /** Create a new DropBoxEntry with the specified contents. */ - public DropBoxEntry(String tag, long timeMillis, String text) { - if (tag == null || text == null) throw new NullPointerException(); - mTag = tag; - mTimeMillis = timeMillis; - mText = text; - mFileDescriptor = null; - mFlags = IS_TEXT; - } - - /** Create a new DropBoxEntry with the specified contents. */ - public DropBoxEntry(String tag, long millis, File data, int flags) throws IOException { - if (tag == null) throw new NullPointerException(); - if (((flags & IS_EMPTY) != 0) != (data == null)) throw new IllegalArgumentException(); - - mTag = tag; - mTimeMillis = millis; - mText = null; - mFlags = flags; - mFileDescriptor = data == null ? null : - ParcelFileDescriptor.open(data, ParcelFileDescriptor.MODE_READ_ONLY); - } - - /** Internal constructor for CREATOR.createFromParcel(). */ - private DropBoxEntry(String tag, long millis, Object value, int flags) { - if (tag == null) throw new NullPointerException(); - if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException(); - - mTag = tag; - mTimeMillis = millis; - mFlags = flags; - - if (value == null) { - mText = null; - mFileDescriptor = null; - } else if (value instanceof String) { - if ((flags & IS_TEXT) == 0) throw new IllegalArgumentException(); - mText = (String) value; - mFileDescriptor = null; - } else if (value instanceof ParcelFileDescriptor) { - mText = null; - mFileDescriptor = (ParcelFileDescriptor) value; - } else { - throw new IllegalArgumentException(); - } - } - - /** Close the input stream associated with this entry. */ - public synchronized void close() { - try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { } - } - - /** @return the tag originally attached to the entry. */ - public String getTag() { return mTag; } - - /** @return time when the entry was originally created. */ - public long getTimeMillis() { return mTimeMillis; } - - /** @return flags describing the content returned by @{link #getInputStream()}. */ - public int getFlags() { return mFlags & ~IS_GZIPPED; } // getInputStream() decompresses. - - /** - * @param maxLength of string to return (will truncate at this length). - * @return the uncompressed text contents of the entry, null if the entry is not text. - */ - public String getText(int maxLength) { - if (mText != null) return mText.substring(0, Math.min(maxLength, mText.length())); - if ((mFlags & IS_TEXT) == 0) return null; - - try { - InputStream stream = getInputStream(); - if (stream == null) return null; - char[] buf = new char[maxLength]; - InputStreamReader reader = new InputStreamReader(stream); - return new String(buf, 0, Math.max(0, reader.read(buf))); - } catch (IOException e) { - return null; - } - } - - /** @return the uncompressed contents of the entry, or null if the contents were lost */ - public InputStream getInputStream() throws IOException { - if (mText != null) return new ByteArrayInputStream(mText.getBytes("UTF8")); - if (mFileDescriptor == null) return null; - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor); - return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is; - } - - public static final Parcelable.Creator<DropBoxEntry> CREATOR = new Parcelable.Creator() { - public DropBoxEntry[] newArray(int size) { return new DropBoxEntry[size]; } - public DropBoxEntry createFromParcel(Parcel in) { - return new DropBoxEntry( - in.readString(), in.readLong(), in.readValue(null), in.readInt()); - } - }; - - public int describeContents() { - return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; - } - - public void writeToParcel(Parcel out, int flags) { - out.writeString(mTag); - out.writeLong(mTimeMillis); - if (mFileDescriptor != null) { - out.writeValue(mFileDescriptor); - } else { - out.writeValue(mText); - } - out.writeInt(mFlags); - } -} diff --git a/core/java/android/os/IDropBox.aidl b/core/java/android/os/IDropBox.aidl deleted file mode 100644 index 26294b6..0000000 --- a/core/java/android/os/IDropBox.aidl +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.os; - -import android.os.DropBoxEntry; -import android.os.ParcelFileDescriptor; - -/** - * Enqueues chunks of data (from various sources -- application crashes, kernel - * log records, etc.). The queue is size bounded and will drop old data if the - * enqueued data exceeds the maximum size. - * - * <p>This interface is implemented by a system service you can access: - * - * <pre>IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));</pre> - * - * <p>Other system services and debugging tools may scan the drop box to upload - * entries for processing. - * - * {@pending} - */ -interface IDropBox { - /** - * Stores human-readable text. The data may be discarded eventually (or even - * immediately) if space is limited, or ignored entirely if the tag has been - * blocked (see {@link #isTagEnabled}). - * - * @param tag describing the type of entry being stored - * @param data value to store - */ - void addText(String tag, String data); - - /** - * Stores binary data. The data may be ignored or discarded as with - * {@link #addText}. - * - * @param tag describing the type of entry being stored - * @param data value to store - * @param flags describing the data, defined in {@link DropBoxEntry} - */ - void addData(String tag, in byte[] data, int flags); - - /** - * Stores data read from a file descriptor. The data may be ignored or - * discarded as with {@link #addText}. You must close your - * ParcelFileDescriptor object after calling this method! - * - * @param tag describing the type of entry being stored - * @param data file descriptor to read from - * @param flags describing the data, defined in {@link DropBoxEntry} - */ - void addFile(String tag, in ParcelFileDescriptor data, int flags); - - /** - * Checks any blacklists (set in system settings) to see whether a certain - * tag is allowed. Entries with disabled tags will be dropped immediately, - * so you can save the work of actually constructing and sending the data. - * - * @param tag that would be used in {@link #addText} or {@link #addFile} - * @return whether events with that tag would be accepted - */ - boolean isTagEnabled(String tag); - - /** - * Gets the next entry from the drop box *after* the specified time. - * Requires android.permission.READ_LOGS. You must always call - * {@link DropBoxEntry#close()} on the return value! - * - * @param tag of entry to look for, null for all tags - * @param millis time of the last entry seen - * @return the next entry, or null if there are no more entries - */ - DropBoxEntry getNextEntry(String tag, long millis); - - // TODO: It may be useful to have some sort of notification mechanism - // when data is added to the dropbox, for demand-driven readers -- - // for now readers need to poll the dropbox to find new data. -} diff --git a/core/java/android/pim/vcard/Constants.java b/core/java/android/pim/vcard/Constants.java index a1c7e10..052f329 100644 --- a/core/java/android/pim/vcard/Constants.java +++ b/core/java/android/pim/vcard/Constants.java @@ -72,6 +72,9 @@ package android.pim.vcard; // Phone number for Skype, available as usual phone. public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER"; + // Property for Android-specific fields. + public static final String PROPERTY_X_ANDROID_CUSTOM = "X-ANDROID-CUSTOM"; + // Properties for DoCoMo vCard. public static final String PROPERTY_X_CLASS = "X-CLASS"; public static final String PROPERTY_X_REDUCTION = "X-REDUCTION"; @@ -158,6 +161,9 @@ package android.pim.vcard; public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK"; } + // TODO: Should be in ContactsContract? + /* package */ static final int MAX_DATA_COLUMN = 15; + private Constants() { } }
\ No newline at end of file diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java index eb9c48a..4069729 100644 --- a/core/java/android/pim/vcard/ContactStruct.java +++ b/core/java/android/pim/vcard/ContactStruct.java @@ -442,7 +442,8 @@ public class ContactStruct { private List<ImData> mImList; private List<PhotoData> mPhotoList; private List<String> mWebsiteList; - + private List<List<String>> mAndroidCustomPropertyList; + private final int mVCardType; private final Account mAccount; @@ -479,23 +480,11 @@ public class ContactStruct { } } - final String formattedPhoneNumber; - { - final String rawPhoneNumber = builder.toString(); - if (VCardConfig.isJapaneseDevice(mVCardType)) { - // As of 2009-10-07, there's no formatNumber() which accepts - // the second argument and returns String directly. - final SpannableStringBuilder tmpBuilder = - new SpannableStringBuilder(rawPhoneNumber); - PhoneNumberUtils.formatNumber(tmpBuilder, PhoneNumberUtils.FORMAT_JAPAN); - formattedPhoneNumber = tmpBuilder.toString(); - } else { - // There's no information available on vCard side. Depend on the default - // behavior, which may cause problem in the future when the additional format - // rule is supported (e.g. PhoneNumberUtils.FORMAT_KLINGON) - formattedPhoneNumber = PhoneNumberUtils.formatNumber(rawPhoneNumber); - } - } + // Use NANP in default when there's no information about locale. + final int formattingType = (VCardConfig.isJapaneseDevice(mVCardType) ? + PhoneNumberUtils.FORMAT_JAPAN : PhoneNumberUtils.FORMAT_NANP); + final String formattedPhoneNumber = + PhoneNumberUtils.formatNumber(builder.toString(), formattingType); PhoneData phoneData = new PhoneData(type, formattedPhoneNumber, label, isPrimary); mPhoneList.add(phoneData); } @@ -928,14 +917,19 @@ public class ContactStruct { mWebsiteList = new ArrayList<String>(1); } mWebsiteList.add(propValue); + } else if (propName.equals(Constants.PROPERTY_BDAY)) { + mBirthday = propValue; } else if (propName.equals(Constants.PROPERTY_X_PHONETIC_FIRST_NAME)) { mPhoneticGivenName = propValue; } else if (propName.equals(Constants.PROPERTY_X_PHONETIC_MIDDLE_NAME)) { mPhoneticMiddleName = propValue; } else if (propName.equals(Constants.PROPERTY_X_PHONETIC_LAST_NAME)) { mPhoneticFamilyName = propValue; - } else if (propName.equals(Constants.PROPERTY_BDAY)) { - mBirthday = propValue; + } else if (propName.equals(Constants.PROPERTY_X_ANDROID_CUSTOM)) { + final List<String> customPropertyList = + VCardUtils.constructListFromValue(propValue, + VCardConfig.isV30(mVCardType)); + handleAndroidCustomProperty(customPropertyList); /*} else if (propName.equals("REV")) { // Revision of this VCard entry. I think we can ignore this. } else if (propName.equals("UID")) { @@ -963,6 +957,13 @@ public class ContactStruct { } } + private void handleAndroidCustomProperty(final List<String> customPropertyList) { + if (mAndroidCustomPropertyList == null) { + mAndroidCustomPropertyList = new ArrayList<List<String>>(); + } + mAndroidCustomPropertyList.add(customPropertyList); + } + /** * Construct the display name. The constructed data must not be null. */ @@ -1017,7 +1018,7 @@ public class ContactStruct { mDisplayName = ""; } } - + /** * Consolidate several fielsds (like mName) using name candidates, */ @@ -1028,7 +1029,7 @@ public class ContactStruct { mPhoneticFullName = mPhoneticFullName.trim(); } } - + // From GoogleSource.java in Contacts app. private static final String ACCOUNT_TYPE_GOOGLE = "com.google"; private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts"; @@ -1224,6 +1225,36 @@ public class ContactStruct { operationList.add(builder.build()); } + if (mAndroidCustomPropertyList != null) { + for (List<String> customPropertyList : mAndroidCustomPropertyList) { + int size = customPropertyList.size(); + if (size < 2 || TextUtils.isEmpty(customPropertyList.get(0))) { + continue; + } else if (size > Constants.MAX_DATA_COLUMN + 1) { + size = Constants.MAX_DATA_COLUMN + 1; + customPropertyList = + customPropertyList.subList(0, Constants.MAX_DATA_COLUMN + 2); + } + + int i = 0; + for (final String customPropertyValue : customPropertyList) { + if (i == 0) { + final String mimeType = customPropertyValue; + builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); + builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0); + builder.withValue(Data.MIMETYPE, mimeType); + } else { // 1 <= i && i <= MAX_DATA_COLUMNS + if (!TextUtils.isEmpty(customPropertyValue)) { + builder.withValue("data" + i, customPropertyValue); + } + } + + operationList.add(builder.build()); + i++; + } + } + } + if (myGroupsId != null) { builder = ContentProviderOperation.newInsert(Data.CONTENT_URI); builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0); diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java index 8eabd4b..6476e40 100644 --- a/core/java/android/pim/vcard/VCardComposer.java +++ b/core/java/android/pim/vcard/VCardComposer.java @@ -1019,11 +1019,11 @@ public class VCardComposer { return; } - final String propertyNickname; + final boolean useAndroidProperty; if (mIsV30) { - propertyNickname = Constants.PROPERTY_NICKNAME; - /*} else if (mUsesAndroidProperty) { - propertyNickname = VCARD_PROPERTY_X_NICKNAME;*/ + useAndroidProperty = false; + } else if (mUsesAndroidProperty) { + useAndroidProperty = true; } else { // There's no way to add this field. return; @@ -1034,29 +1034,13 @@ public class VCardComposer { if (TextUtils.isEmpty(nickname)) { continue; } - - final String encodedNickname; - final boolean reallyUseQuotedPrintable = - (mUsesQuotedPrintable && - !VCardUtils.containsOnlyNonCrLfPrintableAscii(nickname)); - if (reallyUseQuotedPrintable) { - encodedNickname = encodeQuotedPrintable(nickname); + if (useAndroidProperty) { + appendAndroidSpecificProperty(builder, Nickname.CONTENT_ITEM_TYPE, + contentValues); } else { - encodedNickname = escapeCharacters(nickname); - } - - builder.append(propertyNickname); - if (shouldAppendCharsetAttribute(propertyNickname)) { - builder.append(VCARD_ATTR_SEPARATOR); - builder.append(mVCardAttributeCharset); - } - if (reallyUseQuotedPrintable) { - builder.append(VCARD_ATTR_SEPARATOR); - builder.append(VCARD_ATTR_ENCODING_QP); + appendVCardLineWithCharsetAndQPDetection(builder, + Constants.PROPERTY_NICKNAME, nickname); } - builder.append(VCARD_DATA_SEPARATOR); - builder.append(encodedNickname); - builder.append(VCARD_COL_SEPARATOR); } } @@ -1491,6 +1475,33 @@ public class VCardComposer { } } + private void appendAndroidSpecificProperty(final StringBuilder builder, + final String mimeType, ContentValues contentValues) { + List<String> rawDataList = new ArrayList<String>(); + rawDataList.add(mimeType); + final List<String> columnNameList; + if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) { + + } else { + // If you add the other field, please check all the columns are able to be + // converted to String. + // + // e.g. BLOB is not what we can handle here now. + return; + } + + for (int i = 1; i <= Constants.MAX_DATA_COLUMN; i++) { + String value = contentValues.getAsString("data" + i); + if (value == null) { + value = ""; + } + rawDataList.add(value); + } + + appendVCardLineWithCharsetAndQPDetection(builder, + Constants.PROPERTY_X_ANDROID_CUSTOM, rawDataList); + } + /** * Append '\' to the characters which should be escaped. The character set is different * not only between vCard 2.1 and vCard 3.0 but also among each device. @@ -1968,6 +1979,8 @@ public class VCardComposer { } } + // appendVCardLine() variants accepting one String. + private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder, final String propertyName, final String rawData) { appendVCardLineWithCharsetAndQPDetection(builder, propertyName, null, rawData); @@ -2026,6 +2039,87 @@ public class VCardComposer { builder.append(VCARD_COL_SEPARATOR); } + // appendVCardLine() variants accepting List<String>. + + private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder, + final String propertyName, final List<String> rawDataList) { + appendVCardLineWithCharsetAndQPDetection(builder, propertyName, null, rawDataList); + } + + private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder, + final String propertyName, + final List<String> attributeList, final List<String> rawDataList) { + boolean needCharset = false; + boolean reallyUseQuotedPrintable = false; + for (String rawData : rawDataList) { + if (!needCharset && mUsesQuotedPrintable && + !VCardUtils.containsOnlyPrintableAscii(rawData)) { + needCharset = true; + } + if (!reallyUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawData)) { + reallyUseQuotedPrintable = true; + } + if (needCharset && reallyUseQuotedPrintable) { + break; + } + } + + appendVCardLine(builder, propertyName, attributeList, + rawDataList, needCharset, reallyUseQuotedPrintable); + } + + /* + private void appendVCardLine(final StringBuilder builder, + final String propertyName, final List<String> rawDataList) { + appendVCardLine(builder, propertyName, rawDataList, false, false); + } + + private void appendVCardLine(final StringBuilder builder, + final String propertyName, final List<String> rawDataList, + final boolean needCharset, boolean needQuotedPrintable) { + appendVCardLine(builder, propertyName, null, rawDataList, needCharset, needQuotedPrintable); + }*/ + + private void appendVCardLine(final StringBuilder builder, + final String propertyName, + final List<String> attributeList, + final List<String> rawDataList, final boolean needCharset, + boolean needQuotedPrintable) { + builder.append(propertyName); + if (attributeList != null && attributeList.size() > 0) { + builder.append(VCARD_ATTR_SEPARATOR); + appendTypeAttributes(builder, attributeList); + } + if (needCharset) { + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(mVCardAttributeCharset); + } + + builder.append(VCARD_DATA_SEPARATOR); + boolean first = true; + for (String rawData : rawDataList) { + final String encodedData; + if (needQuotedPrintable) { + builder.append(VCARD_ATTR_SEPARATOR); + builder.append(VCARD_ATTR_ENCODING_QP); + encodedData = encodeQuotedPrintable(rawData); + } else { + // TODO: one line may be too huge, which may be invalid in vCard spec, though + // several (even well-known) applications do not care this. + encodedData = escapeCharacters(rawData); + } + + if (first) { + first = false; + } else { + builder.append(VCARD_ITEM_SEPARATOR); + } + builder.append(encodedData); + } + builder.append(VCARD_COL_SEPARATOR); + } + /** * VCARD_ATTR_SEPARATOR must be appended before this method being called. */ diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index d8c5a53..9a72d93 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -152,6 +152,12 @@ public final class Telephony { * <P>Type: INTEGER (boolean)</P> */ public static final String LOCKED = "locked"; + + /** + * Error code associated with sending or receiving this message + * <P>Type: INTEGER</P> + */ + public static final String ERROR_CODE = "error_code"; } /** @@ -243,7 +249,7 @@ public final class Telephony { * @return true if the operation succeeded */ public static boolean moveMessageToFolder(Context context, - Uri uri, int folder) { + Uri uri, int folder, int error) { if (uri == null) { return false; } @@ -266,7 +272,7 @@ public final class Telephony { return false; } - ContentValues values = new ContentValues(2); + ContentValues values = new ContentValues(3); values.put(TYPE, folder); if (markAsUnread) { @@ -274,6 +280,7 @@ public final class Telephony { } else if (markAsRead) { values.put(READ, Integer.valueOf(1)); } + values.put(ERROR_CODE, error); return 1 == SqliteWrapper.update(context, context.getContentResolver(), uri, values, null, null); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 304c927..98a6c2c 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -462,6 +462,7 @@ public class WebView extends AbsoluteLayout static final int UPDATE_TEXT_ENTRY_MSG_ID = 15; static final int WEBCORE_INITIALIZED_MSG_ID = 16; static final int UPDATE_TEXTFIELD_TEXT_MSG_ID = 17; + static final int FIND_AGAIN = 18; static final int MOVE_OUT_OF_PLUGIN = 19; static final int CLEAR_TEXT_ENTRY = 20; static final int UPDATE_TEXT_SELECTION_MSG_ID = 21; @@ -491,7 +492,7 @@ public class WebView extends AbsoluteLayout "UPDATE_TEXT_ENTRY_MSG_ID", // = 15; "WEBCORE_INITIALIZED_MSG_ID", // = 16; "UPDATE_TEXTFIELD_TEXT_MSG_ID", // = 17; - "18", // = 18; + "FIND_AGAIN", // = 18; "MOVE_OUT_OF_PLUGIN", // = 19; "CLEAR_TEXT_ENTRY", // = 20; "UPDATE_TEXT_SELECTION_MSG_ID", // = 21; @@ -2362,6 +2363,7 @@ public class WebView extends AbsoluteLayout } int result = nativeFindAll(find.toLowerCase(), find.toUpperCase()); invalidate(); + mLastFind = find; return result; } @@ -2369,6 +2371,9 @@ public class WebView extends AbsoluteLayout // or not we draw the highlights for matches. private boolean mFindIsUp; private int mFindHeight; + // Keep track of the last string sent, so we can search again after an + // orientation change or the dismissal of the soft keyboard. + private String mLastFind; /** * Return the first substring consisting of the address of a physical @@ -5261,6 +5266,13 @@ public class WebView extends AbsoluteLayout } break; + case FIND_AGAIN: + // Ignore if find has been dismissed. + if (mFindIsUp) { + findAll(mLastFind); + } + break; + case DRAG_HELD_MOTIONLESS: mHeldMotionless = MOTIONLESS_TRUE; invalidate(); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 6505ee2..b466591 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -2115,6 +2115,13 @@ final class WebViewCore { WebView.CLEAR_TEXT_ENTRY).sendToTarget(); } + // called by JNI + private void sendFindAgain() { + if (mWebView == null) return; + Message.obtain(mWebView.mPrivateHandler, + WebView.FIND_AGAIN).sendToTarget(); + } + private native void nativeUpdateFrameCacheIfLoading(); /** diff --git a/core/java/com/android/internal/os/IDropBoxService.aidl b/core/java/com/android/internal/os/IDropBoxService.aidl new file mode 100644 index 0000000..f940041 --- /dev/null +++ b/core/java/com/android/internal/os/IDropBoxService.aidl @@ -0,0 +1,42 @@ +/* + * 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.os; + +import android.os.DropBox; +import android.os.ParcelFileDescriptor; + +/** + * "Backend" interface used by {@link android.os.DropBox} to talk to the + * DropBoxService that actually implements the drop box functionality. + * + * @see DropBox + * @hide + */ +interface IDropBoxService { + /** + * @see DropBox#addText + * @see DropBox#addData + * @see DropBox#addFile + */ + void add(in DropBox.Entry entry); + + /** @see DropBox#getNextEntry */ + boolean isTagEnabled(String tag); + + /** @see DropBox#getNextEntry */ + DropBox.Entry getNextEntry(String tag, long millis); +} diff --git a/core/res/Android.mk b/core/res/Android.mk index cb5524a..78cb86d 100644 --- a/core/res/Android.mk +++ b/core/res/Android.mk @@ -34,3 +34,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES) LOCAL_EXPORT_PACKAGE_RESOURCES := true include $(BUILD_PACKAGE) + +# define a global intermediate target that other module may depend on. +.PHONY: framework-res-package-target +framework-res-package-target: $(LOCAL_BUILT_MODULE) diff --git a/data/sounds/ringtones/FreeFlight.ogg b/data/sounds/ringtones/FreeFlight.ogg Binary files differnew file mode 100644 index 0000000..76dfabe --- /dev/null +++ b/data/sounds/ringtones/FreeFlight.ogg diff --git a/data/sounds/ringtones/FreeFlight.wav b/data/sounds/ringtones/FreeFlight.wav Binary files differnew file mode 100644 index 0000000..a4e14aa --- /dev/null +++ b/data/sounds/ringtones/FreeFlight.wav diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd index 76f1213..47505e6 100644 --- a/docs/html/sdk/download.jd +++ b/docs/html/sdk/download.jd @@ -58,7 +58,7 @@ The License Agreement constitutes a contract between you and Google with respect <h2>Thank you for downloading the Android SDK!</h2> <p>Your download should be underway. If not, <a id="click-download">click here to start the download</a>.</p> <p>To set up your Android development environment, please read the guide to - <a href="installing.html" class="addVersionPath">Installing the Android SDK</a>. + <a href="installing.html">Installing the Android SDK</a>. Once you have completed the installation, see the <a href="/guide/index.html">Dev Guide</a> for documentation about developing Android applications.</p> diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index 8897f03..2172536 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -66,7 +66,11 @@ public: GraphicBuffer(); // creates w * h buffer - GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t ssage); + GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage); + + // create a buffer from an existing handle + GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, + uint32_t stride, native_handle_t* handle, bool keepOwnership); // return status status_t initCheck() const; @@ -94,9 +98,15 @@ protected: GraphicBuffer(const Parcel& reply); virtual ~GraphicBuffer(); + enum { + ownNone = 0, + ownHandle = 1, + ownData = 2, + }; + inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } - bool mOwner; + uint8_t mOwner; private: friend class Surface; diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index cc39dac..eb388af 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -30,8 +30,21 @@ using namespace android::renderscript; pthread_key_t Context::gThreadTLSKey = 0; uint32_t Context::gThreadTLSKeyCount = 0; +uint32_t Context::gGLContextCount = 0; pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER; +static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { + if (returnVal != EGL_TRUE) { + fprintf(stderr, "%s() returned %d\n", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error + = eglGetError()) { + fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), + error); + } +} + void Context::initEGL() { mEGL.mNumConfigs = -1; @@ -61,7 +74,10 @@ void Context::initEGL() LOGV("initEGL start"); mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + checkEglError("eglGetDisplay"); + eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion); + checkEglError("eglInitialize"); status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig); if (err) { @@ -76,9 +92,24 @@ void Context::initEGL() android_createDisplaySurface(), NULL); } + checkEglError("eglCreateWindowSurface"); + if (mEGL.mSurface == EGL_NO_SURFACE) { + LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE"); + } + + mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, NULL); + checkEglError("eglCreateContext"); + if (mEGL.mContext == EGL_NO_CONTEXT) { + LOGE("eglCreateContext returned EGL_NO_CONTEXT"); + } + gGLContextCount++; + + EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext); + checkEglError("eglCreateContext", ret); + if (mEGL.mContext == EGL_NO_CONTEXT) { + LOGE("eglCreateContext returned EGL_NO_CONTEXT"); + } - mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, NULL, NULL); - eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext); eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth); eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight); @@ -101,6 +132,24 @@ void Context::initEGL() } } +void Context::deinitEGL() +{ + EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + checkEglError("eglCreateContext", ret); + if (mEGL.mContext == EGL_NO_CONTEXT) { + LOGE("eglCreateContext returned EGL_NO_CONTEXT"); + } + + eglDestroyContext(mEGL.mDisplay, mEGL.mContext); + checkEglError("eglDestroyContext"); + + gGLContextCount--; + if (!gGLContextCount) { + eglTerminate(mEGL.mDisplay); + } +} + + bool Context::runScript(Script *s, uint32_t launchID) { ObjectBaseRef<ProgramFragment> frag(mFragment); @@ -232,7 +281,9 @@ void * Context::threadProc(void *vrsc) rsc->props.mLogScripts = getProp("debug.rs.script"); rsc->props.mLogObjects = getProp("debug.rs.objects"); + pthread_mutex_lock(&gInitMutex); rsc->initEGL(); + pthread_mutex_unlock(&gInitMutex); ScriptTLSStruct *tlsStruct = new ScriptTLSStruct; if (!tlsStruct) { @@ -294,7 +345,11 @@ void * Context::threadProc(void *vrsc) glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface); - eglTerminate(rsc->mEGL.mDisplay); + + pthread_mutex_lock(&gInitMutex); + rsc->deinitEGL(); + pthread_mutex_unlock(&gInitMutex); + rsc->objDestroyOOBRun(); LOGV("RS Thread exited"); return NULL; diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 0dd90ed..c80fd5a 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -54,6 +54,7 @@ public: static pthread_key_t gThreadTLSKey; static uint32_t gThreadTLSKeyCount; + static uint32_t gGLContextCount; static pthread_mutex_t gInitMutex; struct ScriptTLSStruct { @@ -215,6 +216,7 @@ private: Context(); void initEGL(); + void deinitEGL(); bool runRootScript(); diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp index f84933e..1abfd68 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -256,12 +256,16 @@ void DisplayHardware::init(uint32_t dpy) if (strstr(gl_extensions, "GL_OES_draw_texture")) { mFlags |= DRAW_TEXTURE_EXTENSION; } +#ifdef EGL_ANDROID_image_native_buffer if (strstr( gl_extensions, "GL_OES_EGL_image") && (strstr(egl_extensions, "EGL_KHR_image_base") || strstr(egl_extensions, "EGL_KHR_image")) && strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) { mFlags |= DIRECT_TEXTURE; } +#else +#warning "EGL_ANDROID_image_native_buffer not supported" +#endif // Unbind the context from this thread eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 2bb1e12..f5a5a0b 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -130,62 +130,6 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return NO_ERROR; } -status_t Layer::initializeEglImageLocked( - const sp<GraphicBuffer>& buffer, Texture* texture) -{ - status_t err = NO_ERROR; - - // we need to recreate the texture - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - - // free the previous image - if (texture->image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(dpy, texture->image); - texture->image = EGL_NO_IMAGE_KHR; - } - - // construct an EGL_NATIVE_BUFFER_ANDROID - android_native_buffer_t* clientBuf = buffer->getNativeBuffer(); - - // create the new EGLImageKHR - const EGLint attrs[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, - EGL_NONE, EGL_NONE - }; - texture->image = eglCreateImageKHR( - dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - (EGLClientBuffer)clientBuf, attrs); - - LOGE_IF(texture->image == EGL_NO_IMAGE_KHR, - "eglCreateImageKHR() failed. err=0x%4x", - eglGetError()); - - if (texture->image != EGL_NO_IMAGE_KHR) { - glBindTexture(GL_TEXTURE_2D, texture->name); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, - (GLeglImageOES)texture->image); - GLint error = glGetError(); - if (UNLIKELY(error != GL_NO_ERROR)) { - // this failed, for instance, because we don't support NPOT. - // FIXME: do something! - LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) " - "failed err=0x%04x", - this, texture->image, error); - mFlags &= ~DisplayHardware::DIRECT_TEXTURE; - err = INVALID_OPERATION; - } else { - // Everything went okay! - texture->NPOTAdjust = false; - texture->dirty = false; - texture->width = clientBuf->width; - texture->height = clientBuf->height; - } - } else { - err = INVALID_OPERATION; - } - return err; -} - void Layer::reloadTexture(const Region& dirty) { Mutex::Autolock _l(mLock); @@ -199,10 +143,11 @@ void Layer::reloadTexture(const Region& dirty) mTextures[index].height = 0; } +#ifdef EGL_ANDROID_image_native_buffer if (mFlags & DisplayHardware::DIRECT_TEXTURE) { if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) { if (mTextures[index].dirty) { - initializeEglImageLocked(buffer, &mTextures[index]); + initializeEglImage(buffer, &mTextures[index]); } } else { if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width || @@ -212,7 +157,7 @@ void Layer::reloadTexture(const Region& dirty) buffer->width, buffer->height, buffer->format, GraphicBuffer::USAGE_SW_WRITE_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE); - initializeEglImageLocked( + initializeEglImage( mHybridBuffer, &mTextures[0]); } @@ -279,7 +224,9 @@ void Layer::reloadTexture(const Region& dirty) buffer->unlock(); } } - } else { + } else +#endif + { for (size_t i=0 ; i<NUM_BUFFERS ; i++) { mTextures[i].image = EGL_NO_IMAGE_KHR; } diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index 57b3dfa..1310ecc 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -85,8 +85,6 @@ private: } void reloadTexture(const Region& dirty); - status_t initializeEglImageLocked( - const sp<GraphicBuffer>& buffer, Texture* texture); uint32_t getEffectiveUsage(uint32_t usage) const; diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index ecc7894..8003d22 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -617,6 +617,63 @@ void LayerBase::loadTexture(Texture* texture, } } +status_t LayerBase::initializeEglImage( + const sp<GraphicBuffer>& buffer, Texture* texture) +{ + status_t err = NO_ERROR; + + // we need to recreate the texture + EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); + + // free the previous image + if (texture->image != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(dpy, texture->image); + texture->image = EGL_NO_IMAGE_KHR; + } + + // construct an EGL_NATIVE_BUFFER_ANDROID + android_native_buffer_t* clientBuf = buffer->getNativeBuffer(); + + // create the new EGLImageKHR + const EGLint attrs[] = { + EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, + EGL_NONE, EGL_NONE + }; + texture->image = eglCreateImageKHR( + dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, + (EGLClientBuffer)clientBuf, attrs); + + LOGE_IF(texture->image == EGL_NO_IMAGE_KHR, + "eglCreateImageKHR() failed. err=0x%4x", + eglGetError()); + + if (texture->image != EGL_NO_IMAGE_KHR) { + glBindTexture(GL_TEXTURE_2D, texture->name); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, + (GLeglImageOES)texture->image); + GLint error = glGetError(); + if (UNLIKELY(error != GL_NO_ERROR)) { + // this failed, for instance, because we don't support NPOT. + // FIXME: do something! + LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) " + "failed err=0x%04x", + this, texture->image, error); + mFlags &= ~DisplayHardware::DIRECT_TEXTURE; + err = INVALID_OPERATION; + } else { + // Everything went okay! + texture->NPOTAdjust = false; + texture->dirty = false; + texture->width = clientBuf->width; + texture->height = clientBuf->height; + } + } else { + err = INVALID_OPERATION; + } + return err; +} + + // --------------------------------------------------------------------------- int32_t LayerBaseClient::sIdentity = 0; diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index efa4f8c..ed07b3f 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -261,6 +261,8 @@ protected: void drawWithOpenGL(const Region& clip, const Texture& texture) const; void loadTexture(Texture* texture, const Region& dirty, const GGLSurface& t) const; + status_t initializeEglImage( + const sp<GraphicBuffer>& buffer, Texture* texture); sp<SurfaceFlinger> mFlinger; diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp index 7e27a02..6590503 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/libs/surfaceflinger/LayerBuffer.cpp @@ -339,12 +339,6 @@ LayerBuffer::BufferSource::BufferSource(LayerBuffer& layer, mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0); mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride; mLayer.forceVisibilityTransaction(); - - hw_module_t const* module; - mBlitEngine = NULL; - if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { - copybit_open(module, &mBlitEngine); - } } LayerBuffer::BufferSource::~BufferSource() @@ -352,8 +346,9 @@ LayerBuffer::BufferSource::~BufferSource() if (mTexture.name != -1U) { glDeleteTextures(1, &mTexture.name); } - if (mBlitEngine) { - copybit_close(mBlitEngine); + if (mTexture.image != EGL_NO_IMAGE_KHR) { + EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay()); + eglDestroyImageKHR(dpy, mTexture.image); } } @@ -421,122 +416,28 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const status_t err = NO_ERROR; NativeBuffer src(ourBuffer->getBuffer()); const Rect transformedBounds(mLayer.getTransformedBounds()); - copybit_device_t* copybit = mBlitEngine; - - if (copybit) { - const int src_width = src.crop.r - src.crop.l; - const int src_height = src.crop.b - src.crop.t; - int W = transformedBounds.width(); - int H = transformedBounds.height(); - if (mLayer.getOrientation() & Transform::ROT_90) { - int t(W); W=H; H=t; - } - -#ifdef EGL_ANDROID_get_render_buffer - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLSurface draw = eglGetCurrentSurface(EGL_DRAW); - EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw); - android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf; - if (nb == 0) { - err = BAD_VALUE; - } else { - copybit_image_t dst; - dst.w = nb->width; - dst.h = nb->height; - dst.format = nb->format; - dst.base = NULL; // unused by copybit on msm7k - dst.handle = (native_handle_t *)nb->handle; - - /* With LayerBuffer, it is likely that we'll have to rescale the - * surface, because this is often used for video playback or - * camera-preview. Since we want these operation as fast as possible - * we make sure we can use the 2D H/W even if it doesn't support - * the requested scale factor, in which case we perform the scaling - * in several passes. */ - - const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT); - const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT); - - float xscale = 1.0f; - if (src_width > W*min) xscale = 1.0f / min; - else if (src_width*mag < W) xscale = mag; - - float yscale = 1.0f; - if (src_height > H*min) yscale = 1.0f / min; - else if (src_height*mag < H) yscale = mag; - - if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) { - const int tmp_w = floorf(src_width * xscale); - const int tmp_h = floorf(src_height * yscale); - - if (mTempBitmap==0 || - mTempBitmap->getWidth() < size_t(tmp_w) || - mTempBitmap->getHeight() < size_t(tmp_h)) { - mTempBitmap.clear(); - mTempBitmap = new GraphicBuffer( - tmp_w, tmp_h, src.img.format, - GraphicBuffer::USAGE_HW_2D); - err = mTempBitmap->initCheck(); - } - - if (LIKELY(err == NO_ERROR)) { - NativeBuffer tmp; - tmp.img.w = tmp_w; - tmp.img.h = tmp_h; - tmp.img.format = src.img.format; - tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle; - tmp.crop.l = 0; - tmp.crop.t = 0; - tmp.crop.r = tmp.img.w; - tmp.crop.b = tmp.img.h; - - region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b))); - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); - copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); - err = copybit->stretch(copybit, - &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it); - src = tmp; - } - } - const Rect transformedBounds(mLayer.getTransformedBounds()); - const copybit_rect_t& drect = - reinterpret_cast<const copybit_rect_t&>(transformedBounds); - const State& s(mLayer.drawingState()); - region_iterator it(clip); - - // pick the right orientation for this buffer - int orientation = mLayer.getOrientation(); - if (UNLIKELY(mBufferHeap.transform)) { - Transform rot90; - GraphicPlane::orientationToTransfrom( - ISurfaceComposer::eOrientation90, 0, 0, &rot90); - const Transform& planeTransform(mLayer.graphicPlane(0).transform()); - const Layer::State& s(mLayer.drawingState()); - Transform tr(planeTransform * s.transform * rot90); - orientation = tr.getOrientation(); - } + if (UNLIKELY(mTexture.name == -1LU)) { + mTexture.name = mLayer.createTexture(); + } - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation); - copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha); - copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE); +#if defined(EGL_ANDROID_image_native_buffer) + if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) { + // NOTE: Assume the buffer is allocated with the proper USAGE flags + sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( + src.crop.r, src.crop.b, src.img.format, + GraphicBuffer::USAGE_HW_TEXTURE, + src.img.w, src.img.handle, false); - err = copybit->stretch(copybit, - &dst, &src.img, &drect, &src.crop, &it); - if (err != NO_ERROR) { - LOGE("copybit failed (%s)", strerror(err)); - } - } + err = mLayer.initializeEglImage(graphicBuffer, &mTexture); } #endif - - if (!copybit || err) - { + else { + err = INVALID_OPERATION; + } + + if (err != NO_ERROR) { // OpenGL fall-back - if (UNLIKELY(mTexture.name == -1LU)) { - mTexture.name = mLayer.createTexture(); - } GLuint w = 0; GLuint h = 0; GGLSurface t; @@ -549,11 +450,11 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const t.data = (GGLubyte*)src.img.base; const Region dirty(Rect(t.width, t.height)); mLayer.loadTexture(&mTexture, dirty, t); - mTexture.transform = mBufferHeap.transform; - mLayer.drawWithOpenGL(clip, mTexture); } -} + mTexture.transform = mBufferHeap.transform; + mLayer.drawWithOpenGL(clip, mTexture); +} // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h index 5eb472c..438b711 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/libs/surfaceflinger/LayerBuffer.h @@ -132,7 +132,6 @@ private: size_t mBufferSize; mutable sp<GraphicBuffer> mTempBitmap; mutable LayerBase::Texture mTexture; - copybit_device_t* mBlitEngine; }; class OverlaySource : public Source { diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp index 538dc77..fd61e30 100644 --- a/libs/surfaceflinger/LayerDim.cpp +++ b/libs/surfaceflinger/LayerDim.cpp @@ -55,8 +55,8 @@ void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h) sHeight = h; sUseTexture = false; -#ifdef DIM_WITH_TEXTURE - +#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer) + #warning "using a texture to implement LayerDim" /* On some h/w like msm7K, it is faster to use a texture because the @@ -69,7 +69,6 @@ void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h) uint32_t flags = hw.getFlags(); if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) { - // TODO: api to pass the usage flags sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565, GraphicBuffer::USAGE_SW_WRITE_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE); @@ -123,7 +122,7 @@ void LayerDim::onDraw(const Region& clip) const glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glColor4x(0, 0, 0, alpha); -#ifdef DIM_WITH_TEXTURE +#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer) if (sUseTexture) { glBindTexture(GL_TEXTURE_2D, sTexId); glEnable(GL_TEXTURE_2D); diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index 6698e00..f9bfe6c 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -246,8 +246,10 @@ private: virtual status_t readyToRun(); virtual void onFirstRef(); +public: // hack to work around gcc 4.0.3 bug const GraphicPlane& graphicPlane(int dpy) const; GraphicPlane& graphicPlane(int dpy); +private: void waitForEvent(); public: // hack to work around gcc 4.0.3 bug diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 1cf20d7..efe2d78 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -37,7 +37,7 @@ namespace android { // =========================================================================== GraphicBuffer::GraphicBuffer() - : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()), + : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mVStride(0), mIndex(-1) { width = @@ -50,7 +50,7 @@ GraphicBuffer::GraphicBuffer() GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, PixelFormat reqFormat, uint32_t reqUsage) - : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()), + : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mVStride(0), mIndex(-1) { width = @@ -62,8 +62,23 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, mInitCheck = initSize(w, h, reqFormat, reqUsage); } +GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, + PixelFormat inFormat, uint32_t inUsage, + uint32_t inStride, native_handle_t* inHandle, bool keepOwnership) + : BASE(), mOwner(keepOwnership ? ownHandle : ownNone), + mBufferMapper(GraphicBufferMapper::get()), + mInitCheck(NO_ERROR), mVStride(0), mIndex(-1) +{ + width = w; + height = h; + stride = inStride; + format = inFormat; + usage = inUsage; + handle = inHandle; +} + GraphicBuffer::GraphicBuffer(const Parcel& data) - : BASE(), mOwner(true), mBufferMapper(GraphicBufferMapper::get()), + : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mVStride(0), mIndex(-1) { // we own the handle in this case @@ -83,10 +98,10 @@ GraphicBuffer::GraphicBuffer(const Parcel& data) GraphicBuffer::~GraphicBuffer() { if (handle) { - if (mOwner) { + if (mOwner == ownHandle) { native_handle_close(handle); native_handle_delete(const_cast<native_handle*>(handle)); - } else { + } else if (mOwner == ownData) { GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); allocator.free(handle); } @@ -106,6 +121,9 @@ android_native_buffer_t* GraphicBuffer::getNativeBuffer() const status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f, uint32_t reqUsage) { + if (mOwner != ownData) + return INVALID_OPERATION; + if (handle) { GraphicBufferAllocator& allocator(GraphicBufferAllocator::get()); allocator.free(handle); diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java index 35f0409..e1e09b9 100644 --- a/media/java/android/media/AsyncPlayer.java +++ b/media/java/android/media/AsyncPlayer.java @@ -19,10 +19,12 @@ package android.media; import android.content.Context; import android.net.Uri; import android.os.PowerManager; +import android.os.SystemClock; import android.util.Log; import java.io.IOException; import java.lang.IllegalStateException; +import java.util.LinkedList; /** * Plays a series of audio URIs, but does all the hard work on another thread @@ -31,14 +33,15 @@ import java.lang.IllegalStateException; public class AsyncPlayer { private static final int PLAY = 1; private static final int STOP = 2; + private static final boolean mDebug = false; private static final class Command { - Command next; int code; Context context; Uri uri; boolean looping; int stream; + long requestTime; public String toString() { return "{ code=" + code + " looping=" + looping + " stream=" + stream @@ -46,6 +49,36 @@ public class AsyncPlayer { } } + private LinkedList<Command> mCmdQueue = new LinkedList(); + + private void startSound(Command cmd) { + // Preparing can be slow, so if there is something else + // is playing, let it continue until we're done, so there + // is less of a glitch. + try { + if (mDebug) Log.d(mTag, "Starting playback"); + MediaPlayer player = new MediaPlayer(); + player.setAudioStreamType(cmd.stream); + player.setDataSource(cmd.context, cmd.uri); + player.setLooping(cmd.looping); + player.prepare(); + player.start(); + if (mPlayer != null) { + mPlayer.release(); + } + mPlayer = player; + long delay = SystemClock.uptimeMillis() - cmd.requestTime; + if (delay > 1000) { + Log.w(mTag, "Notification sound delayed by " + delay + "msecs"); + } + } + catch (IOException e) { + Log.w(mTag, "error loading sound for " + cmd.uri, e); + } catch (IllegalStateException e) { + Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e); + } + } + private final class Thread extends java.lang.Thread { Thread() { super("AsyncPlayer-" + mTag); @@ -55,41 +88,23 @@ public class AsyncPlayer { while (true) { Command cmd = null; - synchronized (mLock) { - if (mHead != null) { - cmd = mHead; - mHead = cmd.next; - if (mTail == cmd) { - mTail = null; - } - } + synchronized (mCmdQueue) { + if (mDebug) Log.d(mTag, "RemoveFirst"); + cmd = mCmdQueue.removeFirst(); } switch (cmd.code) { case PLAY: - try { - // Preparing can be slow, so if there is something else - // is playing, let it continue until we're done, so there - // is less of a glitch. - MediaPlayer player = new MediaPlayer(); - player.setAudioStreamType(cmd.stream); - player.setDataSource(cmd.context, cmd.uri); - player.setLooping(cmd.looping); - player.prepare(); - player.start(); - if (mPlayer != null) { - mPlayer.release(); - } - mPlayer = player; - } - catch (IOException e) { - Log.w(mTag, "error loading sound for " + cmd.uri, e); - } catch (IllegalStateException e) { - Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e); - } + if (mDebug) Log.d(mTag, "PLAY"); + startSound(cmd); break; case STOP: + if (mDebug) Log.d(mTag, "STOP"); if (mPlayer != null) { + long delay = SystemClock.uptimeMillis() - cmd.requestTime; + if (delay > 1000) { + Log.w(mTag, "Notification stop delayed by " + delay + "msecs"); + } mPlayer.stop(); mPlayer.release(); mPlayer = null; @@ -99,8 +114,8 @@ public class AsyncPlayer { break; } - synchronized (mLock) { - if (mHead == null) { + synchronized (mCmdQueue) { + if (mCmdQueue.size() == 0) { // nothing left to do, quit // doing this check after we're done prevents the case where they // added it during the operation from spawning two threads and @@ -115,11 +130,8 @@ public class AsyncPlayer { } private String mTag; - private Command mHead; - private Command mTail; private Thread mThread; private MediaPlayer mPlayer; - private Object mLock = new Object(); private PowerManager.WakeLock mWakeLock; // The current state according to the caller. Reality lags behind @@ -154,12 +166,13 @@ public class AsyncPlayer { */ public void play(Context context, Uri uri, boolean looping, int stream) { Command cmd = new Command(); + cmd.requestTime = SystemClock.uptimeMillis(); cmd.code = PLAY; cmd.context = context; cmd.uri = uri; cmd.looping = looping; cmd.stream = stream; - synchronized (mLock) { + synchronized (mCmdQueue) { enqueueLocked(cmd); mState = PLAY; } @@ -170,11 +183,12 @@ public class AsyncPlayer { * at this point. Calling this multiple times has no ill effects. */ public void stop() { - synchronized (mLock) { + synchronized (mCmdQueue) { // This check allows stop to be called multiple times without starting // a thread that ends up doing nothing. if (mState != STOP) { Command cmd = new Command(); + cmd.requestTime = SystemClock.uptimeMillis(); cmd.code = STOP; enqueueLocked(cmd); mState = STOP; @@ -183,12 +197,7 @@ public class AsyncPlayer { } private void enqueueLocked(Command cmd) { - if (mTail == null) { - mHead = cmd; - } else { - mTail.next = cmd; - } - mTail = cmd; + mCmdQueue.add(cmd); if (mThread == null) { acquireWakeLock(); mThread = new Thread(); diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index d90871e..58a0bba 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -959,10 +959,10 @@ public class AudioService extends IAudioService.Stub { /////////////////////////////////////////////////////////////////////////// public class VolumeStreamState { - private final String mVolumeIndexSettingName; - private final String mLastAudibleVolumeIndexSettingName; private final int mStreamType; + private String mVolumeIndexSettingName; + private String mLastAudibleVolumeIndexSettingName; private int mIndexMax; private int mIndex; private int mLastAudibleIndex; @@ -970,8 +970,7 @@ public class AudioService extends IAudioService.Stub { private VolumeStreamState(String settingName, int streamType) { - mVolumeIndexSettingName = settingName; - mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; + setVolumeIndexSettingName(settingName); mStreamType = streamType; @@ -991,6 +990,11 @@ public class AudioService extends IAudioService.Stub { mDeathHandlers = new ArrayList<VolumeDeathHandler>(); } + public void setVolumeIndexSettingName(String settingName) { + mVolumeIndexSettingName = settingName; + mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; + } + public boolean adjustIndex(int deltaIndex) { return setIndex(mIndex + deltaIndex * 10, true); } @@ -1370,11 +1374,17 @@ public class AudioService extends IAudioService.Stub { mNotificationsUseRingVolume = notificationsUseRingVolume; if (mNotificationsUseRingVolume == 1) { STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; + mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( + System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]); } else { STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; + mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( + System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]); // Persist notification volume volume as it was not persisted while aliased to ring volume + // and persist with no delay as there might be registered observers of the persisted + // notification volume. sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION, - SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY); + SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0); } } } diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp index 8627708..aa49429 100644 --- a/media/libmediaplayerservice/TestPlayerStub.cpp +++ b/media/libmediaplayerservice/TestPlayerStub.cpp @@ -176,7 +176,7 @@ status_t TestPlayerStub::resetInternal() mContentUrl = NULL; if (mPlayer) { - LOG_ASSERT(mDeletePlayer != NULL); + LOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null"); (*mDeletePlayer)(mPlayer); mPlayer = NULL; } diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk index 2522656..9837845 100644 --- a/opengl/libagl/Android.mk +++ b/opengl/libagl/Android.mk @@ -25,6 +25,13 @@ LOCAL_SRC_FILES:= \ primitives.cpp.arm \ vertex.cpp.arm +LOCAL_CFLAGS += -DLOG_TAG=\"libagl\" +LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES +LOCAL_CFLAGS += -fvisibility=hidden + +LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger +LOCAL_LDLIBS := -lpthread -ldl + ifeq ($(TARGET_ARCH),arm) LOCAL_SRC_FILES += fixed_asm.S iterators.S LOCAL_CFLAGS += -fstrict-aliasing @@ -38,15 +45,9 @@ endif ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1) LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS LOCAL_SRC_FILES += copybit.cpp + LOCAL_SHARED_LIBRARIES += libui endif -LOCAL_CFLAGS += -DLOG_TAG=\"libagl\" -LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES - -LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger -LOCAL_CFLAGS += -fvisibility=hidden - -LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl LOCAL_MODULE:= libGLES_android diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp index 73b2355..0c3d0ee 100644 --- a/opengl/libagl/copybit.cpp +++ b/opengl/libagl/copybit.cpp @@ -33,6 +33,10 @@ #include <hardware/copybit.h> #include <private/ui/android_natives_priv.h> +#include <ui/GraphicBuffer.h> +#include <ui/Region.h> +#include <ui/Rect.h> + #define DEBUG_COPYBIT true @@ -175,16 +179,6 @@ static bool copybit(GLint x, GLint y, dtdy /= screen_h; } dtdy = -dtdy; // see equation of dtdy above - if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale - || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) { - // The requested scale is out of the range the hardware - // can support. - LOGD_IF(DEBUG_COPYBIT, - "scale out of range dsdx=%08x (Wcr=%d / w=%d), " - "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", - dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr); - return false; - } // copybit doesn't say anything about filtering, so we can't // discriminate. On msm7k, copybit will always filter. @@ -278,21 +272,93 @@ static bool copybit(GLint x, GLint y, return false; } + copybit_device_t* copybit = c->copybits.blitEngine; + copybit_image_t src; + buffer_handle_t source_hnd = textureObject->buffer->handle; + textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src); + copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr }; + + /* + * Below we perform extra passes needed to emulate things the h/w + * cannot do. + */ - // LOGW("calling copybits"); + const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16); + const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16); - copybit_device_t* copybit = c->copybits.blitEngine; + sp<GraphicBuffer> tempBitmap; + + if (dsdx < maxScaleInv || dsdx > minScaleInv || + dtdy < maxScaleInv || dtdy > minScaleInv) + { + // The requested scale is out of the range the hardware + // can support. + LOGD_IF(DEBUG_COPYBIT, + "scale out of range dsdx=%08x (Wcr=%d / w=%d), " + "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", + dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr); + + int32_t xscale=0x10000, yscale=0x10000; + if (dsdx > minScaleInv) xscale = c->copybits.minScale; + else if (dsdx < maxScaleInv) xscale = c->copybits.maxScale; + if (dtdy > minScaleInv) yscale = c->copybits.minScale; + else if (dtdy < maxScaleInv) yscale = c->copybits.maxScale; + dsdx = gglMulx(dsdx, xscale); + dtdy = gglMulx(dtdy, yscale); + + /* we handle only one step of resizing below. Handling an arbitrary + * number is relatively easy (replace "if" above by "while"), but requires + * two intermediate buffers and so far we never had the need. + */ + + if (dsdx < maxScaleInv || dsdx > minScaleInv || + dtdy < maxScaleInv || dtdy > minScaleInv) { + LOGD_IF(DEBUG_COPYBIT, + "scale out of range dsdx=%08x (Wcr=%d / w=%d), " + "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", + dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr); + return false; + } + + const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16); + const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16); + + LOGD_IF(DEBUG_COPYBIT, + "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d", + xscale, yscale, dsdx, dtdy, tmp_w, tmp_h); + + tempBitmap = new GraphicBuffer( + tmp_w, tmp_h, src.format, + GraphicBuffer::USAGE_HW_2D); + + status_t err = tempBitmap->initCheck(); + if (err == NO_ERROR) { + copybit_image_t tmp_dst; + copybit_rect_t tmp_rect; + tmp_dst.w = tmp_w; + tmp_dst.h = tmp_h; + tmp_dst.format = src.format; + tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle; + tmp_rect.l = 0; + tmp_rect.t = 0; + tmp_rect.r = tmp_dst.w; + tmp_rect.b = tmp_dst.h; + region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b))); + copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0); + copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF); + copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE); + err = copybit->stretch(copybit, + &tmp_dst, &src, &tmp_rect, &srect, &tmp_it); + src = tmp_dst; + srect = tmp_rect; + } + } copybit_image_t dst; buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer; textureToCopyBitImage(&cbSurface, cbSurface.format, target_hnd, &dst); copybit_rect_t drect = {x, y, x+w, y+h}; - copybit_image_t src; - buffer_handle_t source_hnd = textureObject->buffer->handle; - textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src); - copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr }; - copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform); copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha); copybit->set_parameter(copybit, COPYBIT_DITHER, diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk new file mode 100644 index 0000000..6ff248d --- /dev/null +++ b/opengl/tests/linetex/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + linetex.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libEGL \ + libGLESv1_CM \ + libui + +LOCAL_MODULE:= test-opengl-linetex + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp new file mode 100644 index 0000000..e62fe03 --- /dev/null +++ b/opengl/tests/linetex/linetex.cpp @@ -0,0 +1,117 @@ +/* +** +** Copyright 2006, 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. +*/ + +#define LOG_TAG "fillrate" + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#include <EGL/egl.h> +#include <GLES/gl.h> +#include <GLES/glext.h> + +#include <utils/StopWatch.h> +#include <ui/FramebufferNativeWindow.h> +#include <ui/EGLUtils.h> + +using namespace android; + +int main(int argc, char** argv) +{ + EGLint configAttribs[] = { + EGL_DEPTH_SIZE, 0, + EGL_NONE + }; + + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLConfig config; + EGLSurface surface; + EGLint w, h; + EGLDisplay dpy; + + EGLNativeWindowType window = android_createDisplaySurface(); + + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(dpy, &majorVersion, &minorVersion); + + status_t err = EGLUtils::selectConfigForNativeWindow( + dpy, configAttribs, window, &config); + if (err) { + fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n"); + return 0; + } + + surface = eglCreateWindowSurface(dpy, config, window, NULL); + context = eglCreateContext(dpy, config, NULL, NULL); + eglMakeCurrent(dpy, surface, surface, context); + eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + + printf("w=%d, h=%d\n", w, h); + + glBindTexture(GL_TEXTURE_2D, 0); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glDisable(GL_DITHER); + glDisable(GL_BLEND); + glEnable(GL_TEXTURE_2D); + glColor4f(1,1,1,1); + + const uint32_t t32[] = { + 0xFFFFFFFF, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, + 0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0xFF000000 + }; + + const GLfloat vertices[4][2] = { + { 0, 0 }, + { w, h } + }; + + const GLfloat texCoords[4][2] = { + { 0, 0 }, + { 1, 0 } + }; + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32); + + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, w, 0, h, 0, 1); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, vertices); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_LINES, 0, 2); + eglSwapBuffers(dpy, surface); + + usleep(5*1000000); + + eglTerminate(dpy); + + return 0; +} diff --git a/services/java/com/android/server/DropBoxService.java b/services/java/com/android/server/DropBoxService.java index 6c96a46..f4e5ebc 100644 --- a/services/java/com/android/server/DropBoxService.java +++ b/services/java/com/android/server/DropBoxService.java @@ -23,8 +23,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.DropBoxEntry; -import android.os.IDropBox; +import android.os.DropBox; import android.os.ParcelFileDescriptor; import android.os.StatFs; import android.os.SystemClock; @@ -32,11 +31,13 @@ import android.provider.Settings; import android.text.format.DateFormat; import android.util.Log; +import com.android.internal.os.IDropBoxService; + import java.io.File; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -53,11 +54,12 @@ import java.util.TreeSet; import java.util.zip.GZIPOutputStream; /** - * Implementation of {@link IDropBox} using the filesystem. + * Implementation of {@link IDropBoxService} using the filesystem. + * Clients use {@link DropBox} to access this service. * * {@hide} */ -public final class DropBoxService extends IDropBox.Stub { +public final class DropBoxService extends IDropBoxService.Stub { private static final String TAG = "DropBoxService"; private static final int DEFAULT_RESERVE_PERCENT = 10; private static final int DEFAULT_QUOTA_PERCENT = 10; @@ -129,50 +131,13 @@ public final class DropBoxService extends IDropBox.Stub { mContext.unregisterReceiver(mReceiver); } - public void addText(String tag, String data) { - addData(tag, data.getBytes(), DropBoxEntry.IS_TEXT); - } - - public void addData(String tag, byte[] data, int flags) { - File temp = null; - OutputStream out = null; - try { - if ((flags & DropBoxEntry.IS_EMPTY) != 0) throw new IllegalArgumentException(); - - init(); - if (!isTagEnabled(tag)) return; - - long max = trimToFit(); - if (data.length > max) { - Log.w(TAG, "Dropping: " + tag + " (" + data.length + " > " + max + " bytes)"); - // Pass temp = null to createEntry() to leave a tombstone - } else { - temp = new File(mDropBoxDir, "drop" + Thread.currentThread().getId() + ".tmp"); - out = new FileOutputStream(temp); - if (data.length > mBlockSize && ((flags & DropBoxEntry.IS_GZIPPED) == 0)) { - flags = flags | DropBoxEntry.IS_GZIPPED; - out = new GZIPOutputStream(out); - } - out.write(data); - out.close(); - out = null; - } - - createEntry(temp, tag, flags); - temp = null; - } catch (IOException e) { - Log.e(TAG, "Can't write: " + tag, e); - } finally { - try { if (out != null) out.close(); } catch (IOException e) {} - if (temp != null) temp.delete(); - } - } - - public void addFile(String tag, ParcelFileDescriptor data, int flags) { + public void add(DropBox.Entry entry) { File temp = null; OutputStream output = null; + final String tag = entry.getTag(); try { - if ((flags & DropBoxEntry.IS_EMPTY) != 0) throw new IllegalArgumentException(); + int flags = entry.getFlags(); + if ((flags & DropBox.IS_EMPTY) != 0) throw new IllegalArgumentException(); init(); if (!isTagEnabled(tag)) return; @@ -180,7 +145,7 @@ public final class DropBoxService extends IDropBox.Stub { long lastTrim = System.currentTimeMillis(); byte[] buffer = new byte[mBlockSize]; - FileInputStream input = new FileInputStream(data.getFileDescriptor()); + InputStream input = entry.getInputStream(); // First, accumulate up to one block worth of data in memory before // deciding whether to compress the data or not. @@ -197,9 +162,9 @@ public final class DropBoxService extends IDropBox.Stub { temp = new File(mDropBoxDir, "drop" + Thread.currentThread().getId() + ".tmp"); output = new FileOutputStream(temp); - if (read == buffer.length && ((flags & DropBoxEntry.IS_GZIPPED) == 0)) { + if (read == buffer.length && ((flags & DropBox.IS_GZIPPED) == 0)) { output = new GZIPOutputStream(output); - flags = flags | DropBoxEntry.IS_GZIPPED; + flags = flags | DropBox.IS_GZIPPED; } do { @@ -234,7 +199,7 @@ public final class DropBoxService extends IDropBox.Stub { Log.e(TAG, "Can't write: " + tag, e); } finally { try { if (output != null) output.close(); } catch (IOException e) {} - try { data.close(); } catch (IOException e) {} + entry.close(); if (temp != null) temp.delete(); } } @@ -244,7 +209,7 @@ public final class DropBoxService extends IDropBox.Stub { mContentResolver, Settings.Gservices.DROPBOX_TAG_PREFIX + tag)); } - public synchronized DropBoxEntry getNextEntry(String tag, long millis) { + public synchronized DropBox.Entry getNextEntry(String tag, long millis) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.READ_LOGS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("READ_LOGS permission required"); @@ -262,9 +227,11 @@ public final class DropBoxService extends IDropBox.Stub { for (EntryFile entry : list.contents.tailSet(new EntryFile(millis + 1))) { if (entry.tag == null) continue; + if ((entry.flags & DropBox.IS_EMPTY) != 0) { + return new DropBox.Entry(entry.tag, entry.timestampMillis); + } try { - File file = (entry.flags & DropBoxEntry.IS_EMPTY) != 0 ? null : entry.file; - return new DropBoxEntry(entry.tag, entry.timestampMillis, file, entry.flags); + return new DropBox.Entry(entry.tag, entry.timestampMillis, entry.file, entry.flags); } catch (IOException e) { Log.e(TAG, "Can't read: " + entry.file, e); // Continue to next file @@ -331,25 +298,25 @@ public final class DropBoxService extends IDropBox.Stub { if (entry.file == null) { pw.println(" (no file)"); continue; - } else if ((entry.flags & DropBoxEntry.IS_EMPTY) != 0) { + } else if ((entry.flags & DropBox.IS_EMPTY) != 0) { pw.println(" (contents lost)"); continue; } else { - pw.print((entry.flags & DropBoxEntry.IS_GZIPPED) != 0 ? " (comopressed " : " ("); - pw.print((entry.flags & DropBoxEntry.IS_TEXT) != 0 ? "text" : "data"); + pw.print((entry.flags & DropBox.IS_GZIPPED) != 0 ? " (comopressed " : " ("); + pw.print((entry.flags & DropBox.IS_TEXT) != 0 ? "text" : "data"); pw.format(", %d bytes)", entry.file.length()); pw.println(); } - if (doFile || (doPrint && (entry.flags & DropBoxEntry.IS_TEXT) == 0)) { + if (doFile || (doPrint && (entry.flags & DropBox.IS_TEXT) == 0)) { if (!doPrint) pw.print(" "); pw.println(entry.file.getPath()); } - if ((entry.flags & DropBoxEntry.IS_TEXT) != 0 && (doPrint || !doFile)) { - DropBoxEntry dbe = null; + if ((entry.flags & DropBox.IS_TEXT) != 0 && (doPrint || !doFile)) { + DropBox.Entry dbe = null; try { - dbe = new DropBoxEntry( + dbe = new DropBox.Entry( entry.tag, entry.timestampMillis, entry.file, entry.flags); if (doPrint) { @@ -435,20 +402,20 @@ public final class DropBoxService extends IDropBox.Stub { * @param dir to store file in * @param tag to use for new log file name * @param timestampMillis of log entry - * @param flags for the entry data (from {@link DropBoxEntry}) + * @param flags for the entry data * @param blockSize to use for space accounting * @throws IOException if the file can't be moved */ public EntryFile(File temp, File dir, String tag,long timestampMillis, int flags, int blockSize) throws IOException { - if ((flags & DropBoxEntry.IS_EMPTY) != 0) throw new IllegalArgumentException(); + if ((flags & DropBox.IS_EMPTY) != 0) throw new IllegalArgumentException(); this.tag = tag; this.timestampMillis = timestampMillis; this.flags = flags; this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis + - ((flags & DropBoxEntry.IS_TEXT) != 0 ? ".txt" : ".dat") + - ((flags & DropBoxEntry.IS_GZIPPED) != 0 ? ".gz" : "")); + ((flags & DropBox.IS_TEXT) != 0 ? ".txt" : ".dat") + + ((flags & DropBox.IS_GZIPPED) != 0 ? ".gz" : "")); if (!temp.renameTo(this.file)) { throw new IOException("Can't rename " + temp + " to " + this.file); @@ -466,7 +433,7 @@ public final class DropBoxService extends IDropBox.Stub { public EntryFile(File dir, String tag, long timestampMillis) throws IOException { this.tag = tag; this.timestampMillis = timestampMillis; - this.flags = DropBoxEntry.IS_EMPTY; + this.flags = DropBox.IS_EMPTY; this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis + ".lost"); this.blocks = 0; new FileOutputStream(this.file).close(); @@ -486,26 +453,26 @@ public final class DropBoxService extends IDropBox.Stub { if (at < 0) { this.tag = null; this.timestampMillis = 0; - this.flags = DropBoxEntry.IS_EMPTY; + this.flags = DropBox.IS_EMPTY; return; } int flags = 0; this.tag = Uri.decode(name.substring(0, at)); if (name.endsWith(".gz")) { - flags |= DropBoxEntry.IS_GZIPPED; + flags |= DropBox.IS_GZIPPED; name = name.substring(0, name.length() - 3); } if (name.endsWith(".lost")) { - flags |= DropBoxEntry.IS_EMPTY; + flags |= DropBox.IS_EMPTY; name = name.substring(at + 1, name.length() - 5); } else if (name.endsWith(".txt")) { - flags |= DropBoxEntry.IS_TEXT; + flags |= DropBox.IS_TEXT; name = name.substring(at + 1, name.length() - 4); } else if (name.endsWith(".dat")) { name = name.substring(at + 1, name.length() - 4); } else { - this.flags = DropBoxEntry.IS_EMPTY; + this.flags = DropBox.IS_EMPTY; this.timestampMillis = 0; return; } @@ -523,7 +490,7 @@ public final class DropBoxService extends IDropBox.Stub { public EntryFile(long millis) { this.tag = null; this.timestampMillis = millis; - this.flags = DropBoxEntry.IS_EMPTY; + this.flags = DropBox.IS_EMPTY; this.file = null; this.blocks = 0; } @@ -618,7 +585,7 @@ public final class DropBoxService extends IDropBox.Stub { mAllFiles.blocks -= late.blocks; FileList tagFiles = mFilesByTag.get(late.tag); if (tagFiles.contents.remove(late)) tagFiles.blocks -= late.blocks; - if ((late.flags & DropBoxEntry.IS_EMPTY) == 0) { + if ((late.flags & DropBox.IS_EMPTY) == 0) { enrollEntry(new EntryFile( late.file, mDropBoxDir, late.tag, t++, late.flags, mBlockSize)); } else { diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 5c4aa79..4bf606d 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -131,6 +131,8 @@ class PowerManagerService extends IPowerManager.Stub static final boolean ANIMATE_KEYBOARD_LIGHTS = false; static final int ANIM_STEPS = 60/4; + // Slower animation for autobrightness changes + static final int AUTOBRIGHTNESS_ANIM_STEPS = 60; // These magic numbers are the initial state of the LEDs at boot. Ideally // we should read them from the driver, but our current hardware returns 0 @@ -156,7 +158,6 @@ class PowerManagerService extends IPowerManager.Stub private int mProximityCount = 0; private int mPowerState; private boolean mOffBecauseOfUser; - private boolean mAnimatingScreenOff; private int mUserState; private boolean mKeyboardVisible = false; private boolean mUserActivityAllowed = true; @@ -224,7 +225,7 @@ class PowerManagerService extends IPowerManager.Stub // could be either static or controllable at runtime private static final boolean mSpew = false; - private static final boolean mDebugLightSensor = false; + private static final boolean mDebugLightSensor = (false || mSpew); /* static PrintStream mLog; @@ -1230,7 +1231,6 @@ class PowerManagerService extends IPowerManager.Stub Log.d(TAG, "preventScreenOn: turning on after a prior preventScreenOn(true)!"); } - mAnimatingScreenOff = false; int err = setScreenStateLocked(true); if (err != 0) { Log.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err); @@ -1392,7 +1392,6 @@ class PowerManagerService extends IPowerManager.Stub reallyTurnScreenOn = false; } if (reallyTurnScreenOn) { - mAnimatingScreenOff = false; err = setScreenStateLocked(true); long identity = Binder.clearCallingIdentity(); try { @@ -1434,7 +1433,6 @@ class PowerManagerService extends IPowerManager.Stub if (!mScreenBrightness.animating) { err = screenOffFinishedAnimatingLocked(becauseOfUser); } else { - mAnimatingScreenOff = true; mOffBecauseOfUser = becauseOfUser; err = 0; mLastTouchDown = 0; @@ -1452,7 +1450,6 @@ class PowerManagerService extends IPowerManager.Stub mTotalTouchDownTime, mTouchCycles); mLastTouchDown = 0; int err = setScreenStateLocked(false); - mAnimatingScreenOff = false; if (mScreenOnStartTime != 0) { mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime; mScreenOnStartTime = 0; @@ -1825,9 +1822,6 @@ class PowerManagerService extends IPowerManager.Stub return; } - if (mAnimatingScreenOff) { - return; - } if (false) { if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) { Log.d(TAG, "userActivity !!!");//, new RuntimeException()); @@ -1845,6 +1839,11 @@ class PowerManagerService extends IPowerManager.Stub + " mProximitySensorActive=" + mProximitySensorActive + " force=" + force); } + // ignore user activity if we are in the process of turning off the screen + if (mScreenBrightness.animating && mScreenBrightness.targetValue == 0) { + Log.d(TAG, "ignoring user activity while turning off screen"); + return; + } if (mLastEventTime <= time || force) { mLastEventTime = time; if ((mUserActivityAllowed && !mProximitySensorActive) || force) { @@ -1925,27 +1924,45 @@ class PowerManagerService extends IPowerManager.Stub Log.d(TAG, "keyboardValue " + keyboardValue); } + boolean startAnimation = false; if (mScreenBrightnessOverride < 0) { - mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, - lcdValue); - } - mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, - buttonValue); - mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, - keyboardValue); - - // update our animation state - if (ANIMATE_SCREEN_LIGHTS) { - mScreenBrightness.curValue = lcdValue; - mScreenBrightness.animating = false; + if (ANIMATE_SCREEN_LIGHTS) { + if (mScreenBrightness.setTargetLocked(lcdValue, + AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS, + (int)mScreenBrightness.curValue)) { + startAnimation = true; + } + } else { + mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT, + lcdValue); + } } if (ANIMATE_BUTTON_LIGHTS) { - mButtonBrightness.curValue = buttonValue; - mButtonBrightness.animating = false; + if (mButtonBrightness.setTargetLocked(buttonValue, + AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS, + (int)mButtonBrightness.curValue)) { + startAnimation = true; + } + } else { + mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS, + buttonValue); } if (ANIMATE_KEYBOARD_LIGHTS) { - mKeyboardBrightness.curValue = keyboardValue; - mKeyboardBrightness.animating = false; + if (mKeyboardBrightness.setTargetLocked(keyboardValue, + AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS, + (int)mKeyboardBrightness.curValue)) { + startAnimation = true; + } + } else { + mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD, + keyboardValue); + } + if (startAnimation) { + if (mDebugLightSensor) { + Log.i(TAG, "lightSensorChangedLocked scheduling light animator"); + } + mHandler.removeCallbacks(mLightAnimator); + mHandler.post(mLightAnimator); } } } @@ -2041,6 +2058,7 @@ class PowerManagerService extends IPowerManager.Stub if (mAutoBrightessEnabled != enabled) { mAutoBrightessEnabled = enabled; // reset computed brightness + mLightSensorValue = -1; mLightSensorBrightness = -1; if (mHasHardwareAutoBrightness) { @@ -2263,14 +2281,17 @@ class PowerManagerService extends IPowerManager.Stub if (ANIMATE_SCREEN_LIGHTS) { mScreenBrightness.curValue = brightness; mScreenBrightness.animating = false; + mScreenBrightness.targetValue = -1; } if (ANIMATE_KEYBOARD_LIGHTS) { mKeyboardBrightness.curValue = brightness; mKeyboardBrightness.animating = false; + mKeyboardBrightness.targetValue = -1; } if (ANIMATE_BUTTON_LIGHTS) { mButtonBrightness.curValue = brightness; mButtonBrightness.animating = false; + mButtonBrightness.targetValue = -1; } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 1a7416a..5f30710 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -296,7 +296,7 @@ class ServerThread extends Thread { try { Log.i(TAG, "DropBox Service"); - ServiceManager.addService("dropbox", + ServiceManager.addService(Context.DROPBOX_SERVICE, new DropBoxService(context, new File("/data/system/dropbox"))); } catch (Throwable e) { Log.e(TAG, "Failure starting DropBox Service", e); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index ad1926e..56270f4 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -2705,13 +2705,31 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. - Configuration config = mWindowManager.updateOrientationFromAppTokens( - mConfiguration, - next.mayFreezeScreenLocked(next.app) ? next : null); - if (config != null) { - next.frozenBeforeDestroy = true; - } - if (!updateConfigurationLocked(config, next)) { + boolean updated; + synchronized (this) { + Configuration config = mWindowManager.updateOrientationFromAppTokens( + mConfiguration, + next.mayFreezeScreenLocked(next.app) ? next : null); + if (config != null) { + /* + * Explicitly restore the locale to the one from the + * old configuration, since the one that comes back from + * the window manager has the default (boot) locale. + * + * It looks like previously the locale picker only worked + * by coincidence: usually it would do its setting of + * the locale after the activity transition, so it didn't + * matter that this lost it. With the synchronized + * block now keeping them from happening at the same time, + * this one always would happen second and undo what the + * locale picker had just done. + */ + config.locale = mConfiguration.locale; + next.frozenBeforeDestroy = true; + } + updated = updateConfigurationLocked(config, next); + } + if (!updated) { // The configuration update wasn't able to keep the existing // instance of the activity, and instead started a new one. // We should be all done, but let's just make sure our activity diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 6b33f52..586f63f 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -1060,8 +1060,8 @@ public class PhoneNumberUtils * Breaks the given number down and formats it according to the rules * for the country the number is from. * - * @param source the phone number to format - * @return a locally acceptable formatting of the input, or the raw input if + * @param source The phone number to format + * @return A locally acceptable formatting of the input, or the raw input if * formatting rules aren't known for the number */ public static String formatNumber(String source) { @@ -1071,10 +1071,27 @@ public class PhoneNumberUtils } /** + * Formats the given number with the given formatting type. Currently + * {@link #FORMAT_NANP} and {@link #FORMAT_JAPAN} are supported as a formating type. + * + * @param source the phone number to format + * @param defaultFormattingType The default formatting rules to apply if the number does + * not begin with +<country_code> + * @return The phone number formatted with the given formatting type. + * + * @hide TODO:Shuold be unhidden. + */ + public static String formatNumber(String source, int defaultFormattingType) { + SpannableStringBuilder text = new SpannableStringBuilder(source); + formatNumber(text, defaultFormattingType); + return text.toString(); + } + + /** * Returns the phone number formatting type for the given locale. * * @param locale The locale of interest, usually {@link Locale#getDefault()} - * @return the formatting type for the given locale, or FORMAT_UNKNOWN if the formatting + * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting * rules are not known for the given locale */ public static int getFormatTypeForLocale(Locale locale) { @@ -1084,7 +1101,8 @@ public class PhoneNumberUtils } /** - * Formats a phone number in-place. Currently only supports NANP formatting. + * Formats a phone number in-place. Currently {@link #FORMAT_JAPAN} and {@link #FORMAT_NANP} + * is supported as a second argument. * * @param text The number to be formatted, will be modified with the formatting * @param defaultFormattingType The default formatting rules to apply if the number does diff --git a/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java b/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java index 439e0d8..286f702 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java @@ -19,8 +19,7 @@ package com.android.unit_tests; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.os.DropBoxEntry; -import android.os.IDropBox; +import android.os.DropBox; import android.os.ParcelFileDescriptor; import android.os.ServiceManager; import android.os.StatFs; @@ -36,7 +35,7 @@ import java.io.InputStream; import java.util.Random; import java.util.zip.GZIPOutputStream; -/** Test {@link IDropBox} functionality. */ +/** Test {@link DropBox} functionality. */ public class DropBoxTest extends AndroidTestCase { public void tearDown() throws Exception { Intent override = new Intent(Settings.Gservices.OVERRIDE_ACTION); @@ -47,7 +46,7 @@ public class DropBoxTest extends AndroidTestCase { } public void testAddText() throws Exception { - IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox")); + DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE); long before = System.currentTimeMillis(); Thread.sleep(5); dropbox.addText("DropBoxTest", "TEST0"); @@ -59,9 +58,9 @@ public class DropBoxTest extends AndroidTestCase { Thread.sleep(5); long after = System.currentTimeMillis(); - DropBoxEntry e0 = dropbox.getNextEntry("DropBoxTest", before); - DropBoxEntry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis()); - DropBoxEntry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()); + DropBox.Entry e0 = dropbox.getNextEntry("DropBoxTest", before); + DropBox.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis()); + DropBox.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()); assertTrue(null == dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis())); assertTrue(e0.getTimeMillis() > before); @@ -80,12 +79,12 @@ public class DropBoxTest extends AndroidTestCase { } public void testAddData() throws Exception { - IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox")); + DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE); long before = System.currentTimeMillis(); dropbox.addData("DropBoxTest", "TEST".getBytes(), 0); long after = System.currentTimeMillis(); - DropBoxEntry e = dropbox.getNextEntry("DropBoxTest", before); + DropBox.Entry e = dropbox.getNextEntry("DropBoxTest", before); assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis())); assertEquals("DropBoxTest", e.getTag()); @@ -123,7 +122,7 @@ public class DropBoxTest extends AndroidTestCase { os2.close(); gz3.close(); - IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox")); + DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE); int mode = ParcelFileDescriptor.MODE_READ_ONLY; ParcelFileDescriptor pfd0 = ParcelFileDescriptor.open(f0, mode); @@ -131,20 +130,20 @@ public class DropBoxTest extends AndroidTestCase { ParcelFileDescriptor pfd2 = ParcelFileDescriptor.open(f2, mode); ParcelFileDescriptor pfd3 = ParcelFileDescriptor.open(f3, mode); - dropbox.addFile("DropBoxTest", pfd0, DropBoxEntry.IS_TEXT); - dropbox.addFile("DropBoxTest", pfd1, DropBoxEntry.IS_TEXT | DropBoxEntry.IS_GZIPPED); + dropbox.addFile("DropBoxTest", pfd0, DropBox.IS_TEXT); + dropbox.addFile("DropBoxTest", pfd1, DropBox.IS_TEXT | DropBox.IS_GZIPPED); dropbox.addFile("DropBoxTest", pfd2, 0); - dropbox.addFile("DropBoxTest", pfd3, DropBoxEntry.IS_GZIPPED); + dropbox.addFile("DropBoxTest", pfd3, DropBox.IS_GZIPPED); pfd0.close(); pfd1.close(); pfd2.close(); pfd3.close(); - DropBoxEntry e0 = dropbox.getNextEntry("DropBoxTest", before); - DropBoxEntry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis()); - DropBoxEntry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()); - DropBoxEntry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()); + DropBox.Entry e0 = dropbox.getNextEntry("DropBoxTest", before); + DropBox.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis()); + DropBox.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()); + DropBox.Entry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()); assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis())); assertTrue(e0.getTimeMillis() > before); @@ -152,8 +151,8 @@ public class DropBoxTest extends AndroidTestCase { assertTrue(e2.getTimeMillis() > e1.getTimeMillis()); assertTrue(e3.getTimeMillis() > e2.getTimeMillis()); - assertEquals(DropBoxEntry.IS_TEXT, e0.getFlags()); - assertEquals(DropBoxEntry.IS_TEXT, e1.getFlags()); + assertEquals(DropBox.IS_TEXT, e0.getFlags()); + assertEquals(DropBox.IS_TEXT, e1.getFlags()); assertEquals(0, e2.getFlags()); assertEquals(0, e3.getFlags()); @@ -199,13 +198,14 @@ public class DropBoxTest extends AndroidTestCase { // Tombstone in the far future new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close(); - DropBoxService dropbox = new DropBoxService(getContext(), dir); + DropBoxService service = new DropBoxService(getContext(), dir); + DropBox dropbox = new DropBox(service); // Until a write, the timestamps are taken at face value - DropBoxEntry e0 = dropbox.getNextEntry(null, before); - DropBoxEntry e1 = dropbox.getNextEntry(null, e0.getTimeMillis()); - DropBoxEntry e2 = dropbox.getNextEntry(null, e1.getTimeMillis()); - DropBoxEntry e3 = dropbox.getNextEntry(null, e2.getTimeMillis()); + DropBox.Entry e0 = dropbox.getNextEntry(null, before); + DropBox.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis()); + DropBox.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis()); + DropBox.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis()); assertTrue(null == dropbox.getNextEntry(null, e3.getTimeMillis())); assertEquals("FUTURE0", e0.getText(80)); @@ -245,11 +245,11 @@ public class DropBoxTest extends AndroidTestCase { e1.close(); e2.close(); e3.close(); - dropbox.stop(); + service.stop(); } public void testIsTagEnabled() throws Exception { - IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox")); + DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE); long before = System.currentTimeMillis(); dropbox.addText("DropBoxTest", "TEST-ENABLED"); assertTrue(dropbox.isTagEnabled("DropBoxTest")); @@ -268,8 +268,8 @@ public class DropBoxTest extends AndroidTestCase { dropbox.addText("DropBoxTest", "TEST-ENABLED-AGAIN"); assertTrue(dropbox.isTagEnabled("DropBoxTest")); - DropBoxEntry e0 = dropbox.getNextEntry("DropBoxTest", before); - DropBoxEntry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis()); + DropBox.Entry e0 = dropbox.getNextEntry("DropBoxTest", before); + DropBox.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis()); assertTrue(null == dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis())); assertEquals("TEST-ENABLED", e0.getText(80)); @@ -281,23 +281,24 @@ public class DropBoxTest extends AndroidTestCase { public void testGetNextEntry() throws Exception { File dir = getEmptyDir("testGetNextEntry"); - DropBoxService dropbox = new DropBoxService(getContext(), dir); + DropBoxService service = new DropBoxService(getContext(), dir); + DropBox dropbox = new DropBox(service); long before = System.currentTimeMillis(); dropbox.addText("DropBoxTest.A", "A0"); dropbox.addText("DropBoxTest.B", "B0"); dropbox.addText("DropBoxTest.A", "A1"); - DropBoxEntry a0 = dropbox.getNextEntry("DropBoxTest.A", before); - DropBoxEntry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis()); + DropBox.Entry a0 = dropbox.getNextEntry("DropBoxTest.A", before); + DropBox.Entry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis()); assertTrue(null == dropbox.getNextEntry("DropBoxTest.A", a1.getTimeMillis())); - DropBoxEntry b0 = dropbox.getNextEntry("DropBoxTest.B", before); + DropBox.Entry b0 = dropbox.getNextEntry("DropBoxTest.B", before); assertTrue(null == dropbox.getNextEntry("DropBoxTest.B", b0.getTimeMillis())); - DropBoxEntry x0 = dropbox.getNextEntry(null, before); - DropBoxEntry x1 = dropbox.getNextEntry(null, x0.getTimeMillis()); - DropBoxEntry x2 = dropbox.getNextEntry(null, x1.getTimeMillis()); + DropBox.Entry x0 = dropbox.getNextEntry(null, before); + DropBox.Entry x1 = dropbox.getNextEntry(null, x0.getTimeMillis()); + DropBox.Entry x2 = dropbox.getNextEntry(null, x1.getTimeMillis()); assertTrue(null == dropbox.getNextEntry(null, x2.getTimeMillis())); assertEquals("DropBoxTest.A", a0.getTag()); @@ -321,7 +322,7 @@ public class DropBoxTest extends AndroidTestCase { x0.close(); x1.close(); x2.close(); - dropbox.stop(); + service.stop(); } public void testSizeLimits() throws Exception { @@ -344,7 +345,9 @@ public class DropBoxTest extends AndroidTestCase { final int overhead = 64; long before = System.currentTimeMillis(); - DropBoxService dropbox = new DropBoxService(getContext(), dir); + DropBoxService service = new DropBoxService(getContext(), dir); + DropBox dropbox = new DropBox(service); + addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead); addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead); @@ -358,16 +361,16 @@ public class DropBoxTest extends AndroidTestCase { addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead); addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead); - DropBoxEntry e0 = dropbox.getNextEntry(null, before); - DropBoxEntry e1 = dropbox.getNextEntry(null, e0.getTimeMillis()); - DropBoxEntry e2 = dropbox.getNextEntry(null, e1.getTimeMillis()); - DropBoxEntry e3 = dropbox.getNextEntry(null, e2.getTimeMillis()); - DropBoxEntry e4 = dropbox.getNextEntry(null, e3.getTimeMillis()); - DropBoxEntry e5 = dropbox.getNextEntry(null, e4.getTimeMillis()); - DropBoxEntry e6 = dropbox.getNextEntry(null, e5.getTimeMillis()); - DropBoxEntry e7 = dropbox.getNextEntry(null, e6.getTimeMillis()); - DropBoxEntry e8 = dropbox.getNextEntry(null, e7.getTimeMillis()); - DropBoxEntry e9 = dropbox.getNextEntry(null, e8.getTimeMillis()); + DropBox.Entry e0 = dropbox.getNextEntry(null, before); + DropBox.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis()); + DropBox.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis()); + DropBox.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis()); + DropBox.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis()); + DropBox.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis()); + DropBox.Entry e6 = dropbox.getNextEntry(null, e5.getTimeMillis()); + DropBox.Entry e7 = dropbox.getNextEntry(null, e6.getTimeMillis()); + DropBox.Entry e8 = dropbox.getNextEntry(null, e7.getTimeMillis()); + DropBox.Entry e9 = dropbox.getNextEntry(null, e8.getTimeMillis()); assertTrue(null == dropbox.getNextEntry(null, e9.getTimeMillis())); assertEquals("DropBoxTest0", e0.getTag()); @@ -406,9 +409,9 @@ public class DropBoxTest extends AndroidTestCase { // Specifying a tag name skips tombstone records. - DropBoxEntry t0 = dropbox.getNextEntry("DropBoxTest1", before); - DropBoxEntry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis()); - DropBoxEntry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis()); + DropBox.Entry t0 = dropbox.getNextEntry("DropBoxTest1", before); + DropBox.Entry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis()); + DropBox.Entry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis()); assertTrue(null == dropbox.getNextEntry("DropBoxTest1", t2.getTimeMillis())); assertEquals("DropBoxTest1", t0.getTag()); @@ -422,7 +425,7 @@ public class DropBoxTest extends AndroidTestCase { t0.close(); t1.close(); t2.close(); - dropbox.stop(); + service.stop(); } public void testAgeLimits() throws Exception { @@ -438,13 +441,15 @@ public class DropBoxTest extends AndroidTestCase { // Write one normal entry and another so big that it is instantly tombstoned long before = System.currentTimeMillis(); - DropBoxService dropbox = new DropBoxService(getContext(), dir); + DropBoxService service = new DropBoxService(getContext(), dir); + DropBox dropbox = new DropBox(service); + dropbox.addText("DropBoxTest", "TEST"); addRandomEntry(dropbox, "DropBoxTest", blockSize * 20); // Verify that things are as expected - DropBoxEntry e0 = dropbox.getNextEntry(null, before); - DropBoxEntry e1 = dropbox.getNextEntry(null, e0.getTimeMillis()); + DropBox.Entry e0 = dropbox.getNextEntry(null, before); + DropBox.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis()); assertTrue(null == dropbox.getNextEntry(null, e1.getTimeMillis())); assertEquals("TEST", e0.getText(80)); @@ -471,7 +476,8 @@ public class DropBoxTest extends AndroidTestCase { File dir = new File(getEmptyDir("testCreateDropBoxWith"), "InvalidDirectory"); new FileOutputStream(dir).close(); // Create an empty file - DropBoxService dropbox = new DropBoxService(getContext(), dir); + DropBoxService service = new DropBoxService(getContext(), dir); + DropBox dropbox = new DropBox(service); dropbox.addText("DropBoxTest", "should be ignored"); dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0); @@ -479,15 +485,15 @@ public class DropBoxTest extends AndroidTestCase { dir.delete(); // Remove the file so a directory can be created dropbox.addText("DropBoxTest", "TEST"); - DropBoxEntry e = dropbox.getNextEntry("DropBoxTest", 0); + DropBox.Entry e = dropbox.getNextEntry("DropBoxTest", 0); assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis())); assertEquals("DropBoxTest", e.getTag()); assertEquals("TEST", e.getText(80)); e.close(); - dropbox.stop(); + service.stop(); } - private void addRandomEntry(IDropBox dropbox, String tag, int size) throws Exception { + private void addRandomEntry(DropBox dropbox, String tag, int size) throws Exception { byte[] bytes = new byte[size]; new Random(System.currentTimeMillis()).nextBytes(bytes); @@ -501,7 +507,7 @@ public class DropBoxTest extends AndroidTestCase { fd.close(); } - private int getEntrySize(DropBoxEntry e) throws Exception { + private int getEntrySize(DropBox.Entry e) throws Exception { InputStream is = e.getInputStream(); if (is == null) return -1; int length = 0; diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java index d0097c4..cfa9ab3 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java @@ -643,9 +643,6 @@ public class VCardExporterTests extends AndroidTestCase { testStructuredNameUseSuperPrimaryCommon(V30); } - /** - * There's no property for nickname in vCard 2.1, so we don't have any requirement on it. - */ public void testNickNameV30() { ExportTestResolver resolver = new ExportTestResolver(); ContentValues contentValues = resolver.buildData(Nickname.CONTENT_ITEM_TYPE); @@ -1269,4 +1266,23 @@ public class VCardExporterTests extends AndroidTestCase { verifyOneComposition(resolver, handler, version); } + + /** + * There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0. + * We use Android-specific "X-ANDROID-CUSTOM" property. + * This test verifies the functionality. + */ + public void testNickNameV21() { + ExportTestResolver resolver = new ExportTestResolver(); + ContentValues contentValues = resolver.buildData(Nickname.CONTENT_ITEM_TYPE); + contentValues.put(Nickname.NAME, "Nicky"); + + VCardVerificationHandler handler = new VCardVerificationHandler(this, V21); + handler.addNewVerifierWithEmptyName() + .addNodeWithOrder("X-ANDROID-CUSTOM", Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;"); + + // TODO: also test import part. + + verifyOneComposition(resolver, handler, V21); + } } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java index 50b7c3f..9bc0962 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java @@ -74,6 +74,8 @@ public class ReliabilityTest extends ActivityInstrumentationTestCase2<Reliabilit Intent intent = new Intent(runner.getContext(), ReliabilityTestActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ReliabilityTestActivity activity = (ReliabilityTestActivity)runner.startActivitySync( + intent); //read from BufferedReader instead of populating a list in advance, //this will avoid excessive memory usage in case of a large list while((url = listReader.readLine()) != null) { @@ -83,8 +85,6 @@ public class ReliabilityTest extends ActivityInstrumentationTestCase2<Reliabilit start = System.currentTimeMillis(); Log.v(LOGTAG, "Testing URL: " + url); FsUtils.updateTestStatus(TEST_STATUS_FILE, url); - ReliabilityTestActivity activity = (ReliabilityTestActivity)runner.startActivitySync( - intent); activity.reset(); //use message to send new URL to avoid interacting with //WebView in non-UI thread @@ -110,11 +110,11 @@ public class ReliabilityTest extends ActivityInstrumentationTestCase2<Reliabilit if(runner.mLogtime) { writeLoadTime(url, activity.getPageLoadTime()); } - activity.finish(); System.runFinalization(); System.gc(); System.gc(); } + activity.finish(); FsUtils.updateTestStatus(TEST_STATUS_FILE, TEST_DONE); // activity.finish(); listReader.close(); |
