diff options
29 files changed, 338 insertions, 129 deletions
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index afda98d..b624402 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -88,8 +88,10 @@ import android.os.FileUtils.FileStatus; import android.telephony.TelephonyManager; import android.text.ClipboardManager; import android.util.AndroidRuntimeException; +import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextThemeWrapper; +import android.view.Display; import android.view.LayoutInflater; import android.view.WindowManagerImpl; import android.view.accessibility.AccessibilityManager; @@ -151,6 +153,7 @@ class ReceiverRestrictedContext extends ContextWrapper { */ class ApplicationContext extends Context { private final static String TAG = "ApplicationContext"; + private final static boolean DEBUG = false; private final static boolean DEBUG_ICONS = false; private static final Object sSync = new Object(); @@ -1254,7 +1257,7 @@ class ApplicationContext extends Context { @Override public int checkUriPermission(Uri uri, String readPermission, String writePermission, int pid, int uid, int modeFlags) { - if (false) { + if (DEBUG) { Log.i("foo", "checkUriPermission: uri=" + uri + "readPermission=" + readPermission + " writePermission=" + writePermission + " pid=" + pid + " uid=" + uid + " mode" + modeFlags); @@ -1356,6 +1359,19 @@ class ApplicationContext extends Context { c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; c.init(pi, null, mMainThread); if (c.mResources != null) { + Resources newRes = c.mResources; + if (mResources.getCompatibilityInfo().applicationScale != + newRes.getCompatibilityInfo().applicationScale) { + DisplayMetrics dm = mMainThread.getDisplayMetricsLocked(false); + c.mResources = new Resources(newRes.getAssets(), dm, + newRes.getConfiguration(), + mResources.getCompatibilityInfo().copy()); + if (DEBUG) { + Log.d(TAG, "loaded context has different scaling. Using container's" + + " compatiblity info:" + mResources.getDisplayMetrics()); + } + + } return c; } } @@ -1475,7 +1491,7 @@ class ApplicationContext extends Context { if ((mode&MODE_WORLD_WRITEABLE) != 0) { perms |= FileUtils.S_IWOTH; } - if (false) { + if (DEBUG) { Log.i(TAG, "File " + name + ": mode=0x" + Integer.toHexString(mode) + ", perms=0x" + Integer.toHexString(perms)); } diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java index 5b4ac0d..34a1a0c 100644 --- a/core/java/android/backup/BackupManager.java +++ b/core/java/android/backup/BackupManager.java @@ -19,6 +19,7 @@ package android.backup; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; +import android.util.Log; /** * BackupManager is the interface to the system's backup service. @@ -39,14 +40,17 @@ import android.os.ServiceManager; * @hide pending API solidification */ public class BackupManager { + private static final String TAG = "BackupManager"; + private Context mContext; - private IBackupManager mService; + private static IBackupManager sService; - /** - * Defined backup transports understood by {@link IBackupManager.selectBackupTransport}. - */ - public static final int TRANSPORT_LOCAL = 1; - public static final int TRANSPORT_GOOGLE = 2; + private static void checkServiceBinder() { + if (sService == null) { + sService = IBackupManager.Stub.asInterface( + ServiceManager.getService(Context.BACKUP_SERVICE)); + } + } /** * Constructs a BackupManager object through which the application can @@ -58,8 +62,6 @@ public class BackupManager { */ public BackupManager(Context context) { mContext = context; - mService = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); } /** @@ -68,10 +70,31 @@ public class BackupManager { * {@link android.app.BackupAgent} subclass will be scheduled when you call this method. */ public void dataChanged() { - if (mService != null) { + checkServiceBinder(); + if (sService != null) { + try { + sService.dataChanged(mContext.getPackageName()); + } catch (RemoteException e) { + Log.d(TAG, "dataChanged() couldn't connect"); + } + } + } + + /** + * Convenience method for callers who need to indicate that some other package + * needs a backup pass. This can be relevant in the case of groups of packages + * that share a uid, for example. + * + * This method requires that the application hold the "android.permission.BACKUP" + * permission if the package named in the argument is not the caller's own. + */ + public static void dataChanged(String packageName) { + checkServiceBinder(); + if (sService != null) { try { - mService.dataChanged(mContext.getPackageName()); + sService.dataChanged(packageName); } catch (RemoteException e) { + Log.d(TAG, "dataChanged(pkg) couldn't connect"); } } } @@ -85,10 +108,12 @@ public class BackupManager { */ public IRestoreSession beginRestoreSession(String transport) { IRestoreSession binder = null; - if (mService != null) { + checkServiceBinder(); + if (sService != null) { try { - binder = mService.beginRestoreSession(transport); + binder = sService.beginRestoreSession(transport); } catch (RemoteException e) { + Log.d(TAG, "beginRestoreSession() couldn't connect"); } } return binder; diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 4e6fe07..dfe304d 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -159,15 +159,33 @@ public class CompatibilityInfo { } } + private CompatibilityInfo(int appFlags, int compFlags, float scale, float invertedScale) { + this.appFlags = appFlags; + mCompatibilityFlags = compFlags; + applicationScale = scale; + applicationInvertedScale = invertedScale; + } + private CompatibilityInfo() { - appFlags = ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS + this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS - | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; - applicationScale = applicationInvertedScale = 1.0f; - mCompatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE; + | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS, + EXPANDABLE | CONFIGURED_EXPANDABLE, + 1.0f, + 1.0f); } /** + * Returns the copy of this instance. + */ + public CompatibilityInfo copy() { + CompatibilityInfo info = new CompatibilityInfo(appFlags, mCompatibilityFlags, + applicationScale, applicationInvertedScale); + info.setVisibleRect(mXOffset, mWidth, mHeight); + return info; + } + + /** * Sets the application's visible rect in compatibility mode. * @param xOffset the application's x offset that is added to center the content. * @param widthPixels the application's width in real pixels on the screen. @@ -470,4 +488,4 @@ public class CompatibilityInfo { return mVisibleInsets; } } -}
\ No newline at end of file +} diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index d7512bb..49ad656 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -129,7 +129,7 @@ public class Resources { */ public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) { - this(assets, metrics, config, null); + this(assets, metrics, config, (ApplicationInfo) null); } /** @@ -166,6 +166,26 @@ public class Resources { } /** + * Creates a new resources that uses the given compatibility info. Used to create + * a context for widgets using the container's compatibility info. + * {@see ApplicationContext#createPackageCotnext}. + * @hide + */ + public Resources(AssetManager assets, DisplayMetrics metrics, + Configuration config, CompatibilityInfo info) { + mAssets = assets; + mMetrics.setToDefaults(); + mCompatibilityInfo = info; + updateConfiguration(config, metrics); + assets.ensureStringBlocks(); + if (mCompatibilityInfo.isScalingRequired()) { + mPreloadedDrawables = emptySparseArray(); + } else { + mPreloadedDrawables = sPreloadedDrawables; + } + } + + /** * Return a global shared Resources object that provides access to only * system resources (no application resources), and is not configured for * the current screen (can not use dimension units, does not change based diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index fca318e..5f90071 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2693,6 +2693,12 @@ public final class Settings { public static final String GMAIL_DISCARD_ERROR_UPHILL_OP = "gmail_discard_error_uphill_op"; /** + * Controls how many attempts Gmail will try to upload an uphill operations before it + * abandons the operation. Defaults to 20. + */ + public static final String GMAIL_NUM_RETRY_UPHILL_OP = "gmail_discard_error_uphill_op"; + + /** * the transcoder URL for mobile devices. */ public static final String TRANSCODER_URL = "mobile_transcoder_url"; diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java index 7c87248..0f0be79 100644 --- a/core/java/android/util/EventLog.java +++ b/core/java/android/util/EventLog.java @@ -73,7 +73,7 @@ import java.util.List; * </ul> * </li> * <li> '\n': 1 byte - an automatically generated newline, used to help detect and recover from log - * corruption and enable stansard unix tools like grep, tail and wc to operate + * corruption and enable standard unix tools like grep, tail and wc to operate * on event logs. </li> * </ul> * @@ -289,4 +289,13 @@ public class EventLog { */ public static native void readEvents(int[] tags, Collection<Event> output) throws IOException; + + /** + * Read events from a file. + * @param path to read from + * @param output container to add events into + * @throws IOException if something goes wrong reading events + */ + public static native void readEvents(String path, Collection<Event> output) + throws IOException; } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index a12b14a..41cc86a 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -553,13 +553,16 @@ public final class ViewRoot extends Handler implements ViewParent, if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty); if (mCurScrollY != 0 || mTranslator != null) { mTempRect.set(dirty); + dirty = mTempRect; if (mCurScrollY != 0) { - mTempRect.offset(0, -mCurScrollY); + dirty.offset(0, -mCurScrollY); } if (mTranslator != null) { - mTranslator.translateRectInAppWindowToScreen(mTempRect); + mTranslator.translateRectInAppWindowToScreen(dirty); + } + if (mAttachInfo.mScalingRequired) { + dirty.inset(-1, -1); } - dirty = mTempRect; } mDirty.union(dirty); if (!mWillDrawSoon) { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index b2f2e51..899d636 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -3024,7 +3024,12 @@ public class WebView extends AbsoluteLayout */ /* package */ void deleteSelection(int start, int end) { mTextGeneration++; - mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, start, end); + WebViewCore.DeleteSelectionData data + = new WebViewCore.DeleteSelectionData(); + data.mStart = start; + data.mEnd = end; + data.mTextGeneration = mTextGeneration; + mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, data); } /** @@ -4672,6 +4677,7 @@ public class WebView extends AbsoluteLayout arg.mNewStart = newStart; arg.mNewEnd = newEnd; mTextGeneration++; + arg.mTextGeneration = mTextGeneration; mWebViewCore.sendMessage(EventHub.REPLACE_TEXT, oldStart, oldEnd, arg); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 44d8b7e..20f7239 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -370,7 +370,8 @@ final class WebViewCore { // Start: functions that deal with text editing private native void nativeReplaceTextfieldText( - int oldStart, int oldEnd, String replace, int newStart, int newEnd); + int oldStart, int oldEnd, String replace, int newStart, int newEnd, + int textGeneration); private native void passToJs(int gen, String currentText, int keyCode, int keyValue, boolean down, @@ -415,8 +416,10 @@ final class WebViewCore { * order, swap them. * @param start Beginning of selection to delete. * @param end End of selection to delete. + * @param textGeneration Text generation number when delete was pressed. */ - private native void nativeDeleteSelection(int start, int end); + private native void nativeDeleteSelection(int start, int end, + int textGeneration); /** * Set the selection to (start, end) in the focused textfield. If start and @@ -551,10 +554,17 @@ final class WebViewCore { byte[] mPostData; } + static class DeleteSelectionData { + int mStart; + int mEnd; + int mTextGeneration; + } + static class ReplaceTextData { String mReplace; int mNewStart; int mNewEnd; + int mTextGeneration; } static class TouchUpData { @@ -920,7 +930,8 @@ final class WebViewCore { case REPLACE_TEXT: ReplaceTextData rep = (ReplaceTextData) msg.obj; nativeReplaceTextfieldText(msg.arg1, msg.arg2, - rep.mReplace, rep.mNewStart, rep.mNewEnd); + rep.mReplace, rep.mNewStart, rep.mNewEnd, + rep.mTextGeneration); break; case PASS_TO_JS: { @@ -1029,7 +1040,11 @@ final class WebViewCore { break; case DELETE_SELECTION: - nativeDeleteSelection(msg.arg1, msg.arg2); + DeleteSelectionData deleteSelectionData + = (DeleteSelectionData) msg.obj; + nativeDeleteSelection(deleteSelectionData.mStart, + deleteSelectionData.mEnd, + deleteSelectionData.mTextGeneration); break; case SET_SELECTION: diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 0cce3a6..cf3ba7f 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -539,16 +539,17 @@ static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobjec // ---------------------------------------------------------------------------- -static void android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz, +static jint android_media_AudioTrack_set_playback_rate(JNIEnv *env, jobject thiz, jint sampleRateInHz) { AudioTrack *lpTrack = (AudioTrack *)env->GetIntField( thiz, javaAudioTrackFields.nativeTrackInJavaObj); if (lpTrack) { - lpTrack->setSampleRate(sampleRateInHz); + return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz)); } else { jniThrowException(env, "java/lang/IllegalStateException", "Unable to retrieve AudioTrack pointer for setSampleRate()"); + return AUDIOTRACK_ERROR; } } @@ -788,7 +789,7 @@ static JNINativeMethod gMethods[] = { {"native_get_native_frame_count", "()I", (void *)android_media_AudioTrack_get_native_frame_count}, {"native_set_playback_rate", - "(I)V", (void *)android_media_AudioTrack_set_playback_rate}, + "(I)I", (void *)android_media_AudioTrack_set_playback_rate}, {"native_get_playback_rate", "()I", (void *)android_media_AudioTrack_get_playback_rate}, {"native_set_marker_pos","(I)I", (void *)android_media_AudioTrack_set_marker_pos}, diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp index 5e5103a..34b7c89 100644 --- a/core/jni/android_util_EventLog.cpp +++ b/core/jni/android_util_EventLog.cpp @@ -51,17 +51,17 @@ struct ByteBuf { size_t len; size_t capacity; uint8_t* buf; - + ByteBuf(size_t initSize) { buf = (uint8_t*)malloc(initSize); len = 0; - capacity = initSize; + capacity = initSize; } - + ~ByteBuf() { free(buf); } - + bool ensureExtraCapacity(size_t extra) { size_t spaceNeeded = len + extra; if (spaceNeeded > capacity) { @@ -77,7 +77,7 @@ struct ByteBuf { return true; } } - + void putIntEvent(jint value) { bool succeeded = ensureExtraCapacity(INT_BUFFER_SIZE); buf[len++] = EVENT_TYPE_INT; @@ -162,7 +162,7 @@ static jint android_util_EventLog_writeEvent_Integer(JNIEnv* env, jobject clazz, * In class android.util.EventLog: * static native int writeEvent(long tag, long value) */ -static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz, +static jint android_util_EventLog_writeEvent_Long(JNIEnv* env, jobject clazz, jint tag, jlong value) { return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value)); @@ -210,6 +210,8 @@ static jint android_util_EventLog_writeEvent_String(JNIEnv* env, jobject clazz, /* * In class android.util.EventLog: * static native void readEvents(int[] tags, Collection<Event> output) + * + * Reads events from the event log, typically /dev/log/events */ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz, jintArray tags, @@ -273,6 +275,80 @@ static void android_util_EventLog_readEvents(JNIEnv* env, jobject clazz, env->ReleaseIntArrayElements(tags, tagValues, 0); } +/* + * In class android.util.EventLog: + * static native void readEvents(String path, Collection<Event> output) + * + * Reads events from a file (See Checkin.Aggregation). Events are stored in + * native raw format (logger_entry + payload). + */ +static void android_util_EventLog_readEventsFile(JNIEnv* env, jobject clazz, jstring path, + jobject out) { + if (path == NULL || out == NULL) { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return; + } + + const char *pathString = env->GetStringUTFChars(path, 0); + int fd = open(pathString, O_RDONLY | O_NONBLOCK); + env->ReleaseStringUTFChars(path, pathString); + + if (fd < 0) { + jniThrowIOException(env, errno); + return; + } + + uint8_t buf[LOGGER_ENTRY_MAX_LEN]; + for (;;) { + // read log entry structure from file + int len = read(fd, buf, sizeof(logger_entry)); + if (len == 0) { + break; // end of file + } else if (len < 0) { + jniThrowIOException(env, errno); + } else if ((size_t) len < sizeof(logger_entry)) { + jniThrowException(env, "java/io/IOException", "Event header too short"); + break; + } + + // read event payload + logger_entry* entry = (logger_entry*) buf; + if (entry->len > LOGGER_ENTRY_MAX_PAYLOAD) { + jniThrowException(env, + "java/lang/IllegalArgumentException", + "Too much data for event payload. Corrupt file?"); + break; + } + + len = read(fd, buf + sizeof(logger_entry), entry->len); + if (len == 0) { + break; // end of file + } else if (len < 0) { + jniThrowIOException(env, errno); + } else if ((size_t) len < entry->len) { + jniThrowException(env, "java/io/IOException", "Event payload too short"); + break; + } + + // create EventLog$Event and add it to the collection + int buffer_size = sizeof(logger_entry) + entry->len; + jbyteArray array = env->NewByteArray(buffer_size); + if (array == NULL) break; + + jbyte *bytes = env->GetByteArrayElements(array, NULL); + memcpy(bytes, buf, buffer_size); + env->ReleaseByteArrayElements(array, bytes, 0); + + jobject event = env->NewObject(gEventClass, gEventInitID, array); + if (event == NULL) break; + + env->CallBooleanMethod(out, gCollectionAddID, event); + env->DeleteLocalRef(event); + env->DeleteLocalRef(array); + } + + close(fd); +} /* * JNI registration. @@ -292,6 +368,10 @@ static JNINativeMethod gRegisterMethods[] = { { "readEvents", "([ILjava/util/Collection;)V", (void*) android_util_EventLog_readEvents + }, + { "readEvents", + "(Ljava/lang/String;Ljava/util/Collection;)V", + (void*) android_util_EventLog_readEventsFile } }; diff --git a/core/res/res/drawable/rate_star_big_half.png b/core/res/res/drawable/rate_star_big_half.png Binary files differindex e73ca79..9762292 100644 --- a/core/res/res/drawable/rate_star_big_half.png +++ b/core/res/res/drawable/rate_star_big_half.png diff --git a/core/res/res/drawable/rate_star_big_off.png b/core/res/res/drawable/rate_star_big_off.png Binary files differindex b4dfa9d..6b5039f 100644 --- a/core/res/res/drawable/rate_star_big_off.png +++ b/core/res/res/drawable/rate_star_big_off.png diff --git a/core/res/res/drawable/rate_star_big_on.png b/core/res/res/drawable/rate_star_big_on.png Binary files differindex 7442c93..a972db2 100644 --- a/core/res/res/drawable/rate_star_big_on.png +++ b/core/res/res/drawable/rate_star_big_on.png diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index 106807e..83ff508 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -197,7 +197,6 @@ public: /* getters, see constructor */ - uint32_t sampleRate() const; int format() const; int channelCount() const; uint32_t frameCount() const; @@ -217,7 +216,7 @@ public: status_t stop(); bool stopped() const; - /* get sample rate for this track + /* get sample rate for this record track */ uint32_t getSampleRate(); @@ -323,7 +322,6 @@ private: sp<ClientRecordThread> mClientRecordThread; Mutex mRecordThreadLock; - uint32_t mSampleRate; uint32_t mFrameCount; audio_track_cblk_t* mCblk; diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 0955819..2e1fbda 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -201,7 +201,6 @@ public: /* getters, see constructor */ int streamType() const; - uint32_t sampleRate() const; int format() const; int channelCount() const; uint32_t frameCount() const; @@ -246,7 +245,7 @@ public: /* set sample rate for this track, mostly used for games' sound effects */ - void setSampleRate(int sampleRate); + status_t setSampleRate(int sampleRate); uint32_t getSampleRate(); /* Enables looping and sets the start and end points of looping. diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index bda969c..496a739 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -26,7 +26,6 @@ namespace android { // ---------------------------------------------------------------------------- -#define MAX_SAMPLE_RATE 65535 #define THREAD_PRIORITY_AUDIO_CLIENT (ANDROID_PRIORITY_AUDIO) // Maximum cumulated timeout milliseconds before restarting audioflinger thread #define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP init time @@ -55,9 +54,9 @@ struct audio_track_cblk_t uint16_t volume[2]; uint32_t volumeLR; }; - uint16_t sampleRate; - uint16_t channels; - int16_t flowControlFlag; // underrun (out) or overrrun (in) indication + uint32_t sampleRate; + uint8_t channels; + uint8_t flowControlFlag; // underrun (out) or overrrun (in) indication uint8_t out; // out equals 1 for AudioTrack and 0 for AudioRecord uint8_t forceReady; uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger diff --git a/include/utils/List.h b/include/utils/List.h index 4041a89..403cd7f 100644 --- a/include/utils/List.h +++ b/include/utils/List.h @@ -154,9 +154,9 @@ protected: inline _NodePtr getNode() const { return mpNode; } + _NodePtr mpNode; /* should be private, but older gcc fails */ private: friend class List; - _NodePtr mpNode; }; public: diff --git a/libs/audioflinger/AudioBufferProvider.h b/libs/audioflinger/AudioBufferProvider.h index 1a467c7..81c5c39 100644 --- a/libs/audioflinger/AudioBufferProvider.h +++ b/libs/audioflinger/AudioBufferProvider.h @@ -36,6 +36,8 @@ public: }; size_t frameCount; }; + + virtual ~AudioBufferProvider() {} virtual status_t getNextBuffer(Buffer* buffer) = 0; virtual void releaseBuffer(Buffer* buffer) = 0; diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index a5b91f6..82289dd 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -1288,7 +1288,7 @@ sp<AudioFlinger::MixerThread::Track> AudioFlinger::MixerThread::createTrack_l( status_t lStatus; // Resampler implementation limits input sampling rate to 2 x output sampling rate. - if (sampleRate > MAX_SAMPLE_RATE || sampleRate > mSampleRate*2) { + if (sampleRate > mSampleRate*2) { LOGE("Sample rate out of range: %d mSampleRate %d", sampleRate, mSampleRate); lStatus = BAD_VALUE; goto Exit; @@ -1603,8 +1603,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( new(mCblk) audio_track_cblk_t(); // clear all buffers mCblk->frameCount = frameCount; - mCblk->sampleRate = (uint16_t)sampleRate; - mCblk->channels = (uint16_t)channelCount; + mCblk->sampleRate = sampleRate; + mCblk->channels = (uint8_t)channelCount; if (sharedBuffer == 0) { mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); @@ -1627,8 +1627,8 @@ AudioFlinger::MixerThread::TrackBase::TrackBase( new(mCblk) audio_track_cblk_t(); // clear all buffers mCblk->frameCount = frameCount; - mCblk->sampleRate = (uint16_t)sampleRate; - mCblk->channels = (uint16_t)channelCount; + mCblk->sampleRate = sampleRate; + mCblk->channels = (uint8_t)channelCount; mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t); memset(mBuffer, 0, frameCount*channelCount*sizeof(int16_t)); // Force underrun condition to avoid false underrun callback until first data is @@ -1689,7 +1689,7 @@ int AudioFlinger::MixerThread::TrackBase::sampleRate() const { } int AudioFlinger::MixerThread::TrackBase::channelCount() const { - return mCblk->channels; + return (int)mCblk->channels; } void* AudioFlinger::MixerThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { @@ -2274,12 +2274,6 @@ sp<IAudioRecord> AudioFlinger::openRecord( goto Exit; } - if (sampleRate > MAX_SAMPLE_RATE) { - LOGE("Sample rate out of range"); - lStatus = BAD_VALUE; - goto Exit; - } - if (mAudioRecordThread == 0) { LOGE("Audio record thread not started"); lStatus = NO_INIT; diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 3cd841d..5f1be9d 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -425,8 +425,7 @@ public class AudioTrack } /** - * Returns the current playback rate in Hz. Note that this rate may differ from the one set - * with {@link #setPlaybackRate(int)} as the value effectively used is implementation-dependent. + * Returns the current playback rate in Hz. */ public int getPlaybackRate() { return native_get_playback_rate(); @@ -651,18 +650,13 @@ public class AudioTrack * Sets the playback sample rate for this track. This sets the sampling rate at which * the audio data will be consumed and played back, not the original sampling rate of the * content. Setting it to half the sample rate of the content will cause the playback to - * last twice as long, but will also result result in a negative pitch shift. - * The current implementation supports a maximum sample rate of 64kHz. - * Use {@link #getSampleRate()} to check the rate actually used in hardware after - * potential clamping. + * last twice as long, but will also result in a negative pitch shift. + * The valid sample rate range if from 1Hz to twice the value returned by + * {@link #getNativeOutputSampleRate(int)}. * @param sampleRateInHz the sample rate expressed in Hz * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, * {@link #ERROR_INVALID_OPERATION} */ - // FIXME: the implementation should support twice the hardware output sample rate - // (see {@link #getNativeOutputSampleRate(int)}), but currently - // due to the representation of the sample rate in the native layer, the sample rate - // is limited to 65535Hz public int setPlaybackRate(int sampleRateInHz) { if (mState != STATE_INITIALIZED) { return ERROR_INVALID_OPERATION; @@ -670,8 +664,7 @@ public class AudioTrack if (sampleRateInHz <= 0) { return ERROR_BAD_VALUE; } - native_set_playback_rate(sampleRateInHz); - return SUCCESS; + return native_set_playback_rate(sampleRateInHz); } @@ -1031,8 +1024,8 @@ public class AudioTrack private native final void native_setVolume(float leftVolume, float rightVolume); - private native final void native_set_playback_rate(int sampleRateInHz); - private native final int native_get_playback_rate(); + private native final int native_set_playback_rate(int sampleRateInHz); + private native final int native_get_playback_rate(); private native final int native_set_marker_pos(int marker); private native final int native_get_marker_pos(); diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index cf0965e..0a6f4f7 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -185,7 +185,6 @@ status_t AudioRecord::set( mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); mCblk->out = 0; - mSampleRate = sampleRate; mFormat = format; // Update buffer size in case it has been limited by AudioFlinger during track creation mFrameCount = mCblk->frameCount; @@ -196,7 +195,7 @@ status_t AudioRecord::set( mRemainingFrames = notificationFrames; mUserData = user; // TODO: add audio hardware input latency here - mLatency = (1000*mFrameCount) / mSampleRate; + mLatency = (1000*mFrameCount) / sampleRate; mMarkerPosition = 0; mMarkerReached = false; mNewPosition = 0; @@ -218,11 +217,6 @@ uint32_t AudioRecord::latency() const return mLatency; } -uint32_t AudioRecord::sampleRate() const -{ - return mSampleRate; -} - int AudioRecord::format() const { return mFormat; @@ -321,6 +315,11 @@ bool AudioRecord::stopped() const return !mActive; } +uint32_t AudioRecord::getSampleRate() +{ + return mCblk->sampleRate; +} + status_t AudioRecord::setMarkerPosition(uint32_t marker) { if (mCbf == 0) return INVALID_OPERATION; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 4a1b69e..af7dae5 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -243,7 +243,6 @@ status_t AudioTrack::set( mCblk->volume[0] = mCblk->volume[1] = 0x1000; mVolume[LEFT] = 1.0f; mVolume[RIGHT] = 1.0f; - mSampleRate = sampleRate; mStreamType = streamType; mFormat = format; mChannelCount = channelCount; @@ -254,7 +253,7 @@ status_t AudioTrack::set( mNotificationFrames = notificationFrames; mRemainingFrames = notificationFrames; mUserData = user; - mLatency = afLatency + (1000*mFrameCount) / mSampleRate; + mLatency = afLatency + (1000*mFrameCount) / sampleRate; mLoopCount = 0; mMarkerPosition = 0; mMarkerReached = false; @@ -281,11 +280,6 @@ int AudioTrack::streamType() const return mStreamType; } -uint32_t AudioTrack::sampleRate() const -{ - return mSampleRate; -} - int AudioTrack::format() const { return mFormat; @@ -438,24 +432,23 @@ void AudioTrack::getVolume(float* left, float* right) *right = mVolume[RIGHT]; } -void AudioTrack::setSampleRate(int rate) +status_t AudioTrack::setSampleRate(int rate) { int afSamplingRate; if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) { - return; + return NO_INIT; } // Resampler implementation limits input sampling rate to 2 x output sampling rate. - if (rate <= 0) rate = 1; - if (rate > afSamplingRate*2) rate = afSamplingRate*2; - if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE; + if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE; - mCblk->sampleRate = (uint16_t)rate; + mCblk->sampleRate = rate; + return NO_ERROR; } uint32_t AudioTrack::getSampleRate() { - return uint32_t(mCblk->sampleRate); + return mCblk->sampleRate; } status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) @@ -866,7 +859,7 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const result.append(buffer); snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d)\n", mFormat, mChannelCount, mFrameCount); result.append(buffer); - snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", mSampleRate, mStatus, mMuted); + snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d)\n", (mCblk == 0) ? 0 : mCblk->sampleRate, mStatus, mMuted); result.append(buffer); snprintf(buffer, 255, " active(%d), latency (%d)\n", mActive, mLatency); result.append(buffer); diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java index 0bed72bd..10f4d6e 100755 --- a/packages/TtsService/src/android/tts/TtsService.java +++ b/packages/TtsService/src/android/tts/TtsService.java @@ -36,6 +36,7 @@ import android.util.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Locale; import java.util.concurrent.locks.ReentrantLock; /** @@ -183,7 +184,8 @@ public class TtsService extends Service implements OnCompletionListener { String defaultLang = android.provider.Settings.Secure.getString(mResolver, android.provider.Settings.Secure.TTS_DEFAULT_LANG); if (defaultLang == null) { - return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG; + // no setting found, use the current Locale to determine the default language + return Locale.getDefault().getISO3Language(); } else { return defaultLang; } @@ -194,7 +196,8 @@ public class TtsService extends Service implements OnCompletionListener { String defaultCountry = android.provider.Settings.Secure.getString(mResolver, android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY); if (defaultCountry == null) { - return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY; + // no setting found, use the current Locale to determine the default country + return Locale.getDefault().getISO3Country(); } else { return defaultCountry; } @@ -205,7 +208,8 @@ public class TtsService extends Service implements OnCompletionListener { String defaultVar = android.provider.Settings.Secure.getString(mResolver, android.provider.Settings.Secure.TTS_DEFAULT_VARIANT); if (defaultVar == null) { - return TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT; + // no setting found, use the current Locale to determine the default variant + return Locale.getDefault().getVariant(); } else { return defaultVar; } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 0f5b3fd..fab97b1 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -648,14 +648,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private void checkPermissionsSafe(String provider) { if (LocationManager.GPS_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) + && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) { throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); } if (LocationManager.NETWORK_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) + && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) - && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) + && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)) { throw new SecurityException( "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission"); @@ -664,14 +664,14 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private boolean isAllowedProviderSafe(String provider) { if (LocationManager.GPS_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) + && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) { return false; } if (LocationManager.NETWORK_PROVIDER.equals(provider) - && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) + && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) - && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION) + && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)) { return false; } @@ -1075,7 +1075,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (mGpsStatusProvider == null) { return false; } - if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) != + if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); } @@ -1103,7 +1103,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // first check for permission to the provider checkPermissionsSafe(provider); // and check for ACCESS_LOCATION_EXTRA_COMMANDS - if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS) + if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) != PackageManager.PERMISSION_GRANTED)) { throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission"); } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index ab6e49c..9da29fa 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -38,6 +38,7 @@ import android.net.wifi.WifiNative; import android.net.wifi.WifiStateTracker; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; +import android.net.wifi.SupplicantState; import android.net.NetworkStateTracker; import android.net.DhcpInfo; import android.os.Binder; @@ -1577,8 +1578,9 @@ public class WifiService extends IWifiManager.Stub { * or plugged in to AC). */ if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) { - if (!mWifiStateTracker.hasIpAddress()) { - // do not keep Wifi awake when screen is off if Wifi is not fully active + WifiInfo info = mWifiStateTracker.requestConnectionInfo(); + if (info.getSupplicantState() != SupplicantState.COMPLETED) { + // do not keep Wifi awake when screen is off if Wifi is not associated mDeviceIdle = true; updateWifiState(); } else { diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index eaeda64..ef3afff 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -455,7 +455,14 @@ public final class BearerData { } } - private static byte[] encode7bitGsm(String msg) + private static int calcUdhSeptetPadding(int userDataHeaderLen) { + int udhBits = userDataHeaderLen * 8; + int udhSeptets = (udhBits + 6) / 7; + int paddingBits = (udhSeptets * 7) - udhBits; + return paddingBits; + } + + private static byte[] encode7bitGsm(String msg, int paddingBits) throws CodingException { try { @@ -464,11 +471,9 @@ public final class BearerData { * an option to produce just the data without prepending * the length. */ - byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg); + byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg, 0, -1, paddingBits, true); byte []data = new byte[fullData.length - 1]; - for (int i = 0; i < data.length; i++) { - data[i] = fullData[i + 1]; - } + System.arraycopy(fullData, 1, data, 0, fullData.length - 1); return data; } catch (com.android.internal.telephony.EncodeException ex) { throw new CodingException("7bit GSM encode failed: " + ex); @@ -478,9 +483,11 @@ public final class BearerData { private static void encodeUserDataPayload(UserData uData) throws CodingException { + // TODO(cleanup): UDH can only occur in EMS mode, meaning + // encapsulation of GSM encoding, and so the logic here should + // be refactored to more cleanly reflect this constraint. + byte[] headerData = null; - // TODO: if there is a header, meaning EMS mode, we probably - // also want the total UD length prior to the UDH length... if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader); int headerDataLen = (headerData == null) ? 0 : headerData.length + 1; // + length octet @@ -502,8 +509,9 @@ public final class BearerData { uData.payloadStr = ""; } if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) { - payloadData = encode7bitGsm(uData.payloadStr); - codeUnitCount = (payloadData.length * 8) / 7; + int paddingBits = calcUdhSeptetPadding(headerDataLen); + payloadData = encode7bitGsm(uData.payloadStr, paddingBits); + codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7; } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) { payloadData = encode7bitAscii(uData.payloadStr, true); codeUnitCount = uData.payloadStr.length(); @@ -528,8 +536,9 @@ public final class BearerData { } else { // If there is a header, we are in EMS mode, in // which case we use GSM encodings. - payloadData = encode7bitGsm(uData.payloadStr); - codeUnitCount = (payloadData.length * 8) / 7; + int paddingBits = calcUdhSeptetPadding(headerDataLen); + payloadData = encode7bitGsm(uData.payloadStr, paddingBits); + codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7; uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; } } catch (CodingException ex) { @@ -880,7 +889,12 @@ public final class BearerData { private static String decode7bitGsm(byte[] data, int offset, int numFields) throws CodingException { - String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields); + int paddingBits = calcUdhSeptetPadding(offset); + numFields -= (((offset * 8) + paddingBits) / 7); + // TODO: It seems wrong that only Gsm7 bit encodings would + // take into account the header in numFields calculations. + // This should be verified. + String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits); if (result == null) { throw new CodingException("7bit GSM decoding failed"); } diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java index 2ff0a6a..f0ba573 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java @@ -108,6 +108,21 @@ public class CdmaSmsTest extends AndroidTestCase { userData.payloadStr = "More @ testing\nis great^|^~woohoo"; revBearerData = BearerData.decode(BearerData.encode(bearerData)); assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0xEE; + concatRef.msgCount = 2; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + userData.userDataHeader = smsHeader; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + SmsHeader decodedHeader = revBearerData.userData.userDataHeader; + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); } @SmallTest diff --git a/tests/backup/src/com/android/backuptest/BackupTestActivity.java b/tests/backup/src/com/android/backuptest/BackupTestActivity.java index 7f30c91..afbc703 100644 --- a/tests/backup/src/com/android/backuptest/BackupTestActivity.java +++ b/tests/backup/src/com/android/backuptest/BackupTestActivity.java @@ -52,6 +52,8 @@ public class BackupTestActivity extends ListActivity static final String PREF_KEY = "pref"; static final String FILE_NAME = "file.txt"; + BackupManager sBm = new BackupManager(this); + Test[] mTests = new Test[] { new Test("Show File") { void run() { @@ -85,8 +87,7 @@ public class BackupTestActivity extends ListActivity output.close(); } } - BackupManager bm = new BackupManager(BackupTestActivity.this); - bm.dataChanged(); + sBm.dataChanged(); } }, new Test("Clear File") { @@ -100,14 +101,12 @@ public class BackupTestActivity extends ListActivity output.close(); } } - BackupManager bm = new BackupManager(BackupTestActivity.this); - bm.dataChanged(); + sBm.dataChanged(); } }, new Test("Poke") { void run() { - BackupManager bm = new BackupManager(BackupTestActivity.this); - bm.dataChanged(); + sBm.dataChanged(); } }, new Test("Show Shared Pref") { @@ -126,8 +125,7 @@ public class BackupTestActivity extends ListActivity SharedPreferences.Editor editor = prefs.edit(); editor.putInt(PREF_KEY, val+1); editor.commit(); - BackupManager bm = new BackupManager(BackupTestActivity.this); - bm.dataChanged(); + sBm.dataChanged(); } }, new Test("Backup Helpers") { |