diff options
23 files changed, 340 insertions, 170 deletions
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index 8aee65c5fc1b..615e8cea64c4 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -29,6 +29,7 @@ import dalvik.system.BlockGuard; import org.xmlpull.v1.XmlPullParserException; +import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -107,7 +108,8 @@ final class SharedPreferencesImpl implements SharedPreferences { FileStatus stat = new FileStatus(); if (FileUtils.getFileStatus(mFile.getPath(), stat) && mFile.canRead()) { try { - FileInputStream str = new FileInputStream(mFile); + BufferedInputStream str = new BufferedInputStream( + new FileInputStream(mFile), 16*1024); map = XmlUtils.readMapXml(str); str.close(); } catch (XmlPullParserException e) { diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index fe0106dc52c4..33310dfd0ad8 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -768,61 +768,6 @@ public final class NfcAdapter { } /** - * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated - * @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback} - * @hide - */ - @Deprecated - public interface NdefPushCallback { - /** - * @deprecated use {@link CreateNdefMessageCallback} instead - */ - @Deprecated - NdefMessage createMessage(); - /** - * @deprecated use{@link OnNdefPushCompleteCallback} instead - */ - @Deprecated - void onMessagePushed(); - } - - /** - * TODO: Remove this - * Converts new callbacks to old callbacks. - */ - static final class LegacyCallbackWrapper implements CreateNdefMessageCallback, - OnNdefPushCompleteCallback { - final NdefPushCallback mLegacyCallback; - LegacyCallbackWrapper(NdefPushCallback legacyCallback) { - mLegacyCallback = legacyCallback; - } - @Override - public void onNdefPushComplete(NfcEvent event) { - mLegacyCallback.onMessagePushed(); - } - @Override - public NdefMessage createNdefMessage(NfcEvent event) { - return mLegacyCallback.createMessage(); - } - } - - /** - * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated - * @deprecated use {@link #setNdefPushMessageCallback} instead - * @hide - */ - @Deprecated - public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) { - if (activity == null || callback == null) { - throw new NullPointerException(); - } - enforceResumed(activity); - LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback); - mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper); - mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper); - } - - /** * Enable NDEF Push feature. * <p>This API is for the Settings application. * @hide diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index 9dea4c43b699..70ec0af4064c 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -32,12 +32,13 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** - * <p>AsyncTask enables proper and easy use of the UI thread. This class allows to - * perform background operations and publish results on the UI thread without - * having to manipulate threads and/or handlers.</p> + * <p>AsyncTask enables proper and easy use of the UI thread (also called main thread) or + * any other looper thread. AsyncTask is most commonly used to interact with the UI thread. + * This class allows to perform background operations and publish results on a looper + * thread without having to manipulate threads and/or handlers.</p> * * <p>An asynchronous task is defined by a computation that runs on a background thread and - * whose result is published on the UI thread. An asynchronous task is defined by 3 generic + * whose result is published on a looper thread. An asynchronous task is defined by 3 generic * types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>, * and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>, * <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p> @@ -101,7 +102,7 @@ import java.util.concurrent.atomic.AtomicInteger; * <h2>The 4 steps</h2> * <p>When an asynchronous task is executed, the task goes through 4 steps:</p> * <ol> - * <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task + * <li>{@link #onPreExecute()}, invoked on the looper thread immediately after the task * is executed. This step is normally used to setup the task, for instance by * showing a progress bar in the user interface.</li> * <li>{@link #doInBackground}, invoked on the background thread @@ -110,14 +111,14 @@ import java.util.concurrent.atomic.AtomicInteger; * of the asynchronous task are passed to this step. The result of the computation must * be returned by this step and will be passed back to the last step. This step * can also use {@link #publishProgress} to publish one or more units - * of progress. These values are published on the UI thread, in the + * of progress. These values are published on the looper thread, in the * {@link #onProgressUpdate} step.</li> - * <li>{@link #onProgressUpdate}, invoked on the UI thread after a + * <li>{@link #onProgressUpdate}, invoked on the looper thread after a * call to {@link #publishProgress}. The timing of the execution is * undefined. This method is used to display any form of progress in the user * interface while the background computation is still executing. For instance, * it can be used to animate a progress bar or show logs in a text field.</li> - * <li>{@link #onPostExecute}, invoked on the UI thread after the background + * <li>{@link #onPostExecute}, invoked on the looper thread after the background * computation finishes. The result of the background computation is passed to * this step as a parameter.</li> * </ol> @@ -135,8 +136,8 @@ import java.util.concurrent.atomic.AtomicInteger; * <p>There are a few threading rules that must be followed for this class to * work properly:</p> * <ul> - * <li>The task instance must be created on the UI thread.</li> - * <li>{@link #execute} must be invoked on the UI thread.</li> + * <li>The task instance must be created on the looper thread.</li> + * <li>{@link #execute} must be invoked on the looper thread.</li> * <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute}, * {@link #doInBackground}, {@link #onProgressUpdate} manually.</li> * <li>The task can be executed only once (an exception will be thrown if @@ -152,6 +153,9 @@ import java.util.concurrent.atomic.AtomicInteger; * <li>Set member fields in {@link #doInBackground}, and refer to them in * {@link #onProgressUpdate} and {@link #onPostExecute}. * </ul> + * + * @see Looper + * @see Handler */ public abstract class AsyncTask<Params, Progress, Result> { private static final String LOG_TAG = "AsyncTask"; @@ -187,7 +191,13 @@ public abstract class AsyncTask<Params, Progress, Result> { private static final int MESSAGE_POST_RESULT = 0x1; private static final int MESSAGE_POST_PROGRESS = 0x2; - private static final InternalHandler sHandler = new InternalHandler(); + private static final ThreadLocal<InternalHandler> sHandler = + new ThreadLocal<InternalHandler>() { + @Override + protected InternalHandler initialValue() { + return new InternalHandler(); + } + }; private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR; private final WorkerRunnable<Params, Result> mWorker; @@ -196,6 +206,7 @@ public abstract class AsyncTask<Params, Progress, Result> { private volatile Status mStatus = Status.PENDING; private final AtomicBoolean mTaskInvoked = new AtomicBoolean(); + private final InternalHandler mHandler; private static class SerialExecutor implements Executor { final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); @@ -242,9 +253,8 @@ public abstract class AsyncTask<Params, Progress, Result> { FINISHED, } - /** @hide Used to force static handler to be created. */ + /** @hide */ public static void init() { - sHandler.getLooper(); } /** @hide */ @@ -253,14 +263,26 @@ public abstract class AsyncTask<Params, Progress, Result> { } /** - * Creates a new asynchronous task. This constructor must be invoked on the UI thread. + * Creates a new asynchronous task. This constructor must be invoked on the looper thread. + * + * @throws IllegalStateException if this constructor is invoked on a non-looper thread + * + * @see Looper */ public AsyncTask() { + if (Looper.myLooper() == null) { + throw new IllegalStateException("AsyncTask can be only instanciated on a " + + "looper thread. The current thread is " + Thread.currentThread()); + } + + mHandler = sHandler.get(); + mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + //noinspection unchecked return postResult(doInBackground(mParams)); } }; @@ -295,7 +317,8 @@ public abstract class AsyncTask<Params, Progress, Result> { } private Result postResult(Result result) { - Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, + @SuppressWarnings({"unchecked"}) + Message message = mHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; @@ -316,7 +339,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * by the caller of this task. * * This method can call {@link #publishProgress} to publish updates - * on the UI thread. + * on the looper thread. * * @param params The parameters of the task. * @@ -329,7 +352,7 @@ public abstract class AsyncTask<Params, Progress, Result> { protected abstract Result doInBackground(Params... params); /** - * Runs on the UI thread before {@link #doInBackground}. + * Runs on the looper thread before {@link #doInBackground}. * * @see #onPostExecute * @see #doInBackground @@ -338,7 +361,7 @@ public abstract class AsyncTask<Params, Progress, Result> { } /** - * <p>Runs on the UI thread after {@link #doInBackground}. The + * <p>Runs on the looper thread after {@link #doInBackground}. The * specified result is the value returned by {@link #doInBackground}.</p> * * <p>This method won't be invoked if the task was cancelled.</p> @@ -354,7 +377,7 @@ public abstract class AsyncTask<Params, Progress, Result> { } /** - * Runs on the UI thread after {@link #publishProgress} is invoked. + * Runs on the looper thread after {@link #publishProgress} is invoked. * The specified values are the values passed to {@link #publishProgress}. * * @param values The values indicating progress. @@ -367,7 +390,7 @@ public abstract class AsyncTask<Params, Progress, Result> { } /** - * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and + * <p>Runs on the looper thread after {@link #cancel(boolean)} is invoked and * {@link #doInBackground(Object[])} has finished.</p> * * <p>The default implementation simply invokes {@link #onCancelled()} and @@ -390,7 +413,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * This method is invoked by the default implementation of * {@link #onCancelled(Object)}.</p> * - * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and + * <p>Runs on the looper thread after {@link #cancel(boolean)} is invoked and * {@link #doInBackground(Object[])} has finished.</p> * * @see #onCancelled(Object) @@ -425,7 +448,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * an attempt to stop the task.</p> * * <p>Calling this method will result in {@link #onCancelled(Object)} being - * invoked on the UI thread after {@link #doInBackground(Object[])} + * invoked on the looper thread after {@link #doInBackground(Object[])} * returns. Calling this method guarantees that {@link #onPostExecute(Object)} * is never invoked. After invoking this method, you should check the * value returned by {@link #isCancelled()} periodically from @@ -498,14 +521,15 @@ public abstract class AsyncTask<Params, Progress, Result> { * with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings on * its use. * - * <p>This method must be invoked on the UI thread. + * <p>This method must be invoked on the looper thread. * * @param params The parameters of the task. * * @return This instance of AsyncTask. * * @throws IllegalStateException If {@link #getStatus()} returns either - * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. + * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED} or + * the current thread is not a looper thread. */ public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); @@ -531,7 +555,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * executed in serial; to guarantee such work is serialized regardless of * platform version you can use this function with {@link #SERIAL_EXECUTOR}. * - * <p>This method must be invoked on the UI thread. + * <p>This method must be invoked on the looper thread. * * @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a * convenient process-wide thread pool for tasks that are loosely coupled. @@ -540,10 +564,16 @@ public abstract class AsyncTask<Params, Progress, Result> { * @return This instance of AsyncTask. * * @throws IllegalStateException If {@link #getStatus()} returns either - * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}. + * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED} or + * the current thread is not a looper thread. */ public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { + if (Looper.myLooper() == null) { + throw new IllegalStateException("AsyncTask can be only instanciated on a " + + "looper thread. The current thread is " + Thread.currentThread()); + } + if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: @@ -576,9 +606,9 @@ public abstract class AsyncTask<Params, Progress, Result> { /** * This method can be invoked from {@link #doInBackground} to - * publish updates on the UI thread while the background computation is + * publish updates on the looper thread while the background computation is * still running. Each call to this method will trigger the execution of - * {@link #onProgressUpdate} on the UI thread. + * {@link #onProgressUpdate} on the looper thread. * * {@link #onProgressUpdate} will note be called if the task has been * canceled. @@ -590,7 +620,7 @@ public abstract class AsyncTask<Params, Progress, Result> { */ protected final void publishProgress(Progress... values) { if (!isCancelled()) { - sHandler.obtainMessage(MESSAGE_POST_PROGRESS, + mHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } } diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 4d7a9bbf8938..cc2fa8532d3d 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -35,7 +35,6 @@ import dalvik.system.VMDebug; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -902,15 +901,13 @@ public final class StrictMode { return false; } + // Thread policy controls BlockGuard. int threadPolicyMask = StrictMode.DETECT_DISK_WRITE | StrictMode.DETECT_DISK_READ | StrictMode.DETECT_NETWORK; if (!IS_USER_BUILD) { threadPolicyMask |= StrictMode.PENALTY_DROPBOX; - if (IS_ENG_BUILD) { - threadPolicyMask |= StrictMode.PENALTY_LOG; - } } if (doFlashes) { threadPolicyMask |= StrictMode.PENALTY_FLASH; @@ -918,6 +915,8 @@ public final class StrictMode { StrictMode.setThreadPolicyMask(threadPolicyMask); + // VM Policy controls CloseGuard, detection of Activity leaks, + // and instance counting. if (IS_USER_BUILD) { setCloseGuardEnabled(false); } else { diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index fd19b5fea9d2..e16a8bdff8fa 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -922,15 +922,20 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { if (selectedView != null) { event.setEnabled(selectedView.isEnabled()); } + event.setCurrentItemIndex(getSelectedItemPosition()); event.setFromIndex(getFirstVisiblePosition()); event.setToIndex(getLastVisiblePosition()); event.setItemCount(getAdapter().getCount()); } private boolean isScrollableForAccessibility() { - final int itemCount = getAdapter().getCount(); - return itemCount > 0 - && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1); + T adapter = getAdapter(); + if (adapter != null) { + final int itemCount = adapter.getCount(); + return itemCount > 0 + && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1); + } + return false; } @Override diff --git a/core/java/com/android/internal/widget/TransportControlView.java b/core/java/com/android/internal/widget/TransportControlView.java index 1042a59d6d24..73d9f10104f4 100644 --- a/core/java/com/android/internal/widget/TransportControlView.java +++ b/core/java/com/android/internal/widget/TransportControlView.java @@ -336,20 +336,27 @@ public class TransportControlView extends FrameLayout implements OnClickListener if (state == mPlayState) { return; } + final int imageResId; + final int imageDescId; switch (state) { case RemoteControlClient.PLAYSTATE_PLAYING: - mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_pause); + imageResId = com.android.internal.R.drawable.ic_media_pause; + imageDescId = com.android.internal.R.string.lockscreen_transport_pause_description; break; case RemoteControlClient.PLAYSTATE_BUFFERING: - mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_stop); + imageResId = com.android.internal.R.drawable.ic_media_stop; + imageDescId = com.android.internal.R.string.lockscreen_transport_stop_description; break; case RemoteControlClient.PLAYSTATE_PAUSED: default: - mBtnPlay.setImageResource(com.android.internal.R.drawable.ic_media_play); + imageResId = com.android.internal.R.drawable.ic_media_play; + imageDescId = com.android.internal.R.string.lockscreen_transport_play_description; break; } + mBtnPlay.setImageResource(imageResId); + mBtnPlay.setContentDescription(getResources().getString(imageDescId)); mPlayState = state; } diff --git a/core/res/res/layout/keyguard_transport_control.xml b/core/res/res/layout/keyguard_transport_control.xml index 2ebe5fceddc2..6e24ce249f5b 100644 --- a/core/res/res/layout/keyguard_transport_control.xml +++ b/core/res/res/layout/keyguard_transport_control.xml @@ -66,7 +66,8 @@ android:src="@drawable/ic_media_rew" android:clickable="true" android:background="?android:attr/selectableItemBackground" - android:padding="10dip"/> + android:padding="10dip" + android:contentDescription="@string/lockscreen_transport_prev_description"/> </FrameLayout> <FrameLayout android:layout_width="wrap_content" @@ -80,7 +81,8 @@ android:clickable="true" android:src="@drawable/ic_media_play" android:background="?android:attr/selectableItemBackground" - android:padding="10dip"/> + android:padding="10dip" + android:contentDescription="@string/lockscreen_transport_play_description"/> </FrameLayout> <FrameLayout android:layout_width="wrap_content" @@ -94,7 +96,8 @@ android:clickable="true" android:src="@drawable/ic_media_ff" android:background="?android:attr/selectableItemBackground" - android:padding="10dip"/> + android:padding="10dip" + android:contentDescription="@string/lockscreen_transport_next_description"/> </FrameLayout> </LinearLayout> </LinearLayout> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 3f0f2f34ba4d..fb4783b51802 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -953,7 +953,7 @@ social updates from your friends. Malicious apps can use this to pretend to be a friend and trick you into revealing passwords or other confidential information.</string> - + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_readCalendar">read calendar events plus confidential information</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> @@ -1831,6 +1831,17 @@ <string name="lockscreen_permanent_disabled_sim_instructions">Your SIM card is permanently disabled.\n Please contact your wireless service provider to obtain another SIM card.</string> + <!-- Shown on transport control of lockscreen. Pressing button goes to previous track. --> + <string name="lockscreen_transport_prev_description">Previous track button</string> + <!-- Shown on transport control of lockscreen. Pressing button goes to next track. --> + <string name="lockscreen_transport_next_description">Next track button</string> + <!-- Shown on transport control of lockscreen. Pressing button pauses playback --> + <string name="lockscreen_transport_pause_description">Pause button</string> + <!-- Shown on transport control of lockscreen. Pressing button pauses playback --> + <string name="lockscreen_transport_play_description">Play button</string> + <!-- Shown on transport control of lockscreen. Pressing button pauses playback --> + <string name="lockscreen_transport_stop_description">Stop button</string> + <!-- Shown in the lock screen when there is emergency calls only mode. --> <string name="emergency_calls_only" msgid="2485604591272668370">Emergency calls only</string> diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk index 564f41cb4cf6..c96496195849 100644 --- a/data/keyboards/keyboards.mk +++ b/data/keyboards/keyboards.mk @@ -24,6 +24,3 @@ PRODUCT_COPY_FILES += $(foreach file,$(keycharmaps),\ PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\ frameworks/base/data/keyboards/$(file):system/usr/idc/$(file)) - -PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) $(keyconfigs) - diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd index b2a78fe98222..5a9313e7f70c 100644 --- a/docs/html/guide/topics/manifest/activity-element.jd +++ b/docs/html/guide/topics/manifest/activity-element.jd @@ -581,8 +581,9 @@ resource usage. </p></dd> <dt><a name="screen"></a>{@code android:screenOrientation}</dt> -<dd>The orientation of the activity's display on the device. -The value can be any one of the following strings: +<dd>The orientation of the activity's display on the device. + +<p>The value can be any one of the following strings:</p> <table> <tr> @@ -640,7 +641,23 @@ is ignored, so the display will not rotate based on how the user moves the devic distinction, the system chooses the orientation using the same policy as for the "{@code unspecified}" setting.</td> </tr> -</table></dd> +</table> + +<p class="note"><strong>Note:</strong> When you declare one of the landscape or portrait values, +it is considered a hard requirement for the orientation in which the activity runs. As such, +the value you declare enables filtering by services such as Android Market so your application is +available only to devices that support the orientation required by your activities. For +example, if you declare either {@code "landscape"}, {@code "reverseLandscape"}, or +{@code "sensorLandscape"}, then your application will be available only to devices that support +landscape orientation. However, you should also explicitly declare that +your application requires either portrait or landscape orientation with the <a +href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}</a> +element. For example, <code><uses-feature +android:name="android.hardware.screen.portrait"/></code>. This is purely a filtering behavior +provided by Android Market (and other services that support it) and the platform itself does not +control whether your app can be installed when a device supports only certain orientations.</p> + +</dd> <dt><a name="state"></a>{@code android:stateNotNeeded}</dt> <dd>Whether or not the activity can be killed and successfully restarted diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd index 49d6b6204779..9f806380e921 100644 --- a/docs/html/guide/topics/manifest/uses-feature-element.jd +++ b/docs/html/guide/topics/manifest/uses-feature-element.jd @@ -111,7 +111,7 @@ the device before installing an application. However, other services with your application. For this reason, it's very important that you declare all of the features (from the list below) that your application uses. </p> -<p>For some features, there may exist a specfic attribute that allows you to define +<p>For some features, there may exist a specific attribute that allows you to define a version of the feature, such as the version of Open GL used (declared with <a href="#glEsVersion"><code>glEsVersion</code></a>). Other features that either do or do not exist for a device, such as a camera, are declared using the @@ -277,7 +277,7 @@ application absolutely requires the feature and cannot function properly without it (<code>"true"</code>), or whether the application prefers to use the feature if available, but is designed to run without it (<code>"false"</code>).</p> -<p>Android Market handles explictly declared features in this way: </p> +<p>Android Market handles explicitly declared features in this way: </p> <ul> <li>If a feature is explicitly declared as being required, Android Market adds @@ -287,7 +287,7 @@ For example: <pre><uses-feature android:name="android.hardware.camera" android:required="true" /></pre></li> <li>If a feature is explicitly declared as <em>not</em> being required, Android Market <em>does not</em> add the feature to the list of required features. For -that reason, an explicity declared non-required feature is never considered when +that reason, an explicitly declared non-required feature is never considered when filtering the application. Even if the device does not provide the declared feature, Android Market will still consider the application compatible with the device and will show it to the user, unless other filtering rules apply. For @@ -650,6 +650,40 @@ the device.</td> <td>The application uses the device's proximity sensor.</td> <td></td> </tr> + +<tr> + <td rowspan="2">Screen</td> + <td><code>android.hardware.screen.landscape</code></td> + <td>The application requires landscape orientation.</td> + <td rowspan="2"> + <p>For example, if your app requires portrait orientation, you should declare +<code><uses-feature android:name="android.hardware.screen.portrait"/></code> so that only devices +that support portrait orientation (whether always or by user choice) can install your app. If your +application <em>supports</em> both orientations, then you don't need to declare either.</p> + <p>Both orientations are assumed <em>not required</em>, by default, so your app may be installed +on devices that support one or both orientations. However, if any of your activities request that +they run in a specific orientation, using the <a +href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a> attribute, then this also declares that the application requires that +orientation. For example, if you declare <a +href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a> with either {@code "landscape"}, {@code "reverseLandscape"}, or +{@code "sensorLandscape"}, then your application will be available only to devices that support +landscape orientation. As a best practice, you should still declare your requirement for this +orientation using a {@code <uses-feature>} element. If you declare an orientation for your +activity using <a href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a>, but don't actually <em>require</em> it, you can disable the +requirement by declaring the orientation with a {@code <uses-feature>} element and include +{@code android:required="false"}.</p> + <p>For backwards compatibility, any device running a platform version that supports only API +level 12 or lower is assumed to support both landscape and portrait.</p> + </td> +</tr> +<tr> + <td><code>android.hardware.screen.portrait</code></td> + <td>The application requires portrait orientation.</td> +</tr> + <tr> <td rowspan="3">Telephony</td> <td><code>android.hardware.telephony</code></td> @@ -672,17 +706,18 @@ device.</td> </tr> <tr> - <td rowspan="5">Touchscreen</td> + <td rowspan="7">Touchscreen</td> <td><code>android.hardware.faketouch</code></td> <td>The application uses basic touch interaction events, such as "click down", "click up", and drag.</td> - <td>When declared, this indicates that the application is compatible with a device that offers an -emulated touchscreen ("fake touch" interface), or better. A device that offers a fake touch -interface provides a user input system that emulates a subset of touchscreen capabilities. For -example, a mouse or remote control that drives an on-screen cursor provides a fake touch interface. -If your application requires only basic point and click interaction, you should declare this -feature. Because this is the minimum level of touch interaction, your app will also be compatible -with devices that offer more complex touch interfaces. + <td><p>When declared as required, this indicates that the application is compatible with a device +only if it offers an emulated touchscreen ("fake touch" interface), or better. A device that offers +a fake touch interface provides a user input system that emulates a subset of touchscreen +capabilities. For example, a mouse or remote control that drives an on-screen cursor provides a fake +touch interface. If your application requires basic point and click interaction (in other +words, it won't work with <em>only</em> a d-pad controller), you should declare this feature. +Because this is the minimum level of touch interaction, your app will also be compatible with +devices that offer more complex touch interfaces.</p> <p class="note"><strong>Note:</strong> Because applications require the {@code android.hardware.touchscreen} feature by default, if you want your application to be available to devices that provide a fake touch interface, you must also explicitly declare that a touch screen is @@ -690,18 +725,53 @@ devices that provide a fake touch interface, you must also explicitly declare th android:name="android.hardware.touchscreen" <strong>android:required="false"</strong> />}</p></td> </tr> + +<tr> + <td><code>android.hardware.faketouch.multitouch.distinct</code></td> + <td>The application performs distinct tracking of two or more "fingers" on a fake touch +interface. This is a superset of the faketouch feature.</td> + <td><p>When declared as required, this indicates that the application is compatible with a device +only if it supports touch emulation for events that supports distinct tracking of two or more +fingers, or better.</p> + <p>Unlike the distinct multitouch defined by {@code +android.hardware.touchscreen.multitouch.distinct}, input devices that support distinct multi-touch +with a fake touch interface will not support all two-finger gestures, because the input is +being transformed to cursor movement on the screen. That is, single finger gestures on such a device +move a cursor; two-finger swipes will result in single-finger touch events; other two-finger +gestures will result in the corresponding two-finger touch event. An example device that supports +distinct multi-touch with a fake touch interface is one that provides a trackpad for cursor movement +which also supports two or more fingers.</p></td> +</tr> + +<tr> + <td><code>android.hardware.faketouch.multitouch.jazzhand</code></td> + <td>The application performs distinct tracking of five or more "fingers" on a fake touch +interface. This is a superset of the faketouch feature.</td> + <td><p>When declared as required, this indicates that the application is compatible with a device +only if it supports touch emulation for events that supports distinct tracking of five or more +fingers.</p> + <p>Unlike the distinct multitouch defined by {@code +android.hardware.touchscreen.multitouch.jazzhand}, input devices that support jazzhand multi-touch +with a fake touch interface will not support all five-finger gestures, because the input is being +transformed to cursor movement on the screen. That is, single finger gestures on such a device move +a cursor; multi-finger gestures will result in single-finger touch events; other multi-finger +gestures will result in the corresponding multi-finger touch event. An example device that supports +distinct multi-touch with a fake touch interface is one that provides a trackpad for cursor movement +which also supports five or more fingers.</p></td> +</tr> + <tr> <td><code>android.hardware.touchscreen</code></td> <td>The application uses touchscreen capabilities for gestures that are more interactive -than basic touch events, such as a fling. This is a superset of the faketouch features.</td> - <td>By default, your application requires this. As such, your application is -<em>not</em> available to devices that provide only an emulated touch interface ("fake touch"), by -default. If you want your application available to devices that provide a fake touch interface, -you must explicitly declare that a touch screen is not required, by -declaring {@code android.hardware.touchscreen} with {@code android:required="false"}. You should -do so even if your application uses—but does not <em>require</em>—a real touch screen -interface. -<p>If your application <em>does require</em> a basic touch interface (in order to perform touch +than basic touch events, such as a fling. This is a superset of the basic faketouch feature.</td> + <td><p>By default, your application requires this. As such, your application is <em>not</em> +available to devices that provide only an emulated touch interface ("fake touch"), by default. If +you want your application available to devices that provide a fake touch interface (or even devices +that provide only a d-pad controller), you must explicitly declare that a touch screen is not +required, by declaring {@code android.hardware.touchscreen} with {@code android:required="false"}. +You should do so even if your application uses—but does not <em>require</em>—a real +touch screen interface.</p> +<p>If your application <em>does require</em> a touch interface (in order to perform touch gestures such as a fling), then you don't need to do anything, because this is required by default. However, it's best if you explicitly declare all features used by your application, so you should still declare this if your app uses it.</p> @@ -712,7 +782,7 @@ should declare the advanced touch screen features below.</p></td> <td><code>android.hardware.touchscreen.multitouch</code></td> <td>The application uses basic two-point multitouch capabilities on the device screen, such as for pinch gestures, but does not need to track touches independently. This -is a superset of touchscreen features.</td> +is a superset of touchscreen feature.</td> <td>This implicitly declares the <code>android.hardware.touchscreen</code> parent feature, unless declared with <code>android:required="false"</code>. </td> </tr> @@ -720,7 +790,7 @@ declared with <code>android:required="false"</code>. </td> <td><code>android.hardware.touchscreen.multitouch.distinct</code></td> <td>Subfeature. The application uses advanced multipoint multitouch capabilities on the device screen, such as for tracking two or more points fully -independently. This is a superset of multitouch features.</td> +independently. This is a superset of multitouch feature.</td> <td rowspan="2">This implicitly declares the <code>android.hardware.touchscreen.multitouch</code> parent feature, unless declared with <code>android:required="false"</code>. </td> </tr> @@ -728,7 +798,7 @@ parent feature, unless declared with <code>android:required="false"</code>. </td <td><code>android.hardware.touchscreen.multitouch.jazzhand</code></td> <td>The application uses advanced multipoint multitouch capabilities on the device screen, for tracking up to five points fully -independently. This is a superset of distinct multitouch features.</td> +independently. This is a superset of distinct multitouch feature.</td> </tr> <tr> diff --git a/docs/html/sdk/android-3.2.jd b/docs/html/sdk/android-3.2.jd index ea2b4ed6ad2e..aeaf9c8171ed 100644 --- a/docs/html/sdk/android-3.2.jd +++ b/docs/html/sdk/android-3.2.jd @@ -550,7 +550,11 @@ portrait orientation.</li> <p>A typical application that functions properly in both landscape and portrait orientations would not normally need to declare an orientation requirement. Rather, an application designed primarily for one orientation, such as an app designed for a television, could declare one of the constants to ensure that it isn't available to devices that don't provide that orientation.</p> -<p>If the application is targeting API level 12 or lower, the platform assumes that if app has not specified whether it requires portrait or landscape, both orientations are required.</p> +<p>If any of activities declared in the manifest request that they run in a specific orientation, +using the <a href="{@docRoot}guide/topics/manifest/activity-element.html#screen">{@code +android:screenOrientation}</a> attribute, then this also declares that the application +requires that orientation.</p> + </li> <li>Other feature constants diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 349b9e32268d..079950852150 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -264,7 +264,7 @@ Layer* LayerRenderer::createTextureLayer(bool isOpaque) { layer->setFbo(0); layer->setAlpha(255, SkXfermode::kSrcOver_Mode); layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); - layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f); + layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f); layer->region.clear(); layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer() @@ -400,6 +400,18 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { renderer.setViewport(bitmap->width(), bitmap->height()); renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f, bitmap->width(), bitmap->height(), !layer->isBlend()); + + glDisable(GL_SCISSOR_TEST); + renderer.translate(0.0f, bitmap->height()); + renderer.scale(1.0f, -1.0f); + + mat4 texTransform(layer->getTexTransform()); + + mat4 invert; + invert.translate(0.0f, 1.0f, 0.0f); + invert.scale(1.0f, -1.0f, 1.0f); + layer->getTexTransform().multiply(invert); + if ((error = glGetError()) != GL_NO_ERROR) goto error; { @@ -413,6 +425,7 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { if ((error = glGetError()) != GL_NO_ERROR) goto error; } + layer->getTexTransform().load(texTransform); status = true; } diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 856914359517..11b6c15185d3 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -18,7 +18,6 @@ package com.android.internal.policy.impl; import android.app.Activity; import android.app.AlertDialog; -import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -57,8 +56,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private static final String TAG = "GlobalActions"; - private StatusBarManager mStatusBar; - private final Context mContext; private final AudioManager mAudioManager; @@ -103,13 +100,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mKeyguardShowing = keyguardShowing; mDeviceProvisioned = isDeviceProvisioned; if (mDialog == null) { - mStatusBar = (StatusBarManager)mContext.getSystemService(Context.STATUS_BAR_SERVICE); mDialog = createDialog(); } prepareDialog(); - mStatusBar.disable(StatusBarManager.DISABLE_EXPAND); mDialog.show(); + mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND); } /** @@ -249,7 +245,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { - mStatusBar.disable(StatusBarManager.DISABLE_NONE); } /** {@inheritDoc} */ diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index 10cf3aaf5c0f..f67f0e056d65 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -218,7 +218,7 @@ public class KeyguardUpdateMonitor { // take a guess to start mSimState = IccCard.State.READY; - mBatteryStatus = BATTERY_STATUS_FULL; + mBatteryStatus = BATTERY_STATUS_UNKNOWN; mBatteryLevel = 100; mTelephonyPlmn = getDefaultPlmn(); diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index b05705eb1224..bcb1aa24930d 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -238,6 +238,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub * Notify our observers of an interface removal. */ private void notifyInterfaceRemoved(String iface) { + // netd already clears out quota and alerts for removed ifaces; update + // our sanity-checking state. + mActiveAlertIfaces.remove(iface); + mActiveQuotaIfaces.remove(iface); + for (INetworkManagementEventObserver obs : mObservers) { try { obs.interfaceRemoved(iface); diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 78dbbd6eb555..1941c6aa9342 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -1677,6 +1677,18 @@ public class PowerManagerService extends IPowerManager.Stub e.fillInStackTrace(); Slog.i(TAG, "Set screen state: " + on, e); } + if (on) { + if ((mPowerState & SCREEN_ON_BIT) == 0 || mSkippedScreenOn) { + // If we are turning the screen state on, but the screen + // light is currently off, then make sure that we set the + // light at this point to 0. This is the case where we are + // turning on the screen and waiting for the UI to be drawn + // before showing it to the user. We want the light off + // until it is ready to be shown to the user, not it using + // whatever the last value it had. + mScreenBrightness.forceValueLocked(Power.BRIGHTNESS_OFF); + } + } int err = Power.setScreenState(on); if (err == 0) { mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0); @@ -2029,8 +2041,6 @@ public class PowerManagerService extends IPowerManager.Stub RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); Slog.i(TAG, "Setting screen brightness: " + brightness, e); - mScreenBrightness.setTargetLocked(brightness, steps, - INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); } } @@ -2103,6 +2113,15 @@ public class PowerManagerService extends IPowerManager.Stub + " delta=" + delta); } + void forceValueLocked(int value) { + targetValue = -1; + curValue = value; + setLightBrightness(mask, value); + if (animating) { + finishAnimationLocked(false, value); + } + } + void setTargetLocked(int target, int stepsToTarget, int initialValue, int nominalCurrentValue) { if (!initialized) { diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp index 59b7e5a7413b..3b7c09e80a83 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp @@ -122,7 +122,7 @@ status_t DisplayHardwareBase::DisplayEventThread::initCheck() const DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger, uint32_t displayIndex) - : mCanDraw(true), mScreenAcquired(true) + : mScreenAcquired(true) { mDisplayEventThread = new DisplayEventThread(flinger); } @@ -133,14 +133,9 @@ DisplayHardwareBase::~DisplayHardwareBase() mDisplayEventThread->requestExitAndWait(); } -void DisplayHardwareBase::setCanDraw(bool canDraw) -{ - mCanDraw = canDraw; -} - bool DisplayHardwareBase::canDraw() const { - return mCanDraw && mScreenAcquired; + return mScreenAcquired; } void DisplayHardwareBase::releaseScreen() const diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h index 3ebc7b6cc54d..ef2df432ce18 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h @@ -43,7 +43,6 @@ public: bool isScreenAcquired() const; bool canDraw() const; - void setCanDraw(bool canDraw); private: @@ -74,7 +73,6 @@ private: }; sp<DisplayEventThreadBase> mDisplayEventThread; - mutable int mCanDraw; mutable int mScreenAcquired; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b01a6a34d16b..195ad2eae498 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -84,7 +84,6 @@ SurfaceFlinger::SurfaceFlinger() mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), - mDeferReleaseConsole(false), mFreezeDisplay(false), mElectronBeamAnimationMode(0), mFreezeCount(0), @@ -503,17 +502,9 @@ void SurfaceFlinger::handleConsoleEvents() SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode); } - if (mDeferReleaseConsole && hw.isScreenAcquired()) { - // We got the release signal before the acquire signal - mDeferReleaseConsole = false; - hw.releaseScreen(); - } - if (what & eConsoleReleased) { if (hw.isScreenAcquired()) { hw.releaseScreen(); - } else { - mDeferReleaseConsole = true; } } @@ -1814,6 +1805,8 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, // redraw the screen entirely... glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { @@ -1845,7 +1838,7 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() const DisplayHardware& hw(graphicPlane(0).displayHardware()); const uint32_t hw_w = hw.getWidth(); const uint32_t hw_h = hw.getHeight(); - const Region screenBounds(hw.bounds()); + const Region screenBounds(hw.getBounds()); GLfloat u, v; GLuint tname; @@ -1855,7 +1848,7 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() } GLfloat vtx[8]; - const GLfloat texCoords[4][2] = { {0,1}, {0,1-v}, {u,1-v}, {u,1} }; + const GLfloat texCoords[4][2] = { {0,0}, {0,v}, {u,v}, {u,0} }; glBindTexture(GL_TEXTURE_2D, tname); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -1941,6 +1934,12 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() s_curve_interpolator itb(nbFrames, 8.5f); v_stretch vverts(hw_w, hw_h); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); for (int i=0 ; i<nbFrames ; i++) { @@ -2169,7 +2168,6 @@ status_t SurfaceFlinger::turnElectronBeamOffImplLocked(int32_t mode) glEnable(GL_SCISSOR_TEST); hw.flip( Region(hw.bounds()) ); - hw.setCanDraw(false); return NO_ERROR; } @@ -2218,7 +2216,6 @@ status_t SurfaceFlinger::turnElectronBeamOnImplLocked(int32_t mode) if (mode & ISurfaceComposer::eElectronBeamAnimationOn) { electronBeamOnAnimationImplLocked(); } - hw.setCanDraw(true); // make sure to redraw the whole screen when the animation is done mDirtyRegion.set(hw.bounds()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 92b265ec8e2c..1cb9be28acf4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -363,7 +363,6 @@ private: Region mWormholeRegion; bool mVisibleRegionsDirty; bool mHwWorkListDirty; - bool mDeferReleaseConsole; bool mFreezeDisplay; int32_t mElectronBeamAnimationMode; int32_t mFreezeCount; diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java index 3232eedcf51e..414ae0dd34bc 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java @@ -22,9 +22,11 @@ import android.app.Activity; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Matrix; import android.graphics.SurfaceTexture; import android.opengl.GLUtils; import android.os.Bundle; +import android.os.Environment; import android.util.Log; import android.view.Gravity; import android.view.TextureView; @@ -39,6 +41,7 @@ import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.opengles.GL; import java.io.BufferedOutputStream; +import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -65,7 +68,8 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa Bitmap b = mTextureView.getBitmap(800, 800); BufferedOutputStream out = null; try { - out = new BufferedOutputStream(new FileOutputStream("/sdcard/out.png")); + File dump = new File(Environment.getExternalStorageDirectory(), "out.png"); + out = new BufferedOutputStream(new FileOutputStream(dump)); b.compress(Bitmap.CompressFormat.PNG, 100, out); } catch (FileNotFoundException e) { e.printStackTrace(); @@ -168,10 +172,10 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; private final float[] mTriangleVerticesData = { // X, Y, Z, U, V - -1.0f, -1.0f, 0, 0.f, 0.f, - 1.0f, -1.0f, 0, 1.f, 0.f, - -1.0f, 1.0f, 0, 0.f, 1.f, - 1.0f, 1.0f, 0, 1.f, 1.f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, }; @Override @@ -212,8 +216,6 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa while (!mFinished) { checkCurrent(); - Log.d(LOG_TAG, "Rendering frame"); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); checkGlError(); @@ -237,7 +239,7 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa checkEglError(); try { - Thread.sleep(20); + Thread.sleep(2000); } catch (InterruptedException e) { // Ignore } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java index fcb57d96b3f1..0f4c66817a05 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java @@ -17,16 +17,23 @@ package com.android.test.hwui; import android.app.Activity; +import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.os.Bundle; +import android.os.Environment; import android.view.Gravity; +import android.view.Surface; import android.view.TextureView; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; @SuppressWarnings({"UnusedDeclaration"}) @@ -44,6 +51,26 @@ public class TextureViewActivity extends Activity implements TextureView.Surface mTextureView = new TextureView(this); mTextureView.setSurfaceTextureListener(this); + mTextureView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bitmap b = mTextureView.getBitmap(800, 800); + BufferedOutputStream out = null; + try { + File dump = new File(Environment.getExternalStorageDirectory(), "out.png"); + out = new BufferedOutputStream(new FileOutputStream(dump)); + b.compress(Bitmap.CompressFormat.PNG, 100, out); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } finally { + if (out != null) try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + }); Button button = new Button(this); button.setText("Remove/Add"); @@ -73,6 +100,8 @@ public class TextureViewActivity extends Activity implements TextureView.Surface @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mCamera = Camera.open(); + mCamera.setDisplayOrientation(getCameraOrientation()); + Camera.Size previewSize = mCamera.getParameters().getPreviewSize(); mTextureView.setLayoutParams(new FrameLayout.LayoutParams( previewSize.width, previewSize.height, Gravity.CENTER)); @@ -86,6 +115,34 @@ public class TextureViewActivity extends Activity implements TextureView.Surface mCamera.startPreview(); } + private int getCameraOrientation() { + Camera.CameraInfo info = new Camera.CameraInfo(); + for (int i = 0; i < Camera.getNumberOfCameras(); i++) { + Camera.getCameraInfo(i, info); + if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) break; + } + + int rotation = getWindowManager().getDefaultDisplay().getRotation(); + int degrees = 0; + + switch (rotation) { + case Surface.ROTATION_0: + degrees = 0; + break; + case Surface.ROTATION_90: + degrees = 90; + break; + case Surface.ROTATION_180: + degrees = 180; + break; + case Surface.ROTATION_270: + degrees = 270; + break; + } + + return (info.orientation - degrees + 360) % 360; + } + @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // Ignored, the Camera does all the work for us |