diff options
189 files changed, 6499 insertions, 2802 deletions
@@ -24,7 +24,7 @@ LOCAL_PATH := $(call my-dir) # Instead, it depends on the R.stamp file, which lists the corresponding # R.java file as a prerequisite. # TODO: find a more appropriate way to do this. -framework-res-source-path := APPS/framework-res_intermediates/src +framework_res_source_path := APPS/framework-res_intermediates/src # the library # ============================================================ @@ -189,9 +189,9 @@ LOCAL_SRC_FILES += \ LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) LOCAL_INTERMEDIATE_SOURCES := \ - $(framework-res-source-path)/android/R.java \ - $(framework-res-source-path)/android/Manifest.java \ - $(framework-res-source-path)/com/android/internal/R.java + $(framework_res_source_path)/android/R.java \ + $(framework_res_source_path)/android/Manifest.java \ + $(framework_res_source_path)/com/android/internal/R.java LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := bouncycastle core core-junit ext @@ -337,9 +337,9 @@ framework_docs_LOCAL_DROIDDOC_SOURCE_PATH := \ $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) framework_docs_LOCAL_INTERMEDIATE_SOURCES := \ - $(framework-res-source-path)/android/R.java \ - $(framework-res-source-path)/android/Manifest.java \ - $(framework-res-source-path)/com/android/internal/R.java + $(framework_res_source_path)/android/R.java \ + $(framework_res_source_path)/android/Manifest.java \ + $(framework_res_source_path)/com/android/internal/R.java framework_docs_LOCAL_JAVA_LIBRARIES := \ bouncycastle \ diff --git a/api/current.xml b/api/current.xml index 9486ca6..7131eb9 100644 --- a/api/current.xml +++ b/api/current.xml @@ -19890,6 +19890,17 @@ visibility="public" > </method> +<method name="getCustomView" + return="android.view.View" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getMenu" return="android.view.Menu" abstract="true" @@ -19901,6 +19912,28 @@ visibility="public" > </method> +<method name="getSubtitle" + return="java.lang.CharSequence" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getTitle" + return="java.lang.CharSequence" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="invalidate" return="void" abstract="true" @@ -68614,6 +68647,17 @@ visibility="public" > </field> +<field name="YV12" + type="int" + transient="false" + volatile="false" + value="842094169" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="Interpolator" extends="java.lang.Object" @@ -184234,6 +184278,17 @@ visibility="public" > </method> +<method name="getAlpha" + return="float" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getAnimation" return="android.view.animation.Animation" abstract="false" @@ -184667,6 +184722,17 @@ <parameter name="location" type="int[]"> </parameter> </method> +<method name="getMatrix" + return="android.graphics.Matrix" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getMeasuredHeight" return="int" abstract="false" @@ -184799,6 +184865,28 @@ visibility="public" > </method> +<method name="getPivotX" + return="float" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getPivotY" + return="float" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getResources" return="android.content.res.Resources" abstract="false" @@ -184854,6 +184942,39 @@ visibility="public" > </method> +<method name="getRotation" + return="float" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getScaleX" + return="float" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getScaleY" + return="float" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getScrollBarStyle" return="int" abstract="false" @@ -185100,6 +185221,28 @@ <parameter name="outRect" type="android.graphics.Rect"> </parameter> </method> +<method name="getX" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getY" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="hasFocus" return="boolean" abstract="false" @@ -186430,6 +186573,19 @@ <parameter name="event" type="android.view.accessibility.AccessibilityEvent"> </parameter> </method> +<method name="setAlpha" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="alpha" type="float"> +</parameter> +</method> <method name="setAnimation" return="void" abstract="false" @@ -186482,6 +186638,19 @@ <parameter name="resid" type="int"> </parameter> </method> +<method name="setBottom" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="bottom" type="int"> +</parameter> +</method> <method name="setClickable" return="void" abstract="false" @@ -186690,6 +186859,19 @@ <parameter name="params" type="android.view.ViewGroup.LayoutParams"> </parameter> </method> +<method name="setLeft" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="left" type="int"> +</parameter> +</method> <method name="setLongClickable" return="void" abstract="false" @@ -186893,6 +187075,32 @@ <parameter name="bottom" type="int"> </parameter> </method> +<method name="setPivotX" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="pivotX" type="float"> +</parameter> +</method> +<method name="setPivotY" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="pivotY" type="float"> +</parameter> +</method> <method name="setPressed" return="void" abstract="false" @@ -186906,6 +187114,32 @@ <parameter name="pressed" type="boolean"> </parameter> </method> +<method name="setRight" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="right" type="int"> +</parameter> +</method> +<method name="setRotation" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="rotation" type="float"> +</parameter> +</method> <method name="setSaveEnabled" return="void" abstract="false" @@ -186932,6 +187166,32 @@ <parameter name="enabled" type="boolean"> </parameter> </method> +<method name="setScaleX" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="scaleX" type="float"> +</parameter> +</method> +<method name="setScaleY" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="scaleY" type="float"> +</parameter> +</method> <method name="setScrollBarStyle" return="void" abstract="false" @@ -187025,6 +187285,19 @@ <parameter name="tag" type="java.lang.Object"> </parameter> </method> +<method name="setTop" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +<parameter name="top" type="int"> +</parameter> +</method> <method name="setTouchDelegate" return="void" abstract="false" @@ -187103,6 +187376,32 @@ <parameter name="willNotDraw" type="boolean"> </parameter> </method> +<method name="setX" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="x" type="int"> +</parameter> +</method> +<method name="setY" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="y" type="int"> +</parameter> +</method> <method name="showContextMenu" return="boolean" abstract="false" diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk index bfa58a1..1df32bb 100644 --- a/cmds/surfaceflinger/Android.mk +++ b/cmds/surfaceflinger/Android.mk @@ -10,7 +10,7 @@ LOCAL_SHARED_LIBRARIES := \ libutils LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/../../libs/surfaceflinger + $(LOCAL_PATH)/../../services/surfaceflinger LOCAL_MODULE:= surfaceflinger diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp index d650721..78b1007 100644 --- a/cmds/surfaceflinger/main_surfaceflinger.cpp +++ b/cmds/surfaceflinger/main_surfaceflinger.cpp @@ -1,18 +1,25 @@ -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <utils/Log.h> +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <binder/BinderService.h> #include <SurfaceFlinger.h> using namespace android; -int main(int argc, char** argv) -{ - sp<ProcessState> proc(ProcessState::self()); - sp<IServiceManager> sm = defaultServiceManager(); - LOGI("ServiceManager: %p", sm.get()); - SurfaceFlinger::instantiate(); - ProcessState::self()->startThreadPool(); - IPCThreadState::self()->joinThreadPool(); +int main(int argc, char** argv) { + SurfaceFlinger::publishAndJoinThreadPool(); + return 0; } diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk index 1813d3e..a880a91 100644 --- a/cmds/system_server/library/Android.mk +++ b/cmds/system_server/library/Android.mk @@ -7,9 +7,9 @@ LOCAL_SRC_FILES:= \ base = $(LOCAL_PATH)/../../.. LOCAL_C_INCLUDES := \ - $(base)/camera/libcameraservice \ - $(base)/libs/audioflinger \ - $(base)/libs/surfaceflinger \ + $(base)/services/camera/libcameraservice \ + $(base)/services/audioflinger \ + $(base)/services/surfaceflinger \ $(base)/media/libmediaplayerservice \ $(JNI_H_INCLUDE) diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index d0b3ac4..3cd2b9e 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -368,6 +368,24 @@ public abstract class ActionBar { * @return The context mode's menu. */ public abstract Menu getMenu(); + + /** + * Returns the current title of this context mode. + * @return Title text + */ + public abstract CharSequence getTitle(); + + /** + * Returns the current subtitle of this context mode. + * @return Subtitle text + */ + public abstract CharSequence getSubtitle(); + + /** + * Returns the current custom view for this context mode. + * @return The current custom view + */ + public abstract View getCustomView(); } /** diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index a1cf233..91e4cd5 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -71,6 +71,7 @@ import android.view.View.OnCreateContextMenuListener; import android.view.ViewGroup.LayoutParams; import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView; +import android.widget.FrameLayout; import android.widget.LinearLayout; import com.android.internal.app.ActionBarImpl; @@ -1270,19 +1271,37 @@ public class Activity extends ContextThemeWrapper * @see #onPause */ public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) { - final View view = mDecor; - if (view == null) { + if (mDecor == null) { return false; } - final int vw = view.getWidth(); - final int vh = view.getHeight(); - final int dw = outBitmap.getWidth(); - final int dh = outBitmap.getHeight(); + int paddingLeft = 0; + int paddingRight = 0; + int paddingTop = 0; + int paddingBottom = 0; + + // Find System window and use padding so we ignore space reserved for decorations + // like the status bar and such. + final FrameLayout top = (FrameLayout) mDecor; + for (int i = 0; i < top.getChildCount(); i++) { + View child = top.getChildAt(i); + if (child.isFitsSystemWindowsFlagSet()) { + paddingLeft = child.getPaddingLeft(); + paddingRight = child.getPaddingRight(); + paddingTop = child.getPaddingTop(); + paddingBottom = child.getPaddingBottom(); + break; + } + } + + final int visibleWidth = mDecor.getWidth() - paddingLeft - paddingRight; + final int visibleHeight = mDecor.getHeight() - paddingTop - paddingBottom; canvas.save(); - canvas.scale(((float)dw)/vw, ((float)dh)/vh); - view.draw(canvas); + canvas.scale( (float) outBitmap.getWidth() / visibleWidth, + (float) outBitmap.getHeight() / visibleHeight); + canvas.translate(-paddingLeft, -paddingTop); + mDecor.draw(canvas); canvas.restore(); return true; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index eb7520f..d66e98b 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -285,24 +285,54 @@ public class ActivityManager { * @param maxNum The maximum number of entries to return in the list. The * actual number returned may be smaller, depending on how many tasks the * user has started. - * + * + * @param flags Optional flags + * @param receiver Optional receiver for delayed thumbnails + * * @return Returns a list of RunningTaskInfo records describing each of * the running tasks. * + * Some thumbnails may not be available at the time of this call. The optional + * receiver may be used to receive those thumbnails. + * * @throws SecurityException Throws SecurityException if the caller does * not hold the {@link android.Manifest.permission#GET_TASKS} permission. + * + * @hide */ - public List<RunningTaskInfo> getRunningTasks(int maxNum) + public List<RunningTaskInfo> getRunningTasks(int maxNum, int flags, IThumbnailReceiver receiver) throws SecurityException { try { - return (List<RunningTaskInfo>)ActivityManagerNative.getDefault() - .getTasks(maxNum, 0, null); + return ActivityManagerNative.getDefault().getTasks(maxNum, flags, receiver); } catch (RemoteException e) { // System dead, we will be dead too soon! return null; } } - + + /** + * Return a list of the tasks that are currently running, with + * the most recent being first and older ones after in order. Note that + * "running" does not mean any of the task's code is currently loaded or + * activity -- the task may have been frozen by the system, so that it + * can be restarted in its previous state when next brought to the + * foreground. + * + * @param maxNum The maximum number of entries to return in the list. The + * actual number returned may be smaller, depending on how many tasks the + * user has started. + * + * @return Returns a list of RunningTaskInfo records describing each of + * the running tasks. + * + * @throws SecurityException Throws SecurityException if the caller does + * not hold the {@link android.Manifest.permission#GET_TASKS} permission. + */ + public List<RunningTaskInfo> getRunningTasks(int maxNum) + throws SecurityException { + return getRunningTasks(maxNum, 0, null); + } + /** * Information you can retrieve about a particular Service that is * currently running in the system. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index aa207e8..c800fbe 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -116,6 +116,7 @@ final class RemoteServiceException extends AndroidRuntimeException { */ public final class ActivityThread { static final String TAG = "ActivityThread"; + private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565; private static final boolean DEBUG = false; static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; static final boolean DEBUG_BROADCAST = false; @@ -2245,13 +2246,24 @@ public final class ActivityThread { h = mThumbnailHeight; } - // XXX Only set hasAlpha if needed? - thumbnail = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565); - thumbnail.eraseColor(0); - Canvas cv = new Canvas(thumbnail); - if (!r.activity.onCreateThumbnail(thumbnail, cv)) { - thumbnail = null; + // On platforms where we don't want thumbnails, set dims to (0,0) + if ((w > 0) && (h > 0)) { + View topView = r.activity.getWindow().getDecorView(); + + // Maximize bitmap by capturing in native aspect. + if (topView.getWidth() >= topView.getHeight()) { + thumbnail = Bitmap.createBitmap(w, h, THUMBNAIL_FORMAT); + } else { + thumbnail = Bitmap.createBitmap(h, w, THUMBNAIL_FORMAT); + } + + thumbnail.eraseColor(0); + Canvas cv = new Canvas(thumbnail); + if (!r.activity.onCreateThumbnail(thumbnail, cv)) { + thumbnail = null; + } } + } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( @@ -2382,7 +2394,7 @@ public final class ActivityThread { if (info != null) { try { // First create a thumbnail for the activity... - //info.thumbnail = createThumbnailBitmap(r); + info.thumbnail = createThumbnailBitmap(r); info.description = r.activity.onCreateDescription(); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 6e9586c..a2a74f8 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1715,8 +1715,9 @@ class ContextImpl extends Context { if (resolveInfo == null) { return null; } - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setClassName(packageName, resolveInfo.activityInfo.name); + Intent intent = new Intent(intentToResolve); + intent.setClassName(resolveInfo.activityInfo.applicationInfo.packageName, + resolveInfo.activityInfo.name); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return intent; } diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 441370a..c0226f8 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -1047,6 +1047,7 @@ public class SQLiteDatabase extends SQLiteClosable { closeClosable(); // finalize ALL statements queued up so far closePendingStatements(); + releaseCustomFunctions(); // close this database instance - regardless of its reference count value dbclose(); if (mConnectionPool != null) { @@ -1083,6 +1084,54 @@ public class SQLiteDatabase extends SQLiteClosable { private native void dbclose(); /** + * A callback interface for a custom sqlite3 function. + * This can be used to create a function that can be called from + * sqlite3 database triggers. + * @hide + */ + public interface CustomFunction { + public void callback(String[] args); + } + + /** + * Registers a CustomFunction callback as a function that can be called from + * sqlite3 database triggers. + * @param name the name of the sqlite3 function + * @param numArgs the number of arguments for the function + * @param function callback to call when the function is executed + * @hide + */ + public void addCustomFunction(String name, int numArgs, CustomFunction function) { + verifyDbIsOpen(); + synchronized (mCustomFunctions) { + int ref = native_addCustomFunction(name, numArgs, function); + if (ref != 0) { + // save a reference to the function for cleanup later + mCustomFunctions.add(new Integer(ref)); + } else { + throw new SQLiteException("failed to add custom function " + name); + } + } + } + + private void releaseCustomFunctions() { + synchronized (mCustomFunctions) { + for (int i = 0; i < mCustomFunctions.size(); i++) { + Integer function = mCustomFunctions.get(i); + native_releaseCustomFunction(function.intValue()); + } + mCustomFunctions.clear(); + } + } + + // list of CustomFunction references so we can clean up when the database closes + private final ArrayList<Integer> mCustomFunctions = + new ArrayList<Integer>(); + + private native int native_addCustomFunction(String name, int numArgs, CustomFunction function); + private native void native_releaseCustomFunction(int function); + + /** * Gets the database version. * * @return the database version @@ -1959,12 +2008,17 @@ public class SQLiteDatabase extends SQLiteClosable { } @Override - protected void finalize() { - if (isOpen()) { - Log.e(TAG, "close() was never explicitly called on database '" + - mPath + "' ", mStackTrace); - closeClosable(); - onAllReferencesReleased(); + protected void finalize() throws Throwable { + try { + if (isOpen()) { + Log.e(TAG, "close() was never explicitly called on database '" + + mPath + "' ", mStackTrace); + closeClosable(); + onAllReferencesReleased(); + releaseCustomFunctions(); + } + } finally { + super.finalize(); } } diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java index 02b6210..00b6864 100644 --- a/core/java/android/net/DownloadManager.java +++ b/core/java/android/net/DownloadManager.java @@ -350,8 +350,7 @@ public class DownloadManager { } if (!mRequestHeaders.isEmpty()) { - // TODO request headers support - throw new UnsupportedOperationException(); + encodeHttpHeaders(values); } putIfNonNull(values, Downloads.COLUMN_TITLE, mTitle); @@ -367,6 +366,15 @@ public class DownloadManager { return values; } + private void encodeHttpHeaders(ContentValues values) { + int index = 0; + for (Map.Entry<String, String> entry : mRequestHeaders.entrySet()) { + String headerString = entry.getKey() + ": " + entry.getValue(); + values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX + index, headerString); + index++; + } + } + private void putIfNonNull(ContentValues contentValues, String key, String value) { if (value != null) { contentValues.put(key, value); diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 9ad125b..31acb5b 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -247,13 +247,16 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { /** * {@inheritDoc} * - * <p>This method verifies the peer's certificate hostname after connecting. + * <p>This method verifies the peer's certificate hostname after connecting + * (unless created with {@link #getInsecure(int, SSLSessionCache)}). */ @Override public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close); s.setHandshakeTimeout(mHandshakeTimeoutMillis); - verifyHostname(s, host); + if (mSecure) { + verifyHostname(s, host); + } return s; } @@ -305,7 +308,8 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { /** * {@inheritDoc} * - * <p>This method verifies the peer's certificate hostname after connecting. + * <p>This method verifies the peer's certificate hostname after connecting + * (unless created with {@link #getInsecure(int, SSLSessionCache)}). */ @Override public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) @@ -313,20 +317,25 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket( host, port, localAddr, localPort); s.setHandshakeTimeout(mHandshakeTimeoutMillis); - verifyHostname(s, host); + if (mSecure) { + verifyHostname(s, host); + } return s; } /** * {@inheritDoc} * - * <p>This method verifies the peer's certificate hostname after connecting. + * <p>This method verifies the peer's certificate hostname after connecting + * (unless created with {@link #getInsecure(int, SSLSessionCache)}). */ @Override public Socket createSocket(String host, int port) throws IOException { OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port); s.setHandshakeTimeout(mHandshakeTimeoutMillis); - verifyHostname(s, host); + if (mSecure) { + verifyHostname(s, host); + } return s; } diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index a23a5a7..10f1d2b 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -289,6 +289,7 @@ public final class Calendar { DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC1); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC2); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC3); + DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.SYNC4); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, Calendars.NAME); DatabaseUtils.cursorStringToContentValuesIfPresent(cursor, cv, diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 1a4f8c0..2a612fe 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -1115,5 +1115,26 @@ public final class Downloads { * This download doesn't show in the UI or in the notifications. */ public static final int VISIBILITY_HIDDEN = 2; + + /** + * Constants related to HTTP request headers associated with each download. + */ + public static class RequestHeaders { + public static final String HEADERS_DB_TABLE = "request_headers"; + public static final String COLUMN_DOWNLOAD_ID = "download_id"; + public static final String COLUMN_HEADER = "header"; + public static final String COLUMN_VALUE = "value"; + + /** + * Path segment to add to a download URI to retrieve request headers + */ + public static final String URI_SEGMENT = "headers"; + + /** + * Prefix for ContentValues keys that contain HTTP header lines, to be passed to + * DownloadProvider.insert(). + */ + public static final String INSERT_KEY_PREFIX = "http_header_"; + } } } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index c469bcc..54cb4ca 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -543,6 +543,9 @@ public class SurfaceView extends View { } if (creating || formatChanged || sizeChanged || visibleChanged || realSizeChanged) { + for (SurfaceHolder.Callback c : callbacks) { + c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight); + } } if (redrawNeeded) { for (SurfaceHolder.Callback c : callbacks) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 05d380e..3a3ad8c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -16,6 +16,7 @@ package android.view; +import android.graphics.RectF; import com.android.internal.R; import com.android.internal.view.menu.MenuBuilder; @@ -1585,6 +1586,87 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility int mViewFlags; /** + * The transform matrix for the View. This transform is calculated internally + * based on the rotation, scaleX, and scaleY properties. The identity matrix + * is used by default. Do *not* use this variable directly; instead call + * getMatrix(), which will automatically recalculate the matrix if necessary + * to get the correct matrix based on the latest rotation and scale properties. + */ + private final Matrix mMatrix = new Matrix(); + + /** + * The transform matrix for the View. This transform is calculated internally + * based on the rotation, scaleX, and scaleY properties. The identity matrix + * is used by default. Do *not* use this variable directly; instead call + * getMatrix(), which will automatically recalculate the matrix if necessary + * to get the correct matrix based on the latest rotation and scale properties. + */ + private Matrix mInverseMatrix; + + /** + * An internal variable that tracks whether we need to recalculate the + * transform matrix, based on whether the rotation or scaleX/Y properties + * have changed since the matrix was last calculated. + */ + private boolean mMatrixDirty = false; + + /** + * An internal variable that tracks whether we need to recalculate the + * transform matrix, based on whether the rotation or scaleX/Y properties + * have changed since the matrix was last calculated. + */ + private boolean mInverseMatrixDirty = true; + + /** + * A variable that tracks whether we need to recalculate the + * transform matrix, based on whether the rotation or scaleX/Y properties + * have changed since the matrix was last calculated. This variable + * is only valid after a call to getMatrix(). + */ + boolean mMatrixIsIdentity = true; + + /** + * The degrees rotation around the pivot point. + */ + @ViewDebug.ExportedProperty + private float mRotation = 0f; + + /** + * The amount of scale in the x direction around the pivot point. A + * value of 1 means no scaling is applied. + */ + @ViewDebug.ExportedProperty + private float mScaleX = 1f; + + /** + * The amount of scale in the y direction around the pivot point. A + * value of 1 means no scaling is applied. + */ + @ViewDebug.ExportedProperty + private float mScaleY = 1f; + + /** + * The amount of scale in the x direction around the pivot point. A + * value of 1 means no scaling is applied. + */ + @ViewDebug.ExportedProperty + private float mPivotX = 0f; + + /** + * The amount of scale in the y direction around the pivot point. A + * value of 1 means no scaling is applied. + */ + @ViewDebug.ExportedProperty + private float mPivotY = 0f; + + /** + * The opacity of the View. This is a value from 0 to 1, where 0 means + * completely transparent and 1 means completely opaque. + */ + @ViewDebug.ExportedProperty + private float mAlpha = 1f; + + /** * The distance in pixels from the left edge of this view's parent * to the left edge of this view. * {@hide} @@ -3019,6 +3101,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Determine if this view has the FITS_SYSTEM_WINDOWS flag set. + * @return True if window has FITS_SYSTEM_WINDOWS set + * + * @hide + */ + public boolean isFitsSystemWindowsFlagSet() { + return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; + } + + /** * Returns the visibility status for this view. * * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. @@ -4406,9 +4498,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility final int y = (int) event.getY(); // Be lenient about moving outside of buttons - int slop = mTouchSlop; - if ((x < 0 - slop) || (x >= getWidth() + slop) || - (y < 0 - slop) || (y >= getHeight() + slop)) { + if (!pointInView(x, y, mTouchSlop)) { // Outside button removeTapCallback(); if ((mPrivateFlags & PRESSED) != 0) { @@ -4754,6 +4844,234 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * The transform matrix of this view, which is calculated based on the current + * roation, scale, and pivot properties. + * + * @see #getRotation() + * @see #getScaleX() + * @see #getScaleY() + * @see #getPivotX() + * @see #getPivotY() + * @return The current transform matrix for the view + */ + public Matrix getMatrix() { + if (mMatrixDirty) { + // transform-related properties have changed since the last time someone + // asked for the matrix; recalculate it with the current values + mMatrix.reset(); + mMatrix.setRotate(mRotation, mPivotX, mPivotY); + mMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY); + mMatrixDirty = false; + mMatrixIsIdentity = mMatrix.isIdentity(); + mInverseMatrixDirty = true; + } + return mMatrix; + } + + /** + * Utility method to retrieve the inverse of the current mMatrix property. + * We cache the matrix to avoid recalculating it when transform properties + * have not changed. + * + * @return The inverse of the current matrix of this view. + */ + Matrix getInverseMatrix() { + if (mInverseMatrixDirty) { + if (mInverseMatrix == null) { + mInverseMatrix = new Matrix(); + } + mMatrix.invert(mInverseMatrix); + mInverseMatrixDirty = false; + } + return mInverseMatrix; + } + + /** + * The degrees that the view is rotated around the pivot point. + * + * @see #getPivotX() + * @see #getPivotY() + * @return The degrees of rotation. + */ + public float getRotation() { + return mRotation; + } + + /** + * Sets the degrees that the view is rotated around the pivot point. + * + * @param rotation The degrees of rotation. + * @see #getPivotX() + * @see #getPivotY() + */ + public void setRotation(float rotation) { + if (mRotation != rotation) { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + mRotation = rotation; + mMatrixDirty = true; + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + + /** + * The amount that the view is scaled in x around the pivot point, as a proportion of + * the view's unscaled width. A value of 1, the default, means that no scaling is applied. + * + * @default 1.0f + * @see #getPivotX() + * @see #getPivotY() + * @return The scaling factor. + */ + public float getScaleX() { + return mScaleX; + } + + /** + * Sets the amount that the view is scaled in x around the pivot point, as a proportion of + * the view's unscaled width. A value of 1 means that no scaling is applied. + * + * @param scaleX The scaling factor. + * @see #getPivotX() + * @see #getPivotY() + */ + public void setScaleX(float scaleX) { + if (mScaleX != scaleX) { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + mScaleX = scaleX; + mMatrixDirty = true; + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + + /** + * The amount that the view is scaled in y around the pivot point, as a proportion of + * the view's unscaled height. A value of 1, the default, means that no scaling is applied. + * + * @default 1.0f + * @see #getPivotX() + * @see #getPivotY() + * @return The scaling factor. + */ + public float getScaleY() { + return mScaleY; + } + + /** + * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of + * the view's unscaled width. A value of 1 means that no scaling is applied. + * + * @param scaleY The scaling factor. + * @see #getPivotX() + * @see #getPivotY() + */ + public void setScaleY(float scaleY) { + if (mScaleY != scaleY) { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + mScaleY = scaleY; + mMatrixDirty = true; + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + + /** + * The x location of the point around which the view is {@link #setRotation(float) rotated} + * and {@link #setScaleX(float) scaled}. + * + * @see #getRotation() + * @see #getScaleX() + * @see #getScaleY() + * @see #getPivotY() + * @return The x location of the pivot point. + */ + public float getPivotX() { + return mPivotX; + } + + /** + * Sets the x location of the point around which the view is + * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. + * + * @param pivotX The x location of the pivot point. + * @see #getRotation() + * @see #getScaleX() + * @see #getScaleY() + * @see #getPivotY() + */ + public void setPivotX(float pivotX) { + if (mPivotX != pivotX) { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + mPivotX = pivotX; + mMatrixDirty = true; + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + + /** + * The y location of the point around which the view is {@link #setRotation(float) rotated} + * and {@link #setScaleY(float) scaled}. + * + * @see #getRotation() + * @see #getScaleX() + * @see #getScaleY() + * @see #getPivotY() + * @return The y location of the pivot point. + */ + public float getPivotY() { + return mPivotY; + } + + /** + * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} + * and {@link #setScaleY(float) scaled}. + * + * @param pivotY The y location of the pivot point. + * @see #getRotation() + * @see #getScaleX() + * @see #getScaleY() + * @see #getPivotY() + */ + public void setPivotY(float pivotY) { + if (mPivotY != pivotY) { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + mPivotY = pivotY; + mMatrixDirty = true; + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + + /** + * The opacity of the view. This is a value from 0 to 1, where 0 means the view is + * completely transparent and 1 means the view is completely opaque. + * + * @default 1.0f + * @return The opacity of the view. + */ + public float getAlpha() { + return mAlpha; + } + + /** + * Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is + * completely transparent and 1 means the view is completely opaque. + * + * @param alpha The opacity of the view. + */ + public void setAlpha(float alpha) { + mAlpha = alpha; + invalidate(); + } + + /** * Top position of this view relative to its parent. * * @return The top of this view, in pixels. @@ -4764,6 +5082,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Sets the top position of this view relative to its parent. + * + * @param top The top of this view, in pixels. + */ + public final void setTop(int top) { + if (top != mTop) { + Matrix m = getMatrix(); + if (mMatrixIsIdentity) { + final ViewParent p = mParent; + if (p != null && mAttachInfo != null) { + final int[] location = mAttachInfo.mInvalidateChildLocation; + final Rect r = mAttachInfo.mTmpInvalRect; + int minTop = Math.min(mTop, top); + location[0] = mLeft; + location[1] = minTop; + r.set(0, 0, mRight - mLeft, mBottom - minTop); + p.invalidateChildInParent(location, r); + } + } else { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + } + mTop = top; + if (!mMatrixIsIdentity) { + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + } + + /** * Bottom position of this view relative to its parent. * * @return The bottom of this view, in pixels. @@ -4774,6 +5123,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Sets the bottom position of this view relative to its parent. + * + * @param bottom The bottom of this view, in pixels. + */ + public final void setBottom(int bottom) { + if (bottom != mBottom) { + Matrix m = getMatrix(); + if (mMatrixIsIdentity) { + final ViewParent p = mParent; + if (p != null && mAttachInfo != null) { + final int[] location = mAttachInfo.mInvalidateChildLocation; + final Rect r = mAttachInfo.mTmpInvalRect; + int maxBottom = Math.max(mBottom, bottom); + location[0] = mLeft; + location[1] = mTop; + r.set(0, 0, mRight - mLeft, maxBottom - mTop); + p.invalidateChildInParent(location, r); + } + } else { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + } + mBottom = bottom; + if (!mMatrixIsIdentity) { + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + } + + /** * Left position of this view relative to its parent. * * @return The left edge of this view, in pixels. @@ -4784,6 +5164,37 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Sets the left position of this view relative to its parent. + * + * @param left The bottom of this view, in pixels. + */ + public final void setLeft(int left) { + if (left != mLeft) { + Matrix m = getMatrix(); + if (mMatrixIsIdentity) { + final ViewParent p = mParent; + if (p != null && mAttachInfo != null) { + final int[] location = mAttachInfo.mInvalidateChildLocation; + final Rect r = mAttachInfo.mTmpInvalRect; + int minLeft = Math.min(mLeft, left); + location[0] = minLeft; + location[1] = mTop; + r.set(0, 0, mRight - minLeft, mBottom - mTop); + p.invalidateChildInParent(location, r); + } + } else { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + } + mLeft = left; + if (!mMatrixIsIdentity) { + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + } + + /** * Right position of this view relative to its parent. * * @return The right edge of this view, in pixels. @@ -4794,12 +5205,149 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility } /** + * Sets the right position of this view relative to its parent. + * + * @param right The bottom of this view, in pixels. + */ + public final void setRight(int right) { + if (right != mRight) { + Matrix m = getMatrix(); + if (mMatrixIsIdentity) { + final ViewParent p = mParent; + if (p != null && mAttachInfo != null) { + final int[] location = mAttachInfo.mInvalidateChildLocation; + final Rect r = mAttachInfo.mTmpInvalRect; + int maxRight = Math.max(mRight, right); + location[0] = mLeft; + location[1] = mTop; + r.set(0, 0, maxRight - mLeft, mBottom - mTop); + p.invalidateChildInParent(location, r); + } + } else { + // Double-invalidation is necessary to capture view's old and new areas + invalidate(); + } + mRight = right; + if (!mMatrixIsIdentity) { + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } + } + + /** + * The horizontal location of this view relative to its parent. This value is equivalent to the + * {@link #getLeft() left} property. + * + * @return The horizontal position of this view, in pixels. + */ + public int getX() { + return mLeft; + } + + /** + * Sets the horizontal location of this view relative to its parent. Setting this value will + * affect both the {@link #setLeft(int) left} and {@link #setRight(int) right} properties + * of this view. + * + * @param x The horizontal position of this view, in pixels. + */ + public void setX(int x) { + offsetLeftAndRight(x - mLeft); + } + + /** + * The vertical location of this view relative to its parent. This value is equivalent to the + * {@link #getTop() left} property. + * + * @return The vertical position of this view, in pixels. + */ + public int getY() { + return mTop; + } + + /** + * Sets the vertical location of this view relative to its parent. Setting this value will + * affect both the {@link #setTop(int) left} and {@link #setBottom(int) right} properties + * of this view. + * + * @param y The vertical position of this view, in pixels. + */ + public void setY(int y) { + offsetTopAndBottom(y - mTop); + } + + /** * Hit rectangle in parent's coordinates * * @param outRect The hit rectangle of the view. */ public void getHitRect(Rect outRect) { - outRect.set(mLeft, mTop, mRight, mBottom); + Matrix m = getMatrix(); + if (mMatrixIsIdentity || mAttachInfo == null) { + outRect.set(mLeft, mTop, mRight, mBottom); + } else { + final RectF tmpRect = mAttachInfo.mTmpTransformRect; + tmpRect.set(-mPivotX, -mPivotY, + getWidth() - mPivotX, getHeight() - mPivotY); + m.mapRect(tmpRect); + outRect.set((int)tmpRect.left + mLeft, (int)tmpRect.top + mTop, + (int)tmpRect.right + mLeft, (int)tmpRect.bottom + mTop); + } + } + + /** + * This method detects whether the given event is inside the view and, if so, + * handles it via the dispatchEvent(MotionEvent) method. + * + * @param ev The event that is being dispatched. + * @param parentX The x location of the event in the parent's coordinates. + * @param parentY The y location of the event in the parent's coordinates. + * @return true if the event was inside this view, false otherwise. + */ + boolean dispatchTouchEvent(MotionEvent ev, float parentX, float parentY) { + float localX = parentX - mLeft; + float localY = parentY - mTop; + Matrix m = getMatrix(); + if (!mMatrixIsIdentity && mAttachInfo != null) { + // non-identity matrix: transform the point into the view's coordinates + final float[] localXY = mAttachInfo.mTmpTransformLocation; + localXY[0] = localX; + localXY[1] = localY; + getInverseMatrix().mapPoints(localXY); + localX = localXY[0]; + localY = localXY[1]; + } + if (localX >= 0 && localY >= 0 && + localX < (mRight - mLeft) && localY < (mBottom - mTop)) { + ev.setLocation(localX, localY); + return dispatchTouchEvent(ev); + } + return false; + } + + /** + * Utility method to determine whether the given point, in local coordinates, + * is inside the view, where the area of the view is expanded by the slop factor. + * This method is called while processing touch-move events to determine if the event + * is still within the view. + */ + private boolean pointInView(float localX, float localY, float slop) { + Matrix m = getMatrix(); + if (!mMatrixIsIdentity && mAttachInfo != null) { + // non-identity matrix: transform the point into the view's coordinates + final float[] localXY = mAttachInfo.mTmpTransformLocation; + localXY[0] = localX; + localXY[1] = localY; + getInverseMatrix().mapPoints(localXY); + localX = localXY[0]; + localY = localXY[1]; + } + if (localX > -slop && localY > -slop && + localX < ((mRight - mLeft) + slop) && localY < ((mBottom - mTop) + slop)) { + return true; + } + return false; } /** @@ -4862,8 +5410,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * @param offset the number of pixels to offset the view by */ public void offsetTopAndBottom(int offset) { - mTop += offset; - mBottom += offset; + if (offset != 0) { + Matrix m = getMatrix(); + if (mMatrixIsIdentity) { + final ViewParent p = mParent; + if (p != null && mAttachInfo != null) { + final int[] location = mAttachInfo.mInvalidateChildLocation; + final Rect r = mAttachInfo.mTmpInvalRect; + int minTop = offset < 0 ? mTop + offset : mTop; + int maxBottom = offset < 0 ? mBottom : mBottom + offset; + location[0] = mLeft; + location[1] = minTop; + r.set(0, 0, mRight - mLeft, maxBottom - minTop); + p.invalidateChildInParent(location, r); + } + } else { + invalidate(); + } + mTop += offset; + mBottom += offset; + if (!mMatrixIsIdentity) { + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } } /** @@ -4872,8 +5442,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * @param offset the numer of pixels to offset the view by */ public void offsetLeftAndRight(int offset) { - mLeft += offset; - mRight += offset; + if (offset != 0) { + Matrix m = getMatrix(); + if (mMatrixIsIdentity) { + final ViewParent p = mParent; + if (p != null && mAttachInfo != null) { + final int[] location = mAttachInfo.mInvalidateChildLocation; + final Rect r = mAttachInfo.mTmpInvalRect; + int minLeft = offset < 0 ? mLeft + offset : mLeft; + int maxRight = offset < 0 ? mRight : mRight + offset; + location[0] = minLeft; + location[1] = mTop; + r.set(0, 0, maxRight - minLeft, mBottom - mTop); + p.invalidateChildInParent(location, r); + } + } else { + invalidate(); + } + mLeft += offset; + mRight += offset; + if (!mMatrixIsIdentity) { + mPrivateFlags |= DRAWN; // force another invalidation with the new orientation + invalidate(); + } + } } /** @@ -7936,7 +8528,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * without resorting to another data structure. * * The specified key should be an id declared in the resources of the - * application to ensure it is unique. Keys identified as belonging to + * application to ensure it is unique (see the <a + * href={@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). + * Keys identified as belonging to * the Android framework or not associated with any package will cause * an {@link IllegalArgumentException} to be thrown. * @@ -9191,6 +9785,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility */ final int[] mInvalidateChildLocation = new int[2]; + + /** + * Global to the view hierarchy used as a temporary for dealing with + * x/y location when view is transformed. + */ + final float[] mTmpTransformLocation = new float[2]; + /** * The view tree observer used to dispatch global events like * layout, pre-draw, touch mode change, etc. @@ -9227,6 +9828,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility final Rect mTmpInvalRect = new Rect(); /** + * Temporary for use in computing hit areas with transformed views + */ + final RectF mTmpTransformRect = new RectF(); + + /** + * Temporary for use in computing invalidation areas with transformed views + */ + final float[] mTmpTransformBounds = new float[8]; + + /** * Temporary list for use in collecting focusable descendents of a view. */ final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 34777ce..22ad27a 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -16,6 +16,7 @@ package android.view; +import android.graphics.Matrix; import com.android.internal.R; import android.content.Context; @@ -867,21 +868,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { - child.getHitRect(frame); - if (frame.contains(scrolledXInt, scrolledYInt)) { - // offset the event to the view's coordinate system - final float xc = scrolledXFloat - child.mLeft; - final float yc = scrolledYFloat - child.mTop; - ev.setLocation(xc, yc); + if (child.dispatchTouchEvent(ev, scrolledXFloat, scrolledYFloat)) { child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; - if (child.dispatchTouchEvent(ev)) { - // Event handled, we have a target now. - mMotionTarget = child; - return true; - } - // The event didn't get handled, try the next view. - // Don't reset the event's location, it's not - // necessary here. + mMotionTarget = child; + return true; } } } @@ -937,8 +927,21 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // finally offset the event to the target's coordinate system and // dispatch the event. - final float xc = scrolledXFloat - (float) target.mLeft; - final float yc = scrolledYFloat - (float) target.mTop; + float xc; + float yc; + Matrix m = getMatrix(); + if (mMatrixIsIdentity || mAttachInfo == null) { + xc = scrolledXFloat - (float) target.mLeft; + yc = scrolledYFloat - (float) target.mTop; + } else { + // non-identity matrix: transform the point into the view's coordinates + final float[] localXY = mAttachInfo.mTmpTransformLocation; + localXY[0] = scrolledXFloat; + localXY[1] = scrolledYFloat; + getInverseMatrix().mapPoints(localXY); + xc = localXY[0] - (float) target.mLeft; + yc = localXY[1] - (float) target.mTop; + } ev.setLocation(xc, yc); if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) { @@ -1609,25 +1612,36 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - float alpha = 1.0f; + float alpha = child.getAlpha(); + Matrix childMatrix = child.getMatrix(); - if (transformToApply != null) { - if (concatMatrix) { - int transX = 0; - int transY = 0; - if (hasNoCache) { - transX = -sx; - transY = -sy; + if (transformToApply != null || alpha < 1.0f || !child.mMatrixIsIdentity) { + int transX = 0; + int transY = 0; + if (hasNoCache) { + transX = -sx; + transY = -sy; + } + if (transformToApply != null) { + if (concatMatrix) { + // Undo the scroll translation, apply the transformation matrix, + // then redo the scroll translate to get the correct result. + canvas.translate(-transX, -transY); + canvas.concat(transformToApply.getMatrix()); + canvas.translate(transX, transY); + mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; } - // Undo the scroll translation, apply the transformation matrix, - // then redo the scroll translate to get the correct result. + float transformAlpha = transformToApply.getAlpha(); + if (transformAlpha < 1.0f) { + alpha *= transformToApply.getAlpha(); + mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; + } + } + if (!child.mMatrixIsIdentity) { canvas.translate(-transX, -transY); - canvas.concat(transformToApply.getMatrix()); + canvas.concat(child.getMatrix()); canvas.translate(transX, transY); - mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; } - - alpha = transformToApply.getAlpha(); if (alpha < 1.0f) { mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; } @@ -2498,6 +2512,41 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int[] location = attachInfo.mInvalidateChildLocation; location[CHILD_LEFT_INDEX] = child.mLeft; location[CHILD_TOP_INDEX] = child.mTop; + Matrix childMatrix = child.getMatrix(); + if (!childMatrix.isIdentity()) { + float[] boundingRectPoints = attachInfo.mTmpTransformBounds; + boundingRectPoints[0] = dirty.left; // upper left + boundingRectPoints[1] = dirty.top; + boundingRectPoints[2] = dirty.right; // upper right + boundingRectPoints[3] = dirty.top; + boundingRectPoints[4] = dirty.right; // lower right + boundingRectPoints[5] = dirty.bottom; + boundingRectPoints[6] = dirty.left; // lower left + boundingRectPoints[7] = dirty.bottom; + childMatrix.mapPoints(boundingRectPoints); + // find the mind/max points to get the bounding rect + float left = Float.MAX_VALUE; + float top = Float.MAX_VALUE; + float right = -Float.MAX_VALUE; + float bottom = -Float.MAX_VALUE; + for (int i = 0; i < 8; i += 2) { + float x = boundingRectPoints[i]; + float y = boundingRectPoints[i+1]; + if (x < left) { + left = x; + } + if (x > right) { + right = x; + } + if (y < top) { + top = y; + } + if (y > bottom) { + bottom = y; + } + } + dirty.set((int)left, (int)top, (int)(right + .5f), (int)(bottom + .5f)); + } // If the child is drawing an animation, we want to copy this flag onto // ourselves and the parent to make sure the invalidate request goes @@ -2532,6 +2581,39 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } parent = parent.invalidateChildInParent(location, dirty); + Matrix m = getMatrix(); + if (!m.isIdentity()) { + float[] boundingRectPoints = { + dirty.left - mLeft, dirty.top - mTop, // upper left + dirty.right - mLeft, dirty.top - mTop, // upper right + dirty.right - mLeft, dirty.bottom - mTop, // lower right + dirty.left - mLeft, dirty.bottom - mTop // lower left + }; + m.mapPoints(boundingRectPoints); + // find the mind/max points to get the bounding rect + float left = Float.MAX_VALUE; + float top = Float.MAX_VALUE; + float right = Float.MIN_VALUE; + float bottom = Float.MIN_VALUE; + for (int i = 0; i < 8; i += 2) { + float x = boundingRectPoints[i]; + float y = boundingRectPoints[i+1]; + if (x < left) { + left = x; + } + if (x > right) { + right = x; + } + if (y < top) { + top = y; + } + if (y > bottom) { + bottom = y; + } + } + dirty.set((int)left + mLeft, (int)top + mTop, (int)(right + .5f) + mLeft, + (int)(bottom + .5f) + mTop); + } } while (parent != null); } } diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java index 6cf455c..f37021b 100644 --- a/core/java/com/android/internal/app/ActionBarImpl.java +++ b/core/java/com/android/internal/app/ActionBarImpl.java @@ -34,6 +34,7 @@ import android.widget.LinearLayout; import android.widget.SpinnerAdapter; import android.widget.ViewAnimator; +import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -70,6 +71,8 @@ public class ActionBarImpl extends ActionBar { private int mContextDisplayMode; + private boolean mClosingContext; + final Handler mHandler = new Handler(); final Runnable mCloseContext = new Runnable() { public void run() { @@ -77,6 +80,7 @@ public class ActionBarImpl extends ActionBar { if (mLowerContextView != null) { mLowerContextView.removeAllViews(); } + mClosingContext = false; } }; @@ -195,6 +199,14 @@ public class ActionBarImpl extends ActionBar { if (mContextMode != null) { mContextMode.finish(); } + + // Don't wait for the close context mode animation to finish. + if (mClosingContext) { + mAnimatorView.clearAnimation(); + mHandler.removeCallbacks(mCloseContext); + mCloseContext.run(); + } + mContextMode = new ContextMode(callback); if (callback.onCreateContextMode(mContextMode, mContextMode.getMenu())) { mContextMode.invalidate(); @@ -327,6 +339,7 @@ public class ActionBarImpl extends ActionBar { public class ContextMode extends ActionBar.ContextMode { private ContextModeCallback mCallback; private ActionMenu mMenu; + private WeakReference<View> mCustomView; public ContextMode(ContextModeCallback callback) { mCallback = callback; @@ -344,6 +357,7 @@ public class ActionBarImpl extends ActionBar { mAnimatorView.setDisplayedChild(NORMAL_VIEW); // Clear out the context mode views after the animation finishes + mClosingContext = true; mHandler.postDelayed(mCloseContext, mAnimatorView.getOutAnimation().getDuration()); if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) { @@ -363,6 +377,7 @@ public class ActionBarImpl extends ActionBar { @Override public void setCustomView(View view) { mUpperContextView.setCustomView(view); + mCustomView = new WeakReference<View>(view); } @Override @@ -374,7 +389,22 @@ public class ActionBarImpl extends ActionBar { public void setTitle(CharSequence title) { mUpperContextView.setTitle(title); } + + @Override + public CharSequence getTitle() { + return mUpperContextView.getTitle(); + } + + @Override + public CharSequence getSubtitle() { + return mUpperContextView.getSubtitle(); + } + @Override + public View getCustomView() { + return mCustomView != null ? mCustomView.get() : null; + } + public void dispatchOnContextItemClicked(MenuItem item) { ActionMenuItem actionItem = (ActionMenuItem) item; if (!actionItem.invoke()) { diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java index 0f895f0..b57b7a8 100644 --- a/core/java/com/android/internal/widget/ActionBarContextView.java +++ b/core/java/com/android/internal/widget/ActionBarContextView.java @@ -105,6 +105,14 @@ public class ActionBarContextView extends ViewGroup { initTitle(); } + public CharSequence getTitle() { + return mTitle; + } + + public CharSequence getSubtitle() { + return mSubtitle; + } + private void initTitle() { if (mTitleLayout == null) { LayoutInflater inflater = LayoutInflater.from(getContext()); diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 48707b9..fbff8ae 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -91,6 +91,7 @@ public class ActionBarView extends ViewGroup { private View mCustomNavView; private boolean mShowMenu; + private boolean mUserTitle; private MenuBuilder mOptionsMenu; private ActionMenuView mMenuView; @@ -212,7 +213,30 @@ public class ActionBarView extends ViewGroup { return mTitle; } + /** + * Set the action bar title. This will always replace or override window titles. + * @param title Title to set + * + * @see #setWindowTitle(CharSequence) + */ public void setTitle(CharSequence title) { + mUserTitle = true; + setTitleImpl(title); + } + + /** + * Set the window title. A window title will always be replaced or overridden by a user title. + * @param title Title to set + * + * @see #setTitle(CharSequence) + */ + public void setWindowTitle(CharSequence title) { + if (!mUserTitle) { + setTitleImpl(title); + } + } + + private void setTitleImpl(CharSequence title) { mTitle = title; if (mTitleView != null) { mTitleView.setText(title); diff --git a/core/jni/Android.mk b/core/jni/Android.mk index d19cae4..d61d56e 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -188,7 +188,6 @@ LOCAL_SHARED_LIBRARIES := \ libssl \ libicuuc \ libicui18n \ - libicudata \ libmedia \ libwpa_client \ libjpeg diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp index 5a92193..290b532 100644 --- a/core/jni/android_database_SQLiteDatabase.cpp +++ b/core/jni/android_database_SQLiteDatabase.cpp @@ -62,6 +62,7 @@ enum { }; static jfieldID offset_db_handle; +static jmethodID method_custom_function_callback; static char *createStr(const char *path, short extra) { int len = strlen(path) + extra; @@ -458,6 +459,62 @@ static void native_finalize(JNIEnv* env, jobject object, jint statementId) } } +static void custom_function_callback(sqlite3_context * context, int argc, sqlite3_value ** argv) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + if (!env) { + LOGE("custom_function_callback cannot call into Java on this thread"); + return; + } + + // pack up the arguments into a string array + jobjectArray strArray = env->NewObjectArray(argc, env->FindClass("java/lang/String"), NULL); + if (!strArray) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return; + } + for (int i = 0; i < argc; i++) { + char* arg = (char *)sqlite3_value_text(argv[i]); + jobject obj = env->NewStringUTF(arg); + if (!obj) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return; + } + env->SetObjectArrayElement(strArray, i, obj); + env->DeleteLocalRef(obj); + } + + // get global ref to CustomFunction object from our user data + jobject function = (jobject)sqlite3_user_data(context); + env->CallVoidMethod(function, method_custom_function_callback, strArray); +} + +static jint native_addCustomFunction(JNIEnv* env, jobject object, + jstring name, jint numArgs, jobject function) +{ + sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle); + char const *nameStr = env->GetStringUTFChars(name, NULL); + jobject ref = env->NewGlobalRef(function); + LOGD("native_addCustomFunction %s ref: %d", nameStr, ref); + int err = sqlite3_create_function(handle, nameStr, numArgs, SQLITE_UTF8, + (void *)ref, custom_function_callback, NULL, NULL); + env->ReleaseStringUTFChars(name, nameStr); + + if (err == SQLITE_OK) + return (int)ref; + else { + LOGE("sqlite3_create_function returned %d", err); + env->DeleteGlobalRef(ref); + throw_sqlite3_exception(env, handle); + return 0; + } +} + +static void native_releaseCustomFunction(JNIEnv* env, jobject object, jint ref) +{ + LOGD("native_releaseCustomFunction %d", ref); + env->DeleteGlobalRef((jobject)ref); +} + static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ @@ -472,6 +529,10 @@ static JNINativeMethod sMethods[] = {"native_getDbLookaside", "()I", (void *)native_getDbLookaside}, {"releaseMemory", "()I", (void *)native_releaseMemory}, {"native_finalize", "(I)V", (void *)native_finalize}, + {"native_addCustomFunction", + "(Ljava/lang/String;ILandroid/database/sqlite/SQLiteDatabase$CustomFunction;)I", + (void *)native_addCustomFunction}, + {"native_releaseCustomFunction", "(I)V", (void *)native_releaseCustomFunction}, }; int register_android_database_SQLiteDatabase(JNIEnv *env) @@ -490,6 +551,17 @@ int register_android_database_SQLiteDatabase(JNIEnv *env) return -1; } + clazz = env->FindClass("android/database/sqlite/SQLiteDatabase$CustomFunction"); + if (clazz == NULL) { + LOGE("Can't find android/database/sqlite/SQLiteDatabase$CustomFunction\n"); + return -1; + } + method_custom_function_callback = env->GetMethodID(clazz, "callback", "([Ljava/lang/String;)V"); + if (method_custom_function_callback == NULL) { + LOGE("Can't find method SQLiteDatabase.CustomFunction.callback\n"); + return -1; + } + return AndroidRuntime::registerNativeMethods(env, "android/database/sqlite/SQLiteDatabase", sMethods, NELEM(sMethods)); } diff --git a/core/res/res/values-xlarge/config.xml b/core/res/res/values-xlarge/config.xml new file mode 100644 index 0000000..2640662 --- /dev/null +++ b/core/res/res/values-xlarge/config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Component to be used as the status bar service. Must implement the IStatusBar + interface. This name is in the ComponentName flattened format (package/class) --> + <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.tablet.TabletStatusBarService</string> +</resources> + diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 689f73a..ec0d83c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -22,7 +22,7 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Component to be used as the status bar service. Must implement the IStatusBar interface. This name is in the ComponentName flattened format (package/class) --> - <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.StatusBarService</string> + <string name="config_statusBarComponent">com.android.systemui/com.android.systemui.statusbar.PhoneStatusBarService</string> <!-- Do not translate. Defines the slots for the right-hand side icons. That is to say, the icons in the status bar that are not notifications. --> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 4d67bdd..679e642 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -19,9 +19,9 @@ --> <resources> <!-- The width that is used when creating thumbnails of applications. --> - <dimen name="thumbnail_width">84dp</dimen> + <dimen name="thumbnail_width">0dp</dimen> <!-- The height that is used when creating thumbnails of applications. --> - <dimen name="thumbnail_height">63dp</dimen> + <dimen name="thumbnail_height">0dp</dimen> <!-- The standard size (both width and height) of an application icon that will be displayed in the app launcher and elsewhere. --> <dimen name="app_icon_size">48dip</dimen> diff --git a/docs/html/guide/topics/resources/available-resources.jd b/docs/html/guide/topics/resources/available-resources.jd index 09c55a5..19babee 100644 --- a/docs/html/guide/topics/resources/available-resources.jd +++ b/docs/html/guide/topics/resources/available-resources.jd @@ -18,23 +18,6 @@ of application resource that you can provide in your resources directory ({@code <p>Here's a brief summary of each resource type:</p> -<div class="sidebox-wrapper"> -<div class="sidebox"> -<h2>{@code R.id} Is Not a Resource</h2> - -<p>You will often use an {@code R.id} integer to handle {@link android.view.View} objects in -your UI. Although the {@code id} is a subclass of the {@code R} class, it is not considered a -"resource" because it is not a reference to an externalized application resource. The {@code id} -is simply a unique identifier that allows you to handle elements in your UI by instantiating -objects with {@link android.app.Activity#findViewById(int) findViewById()}.</p> - -<p>For information about using {@code R.id} with your UI, see <a -href="{@docRoot}guide/topics/ui/declaring-layout.html#attributes">Declaring Layout</a>.</p> - -</div> -</div> - - <dl> <dt><a href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a></dt> <dd>Define pre-determined animations.<br/> diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd index d8de16a..1e4cca7 100644 --- a/docs/html/guide/topics/resources/drawable-resource.jd +++ b/docs/html/guide/topics/resources/drawable-resource.jd @@ -18,32 +18,50 @@ and draw on the screen. There are several different types of drawables:</p> <dl> <dt><a href="#Bitmap">Bitmap File</a><dt> <dd>A bitmap graphic file ({@code .png}, {@code .jpg}, or {@code .gif}). - A {@link android.graphics.drawable.BitmapDrawable}.</dd> + Creates a {@link android.graphics.drawable.BitmapDrawable}.</dd> <dt><a href="#NinePatch">Nine-Patch File</a></dt> <dd>A PNG file with stretchable regions to allow image resizing based on content ({@code -.9.png}). A {@link android.graphics.drawable.NinePatchDrawable}.</dd> -<!-- <dt><a href="#BitmapAlias">Bitmap Alias</a><dt> - <dd>An alias for a drawable.</dd> --> +.9.png}). Creates a {@link android.graphics.drawable.NinePatchDrawable}.</dd> + <dt><a href="#LayerList">Layer List</a></dt> + <dd>A Drawable that manages an array of other Drawables. These are drawn in array order, so the +element with the largest index is be drawn on top. Creates a {@link +android.graphics.drawable.LayerDrawable}.</dd> <dt><a href="#StateList">State List</a></dt> <dd>An XML file that references different bitmap graphics for different states (for example, to use a different image when a button is pressed). - A {@link android.graphics.drawable.StateListDrawable}.</dd> - <dt><a href="#Color">Color</a></dt> - <dd>A resource defined in XML that specifies a rectangle of color, with - optionally rounded corners. A {@link android.graphics.drawable.PaintDrawable}.</dd> - <dt><a href="#Shape">Shape</a></dt> + Creates a {@link android.graphics.drawable.StateListDrawable}.</dd> + <dt><a href="#LevelList">Level List</a></dt> + <dd>An XML file that defines a Drawable that manages a number of alternate Drawables, each +assigned a maximum numerical value. Creates a {@link +android.graphics.drawable.LevelListDrawable}.</dd> + <dt><a href="#Transition">Transition Drawable</a></dt> + <dd>An XML file that defines a Drawable that can cross-fade between two drawable resources. +Creates a {@link android.graphics.drawable.TransitionDrawable}.</dd> + <dt><a href="#Clip">Clip Drawable</a></dt> + <dd>An XML file that defines a drawable that clips another Drawable based on this Drawable's +current level value. Creates a {@link android.graphics.drawable.ClipDrawable}.</dd> + <dt><a href="#Scale">Scale Drawable</a></dt> + <dd>An XML file that defines a drawable that changes the size of another Drawable based on its +current level value. Creates a {@link android.graphics.drawable.ScaleDrawable}</dd> + <dt><a href="#Shape">Shape Drawable</a></dt> <dd>An XML file that defines a geometric shape, including colors and gradients. - A {@link android.graphics.drawable.ShapeDrawable}.</dd> + Creates a {@link android.graphics.drawable.ShapeDrawable}.</dd> </dl> -<p>Documentation for the {@link android.graphics.drawable.AnimationDrawable} resource -is in the <a href="animation-resource.html">Animation Resource</a> document.</p> +<p>Also see the <a href="animation-resource.html">Animation Resource</a> document for how to +create an {@link android.graphics.drawable.AnimationDrawable}.</p> + + -<h2 id="Bitmap">Bitmap File</h2> -<p>A basic bitmap image. Android supports basic bitmap files in a few different formats: +<h2 id="Bitmap">Bitmap</h2> + +<p>A bitmap image. Android supports bitmap files in a three formats: {@code .png} (preferred), {@code .jpg} (acceptable), {@code .gif} (discouraged).</p> +<p>You can reference a bitmap file directly, using the filename as the resource ID, or create an +alias resource ID in XML.</p> + <p class="note"><strong>Note:</strong> Bitmap files may be automatically optimized with lossless image compression by the <a href="{@docRoot}guide/developing/tools/aapt.html">aapt</a> tool. For example, a true-color PNG that does not require more than 256 colors may be converted to an 8-bit @@ -52,11 +70,18 @@ memory. So be aware that the image binaries placed in this directory can change you plan on reading an image as a bit stream in order to convert it to a bitmap, put your images in the <code>res/raw/</code> folder instead, where they will not be optimized.</p> + +<h3 id="BitmapFile">Bitmap File</h3> + +<p>A bitmap file is a {@code .png}, {@code .jpg}, or {@code .gif} file. Android creates a {@link +android.graphics.drawable.Drawable} +resource for any of these files when you save them in the {@code res/drawable/} directory.</p> + <dl class="xml"> <dt>file location:</dt> <dd><code>res/drawable/<em>filename</em>.png</code> ({@code .png}, {@code .jpg}, or {@code .gif})<br/> -The filename will be used as the resource ID.</dd> +The filename is used as the resource ID.</dd> <dt>compiled resource datatype:</dt> <dd>Resource pointer to a {@link android.graphics.drawable.BitmapDrawable}.</dd> @@ -68,15 +93,16 @@ In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> </dd> <dt>example:</dt> -<dd>With an image saved at <code>res/drawable/myimage.png</code>, this layout XML will apply + +<dd>With an image saved at <code>res/drawable/myimage.png</code>, this layout XML applies the image to a View: <pre> <ImageView android:layout_height="wrap_content" android:layout_width="wrap_content" - <strong>android:src="@drawable/myimage"</strong> /> + android:src="@drawable/myimage" /> </pre> -<p>This application code will retrieve the image as a {@link +<p>The following application code retrieves the image as a {@link android.graphics.drawable.Drawable}:</p> <pre> Resources res = {@link android.content.Context#getResources()}; @@ -97,50 +123,218 @@ Drawable drawable = res.{@link android.content.res.Resources#getDrawable(int) ge +<h3 id="XmlBitmap">XML Bitmap</h3> + +<p>An XML bitmap is a resource defined in XML that points to a bitmap file. The effect is an alias for a +raw bitmap file. The XML can specify additional properties for the bitmap such as dithering and tiling.</p> +<p class="note"><strong>Note:</strong> You can use a {@code <bitmap>} element as a child of +an {@code <item>} element. For +example, when creating a <a href="#StateList">state list</a> or <a href="#LayerList">layer list</a>, +you can exclude the {@code android:drawable} +attribute from an {@code <item>} element and nest a {@code <bitmap>} inside it +that defines the drawable item.</p> +<dl class="xml"> -<h2 id="NinePatch">Nine-Patch File</h2> +<dt>file location:</dt> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> + +<dt>compiled resource datatype:</dt> +<dd>Resource pointer to a {@link android.graphics.drawable.BitmapDrawable}.</dd> + +<dt>resource reference:</dt> +<dd> +In Java: <code>R.drawable.<em>filename</em></code></li><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> +</dd> + +<dt>syntax:</dt> +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#bitmap-element">bitmap</a> + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@[package:]drawable/<em>drawable_resource</em>" + android:antialias=["true" | "false"] + android:dither=["true" | "false"] + android:filter=["true" | "false"] + android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" | + "fill_vertical" | "center_horizontal" | "fill_horizontal" | + "center" | "fill" | "clip_vertical" | "clip_horizontal"] + android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] /> +</pre> +</dd> + + +<dt>elements:</dt> +<dd> +<dl class="tag-list"> + + <dt id="bitmap-element"><code><bitmap></code></dt> + <dd>Defines the bitmap source and its properties. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. This is required only if the +<code><bitmap></code> is the root element—it is not needed when the +<code><bitmap></code> is nested inside an <code><item></code>.</dd> + <dt><code>android:src</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable +resource.</dd> + <dt><code>android:antialias</code></dt> + <dd><em>Boolean</em>. Enables or disables antialiasing.</dd> + <dt><code>android:dither</code></dt> + <dd><em>Boolean</em>. Enables or disables dithering of the bitmap if the bitmap does not +have the same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with an RGB 565 +screen).</dd> + <dt><code>android:filter</code></dt> + <dd><em>Boolean</em>. Enables or disables bitmap filtering. Filtering is used when the +bitmap is shrunk or stretched to smooth its apperance.</dd> + <dt><code>android:gravity</code></dt> + <dd><em>Keyword</em>. Defines the gravity for the bitmap. The gravity indicates where to +position the drawable in its container if the bitmap is smaller than the container. + <p>Must be one or more (separated by '|') of the following constant values:</p> +<table> +<tr><th>Value</th><th>Description</th></tr> +<tr><td><code>top</code></td> +<td>Put the object at the top of its container, not changing its size.</td></tr> +<tr><td><code>bottom</code></td> +<td>Put the object at the bottom of its container, not changing its size. </td></tr> +<tr><td><code>left</code></td> +<td>Put the object at the left edge of its container, not changing its size. </td></tr> +<tr><td><code>right</code></td> +<td>Put the object at the right edge of its container, not changing its size. </td></tr> +<tr><td><code>center_vertical</code></td> +<td>Place object in the vertical center of its container, not changing its size. </td></tr> +<tr><td><code>fill_vertical</code></td> +<td>Grow the vertical size of the object if needed so it completely fills its container. </td></tr> +<tr><td><code>center_horizontal</code></td> +<td>Place object in the horizontal center of its container, not changing its size. </td></tr> +<tr><td><code>fill_horizontal</code></td> +<td>Grow the horizontal size of the object if needed so it completely fills its container. +</td></tr> +<tr><td><code>center</code></td> +<td>Place the object in the center of its container in both the vertical and horizontal axis, not +changing its size. </td></tr> +<tr><td><code>fill</code></td> +<td>Grow the horizontal and vertical size of the object if needed so it completely fills its +container. This is the default.</td></tr> +<tr><td><code>clip_vertical</code></td> +<td>Additional option that can be set to have the top and/or bottom edges of the child clipped to +its container's bounds. The clip is based on the vertical gravity: a top gravity clips the +bottom edge, a bottom gravity clips the top edge, and neither clips both edges. +</td></tr> +<tr><td><code>clip_horizontal</code></td> +<td>Additional option that can be set to have the left and/or right edges of the child clipped to +its container's bounds. The clip is based on the horizontal gravity: a left gravity clips +the right edge, a right gravity clips the left edge, and neither clips both edges. +</td></tr> +</table> + </dd> + <dt><code>android:tileMode</code></dt> + <dd><em>Keyword</em>. Defines the tile mode. When the tile mode is enabled, the bitmap is +repeated. Gravity is ignored when the tile mode is enabled. + <p>Must be one of the following constant values:</p> +<table> +<tr><th>Value</th><th>Description</th></tr> +<tr><td><code>disabled</code></td> +<td>Do not tile the bitmap. This is the default value.</td></tr> +<tr><td><code>clamp</code></td> +<td>Replicates the edge color if the shader draws outside of its original bounds</td></tr> +<tr><td><code>repeat</code></td> +<td>Repeats the shader's image horizontally and vertically.</td></tr> +<tr><td><code>mirror</code></td> +<td>Repeats the shader's image horizontally and vertically, alternating mirror images so that +adjacent images always seam.</td></tr> +</table> + + </dd> + </dl> + </dd> + +</dl> +</dd> <!-- end elements and attributes --> + +<dt>example:</dt> +<dd> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<bitmap xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/icon" + android:tileMode="repeat" /> +</pre> + +</dd> + +<dt>see also:</dt> +<dd> +<ul> + <li>{@link android.graphics.drawable.BitmapDrawable}</li> + <li><a href="{@docRoot}guide/topics/resources/providing-resources.html#AliasResources">Creating +alias resources</a> +</ul> +</dd> + +</dl> + + + + + + +<h2 id="NinePatch">Nine-Patch</h2> <p>A {@link android.graphics.NinePatch} is a PNG image in which you can define stretchable regions -that Android will scale when content within the View exceeds the normal image bounds. You will +that Android scales when content within the View exceeds the normal image bounds. You typically assign this type of image as the background of a View that has at least one dimension set to {@code "wrap_content"}, and when the View grows to accomodate the content, the Nine-Patch image -will also be scaled to match the size of the View. An example use of a Nine-Patch image is the +is also scaled to match the size of the View. An example use of a Nine-Patch image is the background used by Android's standard {@link android.widget.Button} widget, which must stretch to accommodate the text (or image) inside the button.</p> -<p>For a complete discussion about how to define a Nine-Patch file with stretchable regions, +<p>Same as with a normal <a href="#Bitmap">bitmap</a>, you can reference a Nine-Patch file directly +or from a resource defined by XML.</p> + +<p>For a complete discussion about how to create a Nine-Patch file with stretchable regions, see the <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D Graphics</a> document.</p> + +<h3 id="NinePatchFile">Nine-Patch File</h3> + <dl class="xml"> <dt>file location:</dt> <dd><code>res/drawable/<em>filename</em>.9.png</code><br/> -The filename will be used as the resource ID.</dd> +The filename is used as the resource ID.</dd> <dt>compiled resource datatype:</dt> <dd>Resource pointer to a {@link android.graphics.drawable.NinePatchDrawable}.</dd> <dt>resource reference:</dt> + <dd> In Java: <code>R.drawable.<em>filename</em></code><br/> In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> </dd> <dt>example:</dt> -<dd>With an image saved at <code>res/drawable/myninepatch.9.png</code>, this layout XML will -apply the Nine-Patch to a View: + +<dd>With an image saved at <code>res/drawable/myninepatch.9.png</code>, this layout XML +applies the Nine-Patch to a View: <pre> <Button android:layout_height="wrap_content" android:layout_width="wrap_content" - <strong>android:background="@drawable/myninepatch"</strong> /> + android:background="@drawable/myninepatch" /> </pre> </dd> <dt>see also:</dt> + <dd> <ul> <li><a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D Graphics</a></li> @@ -153,6 +347,238 @@ apply the Nine-Patch to a View: +<h3 id="NinePatchXml">XML Nine-Patch</h3> + +<p>An XML Nine-Patch is a resource defined in XML that points to a Nine-Patch file. The XML can +specify dithering for the image.</p> + +<dl class="xml"> + +<dt>file location:</dt> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> + +<dt>compiled resource datatype:</dt> +<dd>Resource pointer to a {@link android.graphics.drawable.NinePatchDrawable}.</dd> + +<dt>resource reference:</dt> + +<dd> +In Java: <code>R.drawable.<em>filename</em></code><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> +</dd> + + +<dt>syntax:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#bitmap-element">nine-patch</a> + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@[package:]drawable/<em>drawable_resource</em>" + android:dither=["true" | "false"] /> +</pre> +</dd> + + +<dt>elements:</dt> + +<dd> +<dl class="tag-list"> + + <dt id="layerlist-element"><code><bitmap></code></dt> + <dd>Defines the bitmap source and its properties. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. + <dt><code>android:src</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a Nine-Patch +file.</dd> + <dt><code>android:dither</code></dt> + <dd><em>Boolean</em>. Enables or disables dithering of the bitmap if the bitmap does not +have the same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with an RGB 565 +screen).</dd> + </dl> + </dd> +</dl> +</dd> + + +<dt>example:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<nine-patch xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/myninepatch" + android:dither="false" /> +</pre> +</dd> +</dl> + + + + + + +<h2 id="LayerList">Layer List</h2> + +<p>A {@link android.graphics.drawable.LayerDrawable} is a drawable object +that manages an array of other drawables. Each drawable in the list is drawn in the order of the +list—the last drawable in the list is drawn on top.</p> + +<p>Each drawable is represented by an {@code <item>} element inside a single {@code +<layer-list>} element.</p> + +<dl class="xml"> + +<dt>file location:</dt> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> + +<dt>compiled resource datatype:</dt> +<dd>Resource pointer to a {@link android.graphics.drawable.LayerDrawable}.</dd> + +<dt>resource reference:</dt> + +<dd> +In Java: <code>R.drawable.<em>filename</em></code><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> +</dd> + +<dt>syntax:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#layerlist-element">layer-list</a> + xmlns:android="http://schemas.android.com/apk/res/android" > + <<a href="#layerlist-item-element">item</a> + android:drawable="@[package:]drawable/<em>drawable_resource</em>" + android:id="@[+][<em>package</em>:]id/<i>resource_name</i>" + android:top="<em>dimension</em>" + android:right="<em>dimension</em>" + android:bottom="<em>dimension</em>" + android:left="<em>dimension</em>" /> +</selector> +</pre> +</dd> + +<dt>elements:</dt> + +<dd> +<dl class="tag-list"> + + <dt id="layerlist-element"><code><layer-list></code></dt> + <dd><strong>Required.</strong> This must be the root element. Contains one or more {@code +<item>} elements. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. + </dl> + </dd> + <dt id="layerlist-item-element"><code><item></code></dt> + <dd>Defines a drawable to place in the layer drawable, in a position defined by its attributes. +Must be a child of a <code><selector></code> element. Accepts child {@code <bitmap>} +elements. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>android:drawable</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable +resource.</dd> + <dt><code>android:id</code></dt> + <dd><em>Resource ID</em>. A unique resource ID for this drawable. To create a new resource +ID for this item, use the form: +<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new +ID. You can use this identifier to +retrieve and modify the drawable with {@link android.view.View#findViewById(int) +View.findViewById()} or {@link android.app.Activity#findViewById(int) Activity.findViewById()}.</dd> + <dt><code>android:top</code></dt> + <dd><em>Integer</em>. The top offset in pixels.</dd> + <dt><code>android:right</code></dt> + <dd><em>Integer</em>. The right offset in pixels.</dd> + <dt><code>android:bottom</code></dt> + <dd><em>Integer</em>. The bottom offset in pixels.</dd> + <dt><code>android:left</code></dt> + <dd><em>Integer</em>. The left offset in pixels.</dd> + </dl> + <p>All drawable items are scaled to fit the size of the containing View, by default. Thus, +placing your images in a layer list at different positions might increase the size of the View and +some images scale as appropriate. To avoid +scaling items in the list, use a {@code <bitmap>} element inside the {@code +<item>} element to specify the drawable and define the gravity to something that does not +scale, such as {@code "center"}. For example, the following {@code <item>} defines an item +that scales to fit its container View:</p> +<pre> +<item android:drawable="@drawable/image" /> +</pre> + +<p>To avoid scaling, the following example uses a {@code <bitmap>} element with centered +gravity:</p> +<pre> +<item> + <bitmap android:src="<b>@drawable/image</b>" + android:gravity="center" /> +</item> +</pre> + </dd> + +</dl> +</dd> <!-- end elements and attributes --> + +<dt>example:</dt> + +<dd>XML file saved at <code>res/drawable/layers.xml</code>: +<pre> +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <bitmap android:src="@drawable/android_red" + android:gravity="center" /> + </item> + <item android:top="10dp" android:left="10dp"> + <bitmap android:src="@drawable/android_green" + android:gravity="center" /> + </item> + <item android:top="20dp" android:left="20dp"> + <bitmap android:src="@drawable/android_blue" + android:gravity="center" /> + </item> +</layer-list> +</pre> +<p>Notice that this example uses a nested {@code <bitmap>} element to define the drawable +resource for each item with a "center" gravity. This ensures that none of the images are scaled to +fit the size of the container, due to resizing caused by the offset images.</p> + +<p>This layout XML applies the drawable to a View:</p> +<pre> +<ImageView + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:src="@drawable/layers" /> +</pre> + +<p>The result is a stack of increasingly offset images:</p> +<img src="{@docRoot}images/resources/layers.png" alt="" /> +</dd> <!-- end example --> + +<dt>see also:</dt> +<dd> +<ul> + <li>{@link android.graphics.drawable.LayerDrawable}</li> +</ul> +</dd> + +</dl> + + + + @@ -163,33 +589,36 @@ apply the Nine-Patch to a View: that uses a several different images to represent the same graphic, depending on the state of the object. For example, a {@link android.widget.Button} widget can exist in one of several different states (pressed, focused, -or niether) and, using a state list drawable, you can provide a different button image for each +or niether) and, using a state list drawable, you can provide a different background image for each state.</p> <p>You can describe the state list in an XML file. Each graphic is represented by an {@code <item>} element inside a single {@code <selector>} element. Each {@code <item>} uses various attributes to describe the state in which it should be used as the graphic for the drawable.</p> + <p>During each state change, the state list is traversed top to bottom and the first item that -matches the current state will be used—the selection is <em>not</em> based on the "best +matches the current state is used—the selection is <em>not</em> based on the "best match," but simply the first item that meets the minimum criteria of the state.</p> <dl class="xml"> <dt>file location:</dt> <dd><code>res/drawable/<em>filename</em>.xml</code><br/> -The filename will be used as the resource ID.</dd> +The filename is used as the resource ID.</dd> <dt>compiled resource datatype:</dt> <dd>Resource pointer to a {@link android.graphics.drawable.StateListDrawable}.</dd> <dt>resource reference:</dt> + <dd> In Java: <code>R.drawable.<em>filename</em></code><br/> In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> </dd> <dt>syntax:</dt> + <dd> <pre class="stx"> <?xml version="1.0" encoding="utf-8"?> @@ -212,6 +641,7 @@ In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> </dd> <dt>elements:</dt> + <dd> <dl class="tag-list"> @@ -224,8 +654,8 @@ In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be <code>"http://schemas.android.com/apk/res/android"</code>. <dt><code>android:constantSize</code></dt> - <dd><em>Boolean</em>. "true" if the drawable's reported internal size will remain constant as the state -changes (the size will be the maximum of all of the states); "false" if the size will vary based on + <dd><em>Boolean</em>. "true" if the drawable's reported internal size remains constant as the state +changes (the size is the maximum of all of the states); "false" if the size varies based on the current state. Default is false.</dd> <dt><code>android:dither</code></dt> <dd><em>Boolean</em>. "true" to enable dithering of the bitmap if the bitmap does not have the same pixel @@ -270,9 +700,9 @@ receiving touch/click events); "false" if it should be used when the object is d application is in the foreground), "false" if this item should be used when the application window does not have focus (for example, if the notification shade is pulled down or a dialog appears).</dd> </dl> - <p class="note"><strong>Note:</strong>Remember that the first item in the state list that -matches the current state of the object will be applied. So if the first item in the list contains -none of the state attributes above, then it will be applied every time, which is why your + <p class="note"><strong>Note:</strong> Remember that Android applies the first item in the state list that +matches the current state of the object. So, if the first item in the list contains +none of the state attributes above, then it is applied every time, which is why your default value should always be last (as demonstrated in the following example).</p> </dd> @@ -280,6 +710,7 @@ default value should always be last (as demonstrated in the following example).< </dd> <!-- end elements and attributes --> <dt>example:</dt> + <dd>XML file saved at <code>res/drawable/button.xml</code>: <pre> <?xml version="1.0" encoding="utf-8"?> @@ -292,12 +723,12 @@ default value should always be last (as demonstrated in the following example).< </selector> </pre> -<p>This layout XML will apply the drawable to a View:</p> +<p>This layout XML applies the drawable to a View:</p> <pre> <ImageView android:layout_height="wrap_content" android:layout_width="wrap_content" - <strong>android:src="@drawable/button"</strong> /> + android:src="@drawable/button" /> </pre> </dd> <!-- end example --> @@ -317,106 +748,513 @@ default value should always be last (as demonstrated in the following example).< +<h2 id="LevelList">Level List</h2> +<p>A Drawable that manages a number of alternate Drawables, each assigned a maximum numerical +value. Setting the level value of the drawable with {@link +android.graphics.drawable.Drawable#setLevel(int) setLevel()} loads the drawable resource in the +level list that has a {@code android:maxLevel} value greater than or equal to the value +passed to the method.</p> +<dl class="xml"> +<dt>file location:</dt> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> +<dt>compiled resource datatype:</dt> +<dd>Resource pointer to a {@link android.graphics.drawable.LevelListDrawable}.</dd> + +<dt>resource reference:</dt> + +<dd> +In Java: <code>R.drawable.<em>filename</em></code><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> +</dd> + +<dt>syntax:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#levellist-element">level-list</a> + xmlns:android="http://schemas.android.com/apk/res/android" > + <<a href="#levellist-item-element">item</a> + android:drawable="@drawable/<i>drawable_resource</i>" + android:maxLevel="<i>integer</i>" + android:minLevel="<i>integer</i>" /> +</level-list> +</pre> +</dd> + +<dt>elements:</dt> + +<dd> +<dl class="tag-list"> + + <dt id="levellist-element"><code><level-list></code></dt> + <dd>This must be the root element. Contains one or more {@code <item>} elements. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. + </dl> + </dd> + + <dt id="levellist-item-element"><code><item></code></dt> + <dd>Defines a drawable to use at a certain level. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>android:drawable</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable +resource to be inset.</dd> + <dt><code>android:maxLevel</code></dt> + <dd><em>Integer</em>. The maximum level allowed for this item.</dd> + <dt><code>android:minLevel</code></dt> + <dd><em>Integer</em>. The minimum level allowed for this item.</dd> + </dl> + </dd> +</dl> + +</dd> + +<dt>example:</dt> + +<dd> + +<pre> +<?xml version="1.0" encoding="utf-8"?> +<level-list xmlns:android="http://schemas.android.com/apk/res/android" > + <item + android:drawable="@drawable/status_off" + android:maxLevel="0" /> + <item + android:drawable="@drawable/status_on" + android:maxLevel="1" /> +</level-list> +</pre> +<p>Once this is applied to a {@link android.view.View}, the level can be changed with {@link +android.graphics.drawable.Drawable#setLevel(int) setLevel()} or {@link +android.widget.ImageView#setImageLevel(int) setImageLevel()}.</p> + +</dd> + +<dt>see also:</dt> + +<dd> +<ul> + <li>{@link android.graphics.drawable.LevelListDrawable}</li> +</ul> +</dd> + +</dl> -<h2 id="Color">Color</h2> -<p>This is a color defined in XML that's used as a drawable to fill a rectangular space, -with optionally rounded corners. This kind of drawable behaves like a color fill.</p> -<p class="note"><strong>Note:</strong> A color drawable is a simple resource that is referenced -using the value provided in the {@code name} attribute (not the name of the XML file). As -such, you can combine a color drawable resources with other simple resources in the one XML file, -under one {@code <resources>} element.</p> +<h2 id="Transition">Transition Drawable</h2> + +<p>A {@link android.graphics.drawable.TransitionDrawable} is a drawable object +that can cross-fade between the two drawable resources.</p> + +<p>Each drawable is represented by an {@code <item>} element inside a single {@code +<transition>} element. No more than two items are supported. To transition forward, call +{@link android.graphics.drawable.TransitionDrawable#startTransition(int) startTransition()}. To +transition backward, call {@link android.graphics.drawable.TransitionDrawable#reverseTransition(int) +reverseTransition()}.</p> + <dl class="xml"> <dt>file location:</dt> -<dd><code>res/drawable/<em>filename</em>.png</code><br/> -The filename is arbitrary. The element's {@code name} will be used as the resource ID.</dd> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> <dt>compiled resource datatype:</dt> -<dd>Resource pointer to a {@link android.graphics.drawable.PaintDrawable}.</dd> +<dd>Resource pointer to a {@link android.graphics.drawable.TransitionDrawable}.</dd> <dt>resource reference:</dt> + <dd> -In Java: <code>R.drawable.<em>color_name</em></code><br/> -In XML: <code>@[<em>package</em>:]drawable/<em>color_name</em></code> +In Java: <code>R.drawable.<em>filename</em></code><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> </dd> <dt>syntax:</dt> + <dd> <pre class="stx"> -<?xml version="1.0" encoding="utf-8"?> -<<a href="#color-resources-element">resources</a>> - <<a href="#drawable-element">drawable</a> - name="<em>color_name</em>" - ><em>color</em></drawable> -</resources> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#transition-element">layer-list</a> +xmlns:android="http://schemas.android.com/apk/res/android" > + <<a href="#transition-item-element">item</a> + android:drawable="@[package:]drawable/<em>drawable_resource</em>" + android:id="@[+][<em>package</em>:]id/<i>resource_name</i>" + android:top="<em>dimension</em>" + android:right="<em>dimension</em>" + android:bottom="<em>dimension</em>" + android:left="<em>dimension</em>" /> +</selector> </pre> </dd> <dt>elements:</dt> + <dd> <dl class="tag-list"> - <dt id="color-resources-element"><code><resources></code></dt> - <dd><strong>Required.</strong> This must be the root node. - <p>No attributes.</p> + <dt id="transition-element"><code><transition></code></dt> + <dd><strong>Required.</strong> This must be the root element. Contains one or more {@code +<item>} elements. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. + </dl> </dd> - <dt id="drawable-element"><code><drawable></code></dt> - <dd>A color to use as a drawable rectangle. The value can be - any valid hexadecimal color value or a <a href="more-resources.html#Color">color - resource</a>. A color value always begins with a pound (#) character, followed - by the Alpha-Red-Green-Blue information in one of the following formats: - #<em>RGB</em>, #<em>RRGGBB</em>, #<em>ARGB</em>, or #<em>AARRGGBB</em>. + <dt id="transition-item-element"><code><item></code></dt> + <dd>Defines a drawable to place in the layer drawable, in a position defined by its attributes. +Must be a child of a <code><selector></code> element. Accepts child {@code <bitmap>} +elements. <p class="caps">attributes:</p> <dl class="atn-list"> - <dt><code>name</code></dt> - <dd><em>String</em>. <strong>Required</strong>. - A name for the color. This name will be used as the resource ID.</dd> + <dt><code>android:drawable</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable +resource.</dd> + <dt><code>android:id</code></dt> + <dd><em>Resource ID</em>. A unique resource ID for this drawable. To create a new resource +ID for this item, use the form: +<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new +ID. You can use this identifier to +retrieve and modify the drawable with {@link android.view.View#findViewById(int) +View.findViewById()} or {@link android.app.Activity#findViewById(int) Activity.findViewById()}.</dd> + <dt><code>android:top</code></dt> + <dd><em>Integer</em>. The top offset in pixels.</dd> + <dt><code>android:right</code></dt> + <dd><em>Integer</em>. The right offset in pixels.</dd> + <dt><code>android:bottom</code></dt> + <dd><em>Integer</em>. The bottom offset in pixels.</dd> + <dt><code>android:left</code></dt> + <dd><em>Integer</em>. The left offset in pixels.</dd> </dl> - </dd> </dl> </dd> <!-- end elements and attributes --> <dt>example:</dt> -<dd>XML file saved at <code>res/drawable/colors.xml</code>: + +<dd>XML file saved at <code>res/drawable/transition.xml</code>: <pre> -<?xml version="1.0" encoding="utf-8"?> -<resources> - <drawable name="solid_red">#f00</drawable> - <drawable name="solid_blue">#0000ff</drawable> -</resources> +<?xml version="1.0" encoding="utf-8"?> +<transition xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/on" /> + <item android:drawable="@drawable/off" /> +</layer-list> </pre> - <p>This layout XML will apply a color drawable to a View:</p> + +<p>This layout XML applies the drawable to a View:</p> <pre> -<TextView - android:layout_width="fill_parent" +<ImageButton + android:id="@+id/button" android:layout_height="wrap_content" - <strong>android:background="@drawable/solid_blue"</strong> /> + android:layout_width="wrap_content" + android:src="@drawable/transition" /> </pre> - <p>This application code will get a color drawable and apply it to a View:</p> + +<p>And the following code performs a 500ms transition from the first item to the second:</p> <pre> -Resources res = {@link android.content.Context#getResources()}; -Drawable redDrawable = res.{@link android.content.res.Resources#getDrawable(int) getDrawable}(R.drawable.solid_red); +ImageButton button = (ImageButton) findViewById(R.id.button); +TransitionDrawable drawable = (TransitionDrawable) button.getDrawable(); +drawable.startTransition(500); +</pre> + +</dd> <!-- end example --> -TextView tv = (TextView) findViewByID(R.id.text); -tv.setBackground(redDrawable); +<dt>see also:</dt> + +<dd> +<ul> + <li>{@link android.graphics.drawable.TransitionDrawable}</li> +</ul> +</dd> + +</dl> + + + + + + + + +<h2 id="Inset">Inset Drawable</h2> + +<p>A drawable defined in XML that insets another drawable by a specified distance. This is used when +a View needs a background that is smaller than the View's actual bounds.</p> + +<dl class="xml"> + +<dt>file location:</dt> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> + +<dt>compiled resource datatype:</dt> +<dd>Resource pointer to a {@link android.graphics.drawable.InsetDrawable}.</dd> + +<dt>resource reference:</dt> + +<dd> +In Java: <code>R.drawable.<em>filename</em></code><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> +</dd> + +<dt>syntax:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#inset-element">inset</a> + xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/<i>drawable_resource</i>" + android:insetTop="<i>dimension</i>" + android:insetRight="<i>dimension</i>" + android:insetBottom="<i>dimension</i>" + android:insetLeft="<i>dimension</i>" /> </pre> +</dd> + +<dt>elements:</dt> + +<dd> +<dl class="tag-list"> + + <dt id="inset-element"><code><inset></code></dt> + <dd>Defines the inset drawable. This must be the root element. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. + <dt><code>android:drawable</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable +resource to be inset.</dd> + <dt><code>android:insetTop</code></dt> + <dd><em>Dimension</em>. The top inset, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a></dd> + <dt><code>android:insetRight</code></dt> + <dd><em>Dimension</em>. The right inset, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a></dd> + <dt><code>android:insetBottom</code></dt> + <dd><em>Dimension</em>. The bottom inset, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a></dd> + <dt><code>android:insetLeft</code></dt> + <dd><em>Dimension</em>. The left inset, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a></dd> + </dl> + </dd> +</dl> + +</dd> + +<dt>example:</dt> + +<dd> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/background" + android:insetTop="10dp" + android:insetLeft="10dp" /> +</pre> +</dd> + +<dt>see also:</dt> + +<dd> +<ul> + <li>{@link android.graphics.drawable.InsetDrawable}</li> +</ul> +</dd> + +</dl> + + + + + + + + +<h2 id="Clip">Clip Drawable</h2> + +<p>A drawable defined in XML that clips another drawable based on this Drawable's current level. You +can control how much the child drawable gets clipped in width and height based on the level, as well +as a gravity to control where it is placed in its overall container. Most often used to implement +things like progress bars.</p> + +<dl class="xml"> + +<dt>file location:</dt> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> + +<dt>compiled resource datatype:</dt> +<dd>Resource pointer to a {@link android.graphics.drawable.ClipDrawable}.</dd> + +<dt>resource reference:</dt> + +<dd> +In Java: <code>R.drawable.<em>filename</em></code><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> +</dd> + +<dt>syntax:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#clip-element">clip</a> + xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/<i>drawable_resource</i>" + android:clipOrientation=["horizontal" | "vertical"] + android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" | + "fill_vertical" | "center_horizontal" | "fill_horizontal" | + "center" | "fill" | "clip_vertical" | "clip_horizontal"] /> +</pre> +</dd> + +<dt>elements:</dt> + +<dd> +<dl class="tag-list"> + + <dt id="clip-element"><code><clip></code></dt> + <dd>Defines the clip drawable. This must be the root element. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. + <dt><code>android:drawable</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable +resource to be clipped.</dd> + <dt><code>android:clipOrientation</code></dt> + <dd><em>Keyword</em>. The orientation for the clip. + <p>Must be one of the following constant values:</p> +<table> +<tr><th>Value</th><th>Description</th></tr> +<tr><td><code>horizontal</code></td> +<td>Clip the drawable horizontally.</td></tr> +<tr><td><code>vertical</code></td> +<td>Clip the drawable vertically.</td></tr> +</table> + </dd> + <dt><code>android:gravity</code></dt> + <dd><em>Keyword</em>. Specifies where to clip within the drawable. + <p>Must be one or more (separated by '|') of the following constant values:</p> +<table> +<tr><th>Value</th><th>Description</th></tr> +<tr><td><code>top</code></td> +<td>Put the object at the top of its container, not changing its size. When {@code +clipOrientation} is {@code "vertical"}, clipping occurs at the bottom of the drawable.</td></tr> +<tr><td><code>bottom</code></td> +<td>Put the object at the bottom of its container, not changing its size. When {@code +clipOrientation} is {@code "vertical"}, clipping occurs at the top of the drawable.</td></tr> +<tr><td><code>left</code></td> +<td>Put the object at the left edge of its container, not changing its size. This is the +default. When {@code clipOrientation} is {@code "horizontal"}, clipping occurs at the right side of +the drawable. This is the default.</td></tr> +<tr><td><code>right</code></td> +<td>Put the object at the right edge of its container, not changing its size. When {@code +clipOrientation} is {@code "horizontal"}, clipping occurs at the left side of +the drawable.</td></tr> +<tr><td><code>center_vertical</code></td> +<td>Place object in the vertical center of its container, not changing its size. Clipping behaves +the same as when gravity is {@code "center"}.</td></tr> +<tr><td><code>fill_vertical</code></td> +<td>Grow the vertical size of the object if needed so it completely fills its container. When {@code +clipOrientation} is {@code "vertical"}, no clipping occurs because the drawable fills the +vertical space (unless the drawable level is 0, in which case it's not visible).</td></tr> +<tr><td><code>center_horizontal</code></td> +<td>Place object in the horizontal center of its container, not changing its size. +Clipping behaves the same as when gravity is {@code "center"}.</td></tr> +<tr><td><code>fill_horizontal</code></td> +<td>Grow the horizontal size of the object if needed so it completely fills its container. When +{@code clipOrientation} is {@code "horizontal"}, no clipping occurs because the drawable fills the +horizontal space (unless the drawable level is 0, in which case it's not visible). +</td></tr> +<tr><td><code>center</code></td> +<td>Place the object in the center of its container in both the vertical and horizontal axis, not +changing its size. When {@code +clipOrientation} is {@code "horizontal"}, clipping occurs on the left and right. When {@code +clipOrientation} is {@code "vertical"}, clipping occurs on the top and bottom.</td></tr> +<tr><td><code>fill</code></td> +<td>Grow the horizontal and vertical size of the object if needed so it completely fills its +container. No clipping occurs because the drawable fills the +horizontal and vertical space (unless the drawable level is 0, in which case it's not +visible).</td></tr> +<tr><td><code>clip_vertical</code></td> +<td>Additional option that can be set to have the top and/or bottom edges of the child clipped to +its container's bounds. The clip is based on the vertical gravity: a top gravity clips the +bottom edge, a bottom gravity clips the top edge, and neither clips both edges. +</td></tr> +<tr><td><code>clip_horizontal</code></td> +<td>Additional option that can be set to have the left and/or right edges of the child clipped to +its container's bounds. The clip is based on the horizontal gravity: a left gravity clips +the right edge, a right gravity clips the left edge, and neither clips both edges. +</td></tr> +</table></dd> + </dl> + </dd> +</dl> + +</dd> <!-- end elements and attributes --> + +<dt>example:</dt> + +<dd>XML file saved at <code>res/drawable/clip.xml</code>: +<pre> +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/android" + android:clipOrientation="horizontal" + android:gravity="left" /> +</shape> +</pre> + <p>The following layout XML applies the clip drawable to a View:</p> +<pre> +<ImageView + android:id="@+id/image" + android:background="@drawable/clip" + android:layout_height="wrap_content" + android:layout_width="wrap_content" /> +</pre> + + <p>The following code gets the drawable and increases the amount of clipping in order to +progressively reveal the image:</p> +<pre> +ImageView imageview = (ImageView) findViewById(R.id.image); +ClipDrawable drawable = (ClipDrawable) imageview.getDrawable(); +drawable.setLevel(drawable.getLevel() + 1000); +</pre> + +<p>Increasing the level reduces the amount of clipping and slowly reveals the image. Here it is +at a level of 7000:</p> +<img src="{@docRoot}images/resources/clip.png" alt="" /> + +<p class="note"><strong>Note:</strong> The default level is 0, which is fully clipped so the image +is not visible. When the level is 10,000, the image is not clipped and completely visible.</p> </dd> <!-- end example --> <dt>see also:</dt> + <dd> <ul> - <li>{@link android.graphics.drawable.PaintDrawable}</li> + <li>{@link android.graphics.drawable.ClipDrawable}</li> </ul> </dd> @@ -430,10 +1268,139 @@ tv.setBackground(redDrawable); +<h2 id="Scale">Scale Drawable</h2> + +<p>A drawable defined in XML that changes the size of another drawable based on its current +level.</p> + +<dl class="xml"> + +<dt>file location:</dt> +<dd><code>res/drawable/<em>filename</em>.xml</code><br/> +The filename is used as the resource ID.</dd> + +<dt>compiled resource datatype:</dt> +<dd>Resource pointer to a {@link android.graphics.drawable.ScaleDrawable}.</dd> + +<dt>resource reference:</dt> + +<dd> +In Java: <code>R.drawable.<em>filename</em></code><br/> +In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> +</dd> + +<dt>syntax:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#scale-element">scale</a> + xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/<i>drawable_resource</i>" + android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" | + "fill_vertical" | "center_horizontal" | "fill_horizontal" | + "center" | "fill" | "clip_vertical" | "clip_horizontal"] + android:scaleHeight="<i>percentage</i>" + android:scaleWidth="<i>percentage</i>" /> +</pre> +</dd> + +<dt>elements:</dt> +<dd> +<dl class="tag-list"> + <dt id="scale-element"><code><scale></code></dt> + <dd>Defines the scale drawable. This must be the root element. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. + <dt><code>android:drawable</code></dt> + <dd><em>Drawable resource</em>. <strong>Required</strong>. Reference to a drawable +resource.</dd> + <dt><code>android:scaleGravity</code></dt> + <dd><em>Keyword</em>. Specifies the gravity position after scaling. + <p>Must be one or more (separated by '|') of the following constant values:</p> +<table> +<tr><th>Value</th><th>Description</th></tr> +<tr><td><code>top</code></td> +<td>Put the object at the top of its container, not changing its size.</td></tr> +<tr><td><code>bottom</code></td> +<td>Put the object at the bottom of its container, not changing its size. </td></tr> +<tr><td><code>left</code></td> +<td>Put the object at the left edge of its container, not changing its size. This is the +default.</td></tr> +<tr><td><code>right</code></td> +<td>Put the object at the right edge of its container, not changing its size. </td></tr> +<tr><td><code>center_vertical</code></td> +<td>Place object in the vertical center of its container, not changing its size. </td></tr> +<tr><td><code>fill_vertical</code></td> +<td>Grow the vertical size of the object if needed so it completely fills its container. </td></tr> +<tr><td><code>center_horizontal</code></td> +<td>Place object in the horizontal center of its container, not changing its size. </td></tr> +<tr><td><code>fill_horizontal</code></td> +<td>Grow the horizontal size of the object if needed so it completely fills its container. +</td></tr> +<tr><td><code>center</code></td> +<td>Place the object in the center of its container in both the vertical and horizontal axis, not +changing its size. </td></tr> +<tr><td><code>fill</code></td> +<td>Grow the horizontal and vertical size of the object if needed so it completely fills its +container. </td></tr> +<tr><td><code>clip_vertical</code></td> +<td>Additional option that can be set to have the top and/or bottom edges of the child clipped to +its container's bounds. The clip is based on the vertical gravity: a top gravity clips the +bottom edge, a bottom gravity clips the top edge, and neither clips both edges. +</td></tr> +<tr><td><code>clip_horizontal</code></td> +<td>Additional option that can be set to have the left and/or right edges of the child clipped to +its container's bounds. The clip is based on the horizontal gravity: a left gravity clips +the right edge, a right gravity clips the left edge, and neither clips both edges. +</td></tr> +</table></dd> + <dt><code>android:scaleHeight</code></dt> + <dd><em>Percentage</em>. The scale height, expressed as a percentage of the drawable's +bound. The value's format is XX%. For instance: 100%, 12.5%, etc.</dd> + <dt><code>android:scaleWidth</code></dt> + <dd><em>Percentage</em>. The scale width, expressed as a percentage of the drawable's +bound. The value's format is XX%. For instance: 100%, 12.5%, etc.</dd> + </dl> + </dd> +</dl> -<h2 id="Shape">Shape</h2> +</dd> + +<dt>example:</dt> + +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<scale xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/logo" + android:scaleGravity="center_vertical|center_horizontal" + android:scaleHeight="80%" + android:scaleWidth="80%" /> +</pre> +</dd> + +<dt>see also:</dt> +<dd> +<ul> + <li>{@link android.graphics.drawable.ScaleDrawable}</li> +</ul> +</dd> + +</dl> + + + + + + + +<h2 id="Shape">Shape Drawable</h2> <p>This is a generic shape defined in XML.</p> @@ -441,23 +1408,32 @@ tv.setBackground(redDrawable); <dt>file location:</dt> <dd><code>res/drawable/<em>filename</em>.xml</code><br/> -The filename will be used as the resource ID.</dd> +The filename is used as the resource ID.</dd> <dt>compiled resource datatype:</dt> <dd>Resource pointer to a {@link android.graphics.drawable.ShapeDrawable}.</dd> <dt>resource reference:</dt> + <dd> In Java: <code>R.drawable.<em>filename</em></code><br/> In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> </dd> <dt>syntax:</dt> + <dd> <pre class="stx"> <?xml version="1.0" encoding="utf-8"?> -<<a href="#shape-element">shape</a> xmlns:android="http://schemas.android.com/apk/res/android" +<<a href="#shape-element">shape</a> + xmlns:android="http://schemas.android.com/apk/res/android" android:shape=["rectangle" | "oval" | "line" | "ring"] > + <<a href="#corners-element">corners</a> + android:radius="<em>integer</em>" + android:topLeftRadius="<em>integer</em>" + android:topRightRadius="<em>integer</em>" + android:bottomLeftRadius="<em>integer</em>" + android:bottomRightRadius="<em>integer</em>" /> <<a href="#gradient-element">gradient</a> android:angle="<em>integer</em>" android:centerX="<em>integer</em>" @@ -467,37 +1443,40 @@ In XML: <code>@[<em>package</em>:]drawable/<em>filename</em></code> android:gradientRadius="<em>integer</em>" android:startColor="<em>color</em>" android:type=["linear" | "radial" | "sweep"] - android:usesLevel=["true" | "false"] /> + android:usesLevel=["true" | "false"] /> + <<a href="#padding-element">padding</a> + android:left="<em>integer</em>" + android:top="<em>integer</em>" + android:right="<em>integer</em>" + android:bottom="<em>integer</em>" /> + <<a href="#size-element">size</a> + android:width="<em>integer</em>" + android:color="<em>color</em>" + android:dashWidth="<em>integer</em>" + android:dashGap="<em>integer</em>" /> <<a href="#solid-element">solid</a> - android:color="<em>color</em>" /> + android:color="<em>color</em>" /> <<a href="#stroke-element">stroke</a> android:width="<em>integer</em>" android:color="<em>color</em>" android:dashWidth="<em>integer</em>" - android:dashGap="<em>integer</em>" /> - <<a href="#padding-element">padding</a> - android:left="<em>integer</em>" - android:top="<em>integer</em>" - android:right="<em>integer</em>" - android:bottom="<em>integer</em>" /> - <<a href="#corners-element">corners</a> - android:radius="<em>integer</em>" - android:topLeftRadius="<em>integer</em>" - android:topRightRadius="<em>integer</em>" - android:bottomLeftRadius="<em>integer</em>" - android:bottomRightRadius="<em>integer</em>" /> + android:dashGap="<em>integer</em>" /> </shape> </pre> </dd> <dt>elements:</dt> + <dd> <dl class="tag-list"> <dt id="shape-element"><code><shape></code></dt> - <dd><strong>Required.</strong> This must be the root element. + <dd>The shape drawable. This must be the root element. <p class="caps">attributes:</p> <dl class="atn-list"> + <dt><code>xmlns:android</code></dt> + <dd><em>String</em>. <strong>Required.</strong> Defines the XML namespace, which must be + <code>"http://schemas.android.com/apk/res/android"</code>. <dt><code>android:shape</code></dt> <dd><em>Keyword</em>. Defines the type of shape. Valid values are: <table> @@ -525,7 +1504,7 @@ href="more-resources.html#Dimension">dimension resource</a>.</dd> <dd><em>Float</em>. The radius for the inner part of the ring, expressed as a ratio of the ring's width. For instance, if {@code android:innerRadiusRatio="5"}, then the inner radius equals the ring's width divided by 5. This -value will be overridden by {@code android:innerRadius}. Default value is 9.</dd> +value is overridden by {@code android:innerRadius}. Default value is 9.</dd> <dt><code>android:thickness</code></dt> <dd><em>Dimension</em>. The thickness of the ring, as a dimension value or <a @@ -533,13 +1512,40 @@ href="more-resources.html#Dimension">dimension resource</a>.</dd> <dt><code>android:thicknessRatio</code></dt> <dd><em>Float</em>. The thickness of the ring, expressed as a ratio of the ring's width. For instance, if {@code android:thicknessRatio="2"}, then -the thickness equals the ring's width divided by 2. This value will be overridden by {@code +the thickness equals the ring's width divided by 2. This value is overridden by {@code android:innerRadius}. Default value is 3.</dd> <dt><code>android:useLevel</code></dt> <dd><em>Boolean</em>. "true" if this is used as a {@link android.graphics.drawable.LevelListDrawable}. This should normally be "false" or your shape may not appear.</dd> </dl> + <dt id="corners-element"><code><corners></code></dt> + <dd>Creates rounded corners for the shape. Applies only when the shape is a rectangle. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>android:radius</code></dt> + <dd><em>Dimension</em>. The radius for all corners, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>. This is overridden for each +corner by the following attributes.</dd> + <dt><code>android:topLeftRadius</code></dt> + <dd><em>Dimension</em>. The radius for the top-left corner, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + <dt><code>android:topRightRadius</code></dt> + <dd><em>Dimension</em>. The radius for the top-right corner, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + <dt><code>android:bottomLeftRadius</code></dt> + <dd><em>Dimension</em>. The radius for the bottom-left corner, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + <dt><code>android:bottomRightRadius</code></dt> + <dd><em>Dimension</em>. The radius for the bottom-right corner, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + </dl> + <p class="note"><strong>Note:</strong> Every corner must (initially) be provided a corner +radius greater than 1, or else no corners are rounded. If you want specific corners +to <em>not</em> be rounded, a work-around is to use {@code android:radius} to set a default corner +radius greater than 1, but then override each and every corner with the values you really +want, providing zero ("0dp") where you don't want rounded corners.</p> + </dd> <dt id="gradient-element"><code><gradient></code></dt> <dd>Specifies a gradient color for the shape. <p class="caps">attributes:</p> @@ -582,6 +1588,42 @@ value or <a href="more-resources.html#Color">color resource</a>.</dd> android.graphics.drawable.LevelListDrawable}.</dd> </dl> </dd> + <dt id="padding-element"><code><padding></code></dt> + <dd>Padding to apply to the containing View element (this pads the position of the View +content, not the shape). + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>android:left</code></dt> + <dd><em>Dimension</em>. Left padding, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + <dt><code>android:top</code></dt> + <dd><em>Dimension</em>. Top padding, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + <dt><code>android:right</code></dt> + <dd><em>Dimension</em>. Right padding, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + <dt><code>android:bottom</code></dt> + <dd><em>Dimension</em>. Bottom padding, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + </dl> + </dd> + <dt id="solid-element"><code><size></code></dt> + <dd>The size of the shape. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>android:height</code></dt> + <dd><em>Dimension</em>. The height of the shape, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + <dt><code>android:width</code></dt> + <dd><em>Dimension</em>. The width of the shape, as a dimension value or <a +href="more-resources.html#Dimension">dimension resource</a>.</dd> + </dl> + <p class="note"><strong>Note:</strong> The shape scales to the size of the container +View proportionate to the dimensions defined here, by default. When you use the shape in an {@link +android.widget.ImageView}, you can restrict scaling by setting the <a +href="{@docRoot}reference/android/widget/ImageView.html#attr_android:scaleType">{@code +android:scaleType}</a> to {@code "center"}.</p> + </dd> <dt id="solid-element"><code><solid></code></dt> <dd>A solid color to fill the shape. <p class="caps">attributes:</p> @@ -611,57 +1653,12 @@ href="more-resources.html#Dimension">dimension resource</a>. Only valid if {@cod android:dashGap} is set.</dd> </dl> </dd> - <dt id="padding-element"><code><padding></code></dt> - <dd>Padding to apply to the containing View element (this pads the position of the View -content, not the shape). - <p class="caps">attributes:</p> - <dl class="atn-list"> - <dt><code>android:left</code></dt> - <dd><em>Dimension</em>. Left padding, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - <dt><code>android:top</code></dt> - <dd><em>Dimension</em>. Top padding, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - <dt><code>android:right</code></dt> - <dd><em>Dimension</em>. Right padding, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - <dt><code>android:bottom</code></dt> - <dd><em>Dimension</em>. Bottom padding, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - </dl> - </dd> - <dt id="corners-element"><code><corners></code></dt> - <dd>Creates rounded corners for the shape. Applies only when the shape is a rectangle. - <p class="caps">attributes:</p> - <dl class="atn-list"> - <dt><code>android:radius</code></dt> - <dd><em>Dimension</em>. The radius for all corners, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>. This will be overridden for each -corner by the following attributes.</dd> - <dt><code>android:topLeftRadius</code></dt> - <dd><em>Dimension</em>. The radius for the top-left corner, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - <dt><code>android:topRightRadius</code></dt> - <dd><em>Dimension</em>. The radius for the top-right corner, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - <dt><code>android:bottomLeftRadius</code></dt> - <dd><em>Dimension</em>. The radius for the bottom-left corner, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - <dt><code>android:bottomRightRadius</code></dt> - <dd><em>Dimension</em>. The radius for the bottom-right corner, as a dimension value or <a -href="more-resources.html#Dimension">dimension resource</a>.</dd> - </dl> - <p class="note"><strong>Note:</strong> Every corner must (initially) be provided a corner -radius greater than zero, or else no corners will be rounded. If you want specific corners -to <em>not</em> be rounded, a work-around is to use {@code android:radius} to set a default corner -radius greater than zero, but then override each and every corner with the values you really -want, providing zero ("0dp") where you don't want rounded corners.</p> - </dd> </dl> </dd> <!-- end elements and attributes --> <dt>example:</dt> + <dd>XML file saved at <code>res/drawable/gradient_box.xml</code>: <pre> <?xml version="1.0" encoding="utf-8"?> @@ -678,14 +1675,16 @@ want, providing zero ("0dp") where you don't want rounded corners.</p> <corners android:radius="8dp" /> </shape> </pre> - <p>This layout XML will apply the shape drawable to a View:</p> + + <p>This layout XML applies the shape drawable to a View:</p> <pre> <TextView android:background="@drawable/gradient_box" android:layout_height="wrap_content" android:layout_width="wrap_content" /> </pre> - <p>This application code will get the shape drawable and apply it to a View:</p> + + <p>This application code gets the shape drawable and applies it to a View:</p> <pre> Resources res = {@link android.content.Context#getResources()}; Drawable shape = res. {@link android.content.res.Resources#getDrawable(int) getDrawable}(R.drawable.gradient_box); @@ -695,6 +1694,14 @@ tv.setBackground(shape); </pre> </dd> <!-- end example --> +<dt>see also:</dt> + +<dd> +<ul> + <li>{@link android.graphics.drawable.ShapeDrawable}</li> +</ul> +</dd> + </dl> diff --git a/docs/html/guide/topics/resources/layout-resource.jd b/docs/html/guide/topics/resources/layout-resource.jd index 0688a18..111851c 100644 --- a/docs/html/guide/topics/resources/layout-resource.jd +++ b/docs/html/guide/topics/resources/layout-resource.jd @@ -35,12 +35,12 @@ In XML: <code>@[<em>package</em>:]layout/<em>filename</em></code> <pre class="stx"> <?xml version="1.0" encoding="utf-8"?> <<a href="#viewgroup-element"><em>ViewGroup</em></a> xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/<em>name</em>" + android:id="@[+][<em>package</em>:]id/<em>resource_name</em>" android:layout_height=["<em>dimension</em>" | "fill_parent" | "wrap_content"] android:layout_width=["<em>dimension</em>" | "fill_parent" | "wrap_content"] [<em>ViewGroup-specific attributes</em>] > <<a href="#view-element"><em>View</em></a> - android:id="@+id/<em>name</em>" + android:id="@[+][<em>package</em>:]id/<em>resource_name</em>" android:layout_height=["<em>dimension</em>" | "fill_parent" | "wrap_content"] android:layout_width=["<em>dimension</em>" | "fill_parent" | "wrap_content"] [<em>View-specific attributes</em>] > @@ -49,10 +49,12 @@ In XML: <code>@[<em>package</em>:]layout/<em>filename</em></code> <<a href="#viewgroup-element"><em>ViewGroup</em></a> > <<a href="#view-element"><em>View</em></a> /> </<em>ViewGroup</em>> + <<a href="#include-element">include</a> layout="@layout/<i>layout_resource</i>"/> </<em>ViewGroup</em>> </pre> <p class="note"><strong>Note:</strong> The root element can be either a -{@link android.view.ViewGroup} or a {@link android.view.View}, but there must be only +{@link android.view.ViewGroup}, a {@link android.view.View}, or a <a +href="#merge-element">{@code <merge>}</a> element, but there must be only one root element and it must contain the {@code xmlns:android} attribute with the {@code android} namespace as shown.</p> </dd> @@ -74,10 +76,9 @@ namespace as shown.</p> <p class="caps">attributes:</p> <dl class="atn-list"> <dt><code>android:id</code></dt> - <dd><em>Resource name</em>. A unique resource name for the element, which you can -use to obtain a reference to the {@link android.view.ViewGroup} from your application. - The value takes the form: <code>"@+id/<em>name</em>"</code>. See more about the - <a href="#idvalue">value for {@code android:id}</a> below. + <dd><em>Resource ID</em>. A unique resource name for the element, which you can +use to obtain a reference to the {@link android.view.ViewGroup} from your application. See more +about the <a href="#idvalue">value for {@code android:id}</a> below. </dd> <dt><code>android:layout_height</code></dt> <dd><em>Dimension or keyword</em>. <strong>Required</strong>. The height for the group, as a @@ -107,10 +108,9 @@ attributes</a>).</p> <p class="caps">attributes:</p> <dl class="atn-list"> <dt><code>android:id</code></dt> - <dd><em>Resource name</em>. A unique resource name for the element, which you can use to - obtain a reference to the {@link android.view.View} from your application. - The value takes the form: <code>"@+id/<em>name</em>"</code>. See more about the - <a href="#idvalue">value for {@code android:id}</a> below. + <dd><em>Resource ID</em>. A unique resource name for the element, which you can use to + obtain a reference to the {@link android.view.View} from your application. See more about +the <a href="#idvalue">value for {@code android:id}</a> below. </dd> <dt><code>android:layout_height</code></dt> <dd><em>Dimension or keyword</em>. <strong>Required</strong>. The height for the element, as @@ -137,20 +137,71 @@ or {@code "wrap_content"}). See the <a href="#layoutvalues">valid values</a> bel which gives it's parent initial focus on the screen. You can have only one of these elements per file.</dd> + <dt id="include-element"><code><include></code></dt> + <dd>Includes a layout file into this layout. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>layout</code></dt> + <dd><em>Layout resource</em>. <strong>Required</strong>. Reference to a layout +resource.</dd> + <dt><code>android:id</code></dt> + <dd><em>Resource ID</em>. Overrides the ID given to the root view in the included layout. + </dd> + <dt><code>android:layout_height</code></dt> + <dd><em>Dimension or keyword</em>. Overrides the height given to the root view in the +included layout. + </dd> + <dt><code>android:layout_width</code></dt> + <dd><em>Dimension or keyword</em>. Overrides the width given to the root view in the +included layout. + </dd> + </dl> + <p>You can include any other layout attributes in the <code><include></code> that are +supported by the root element in the included layout and they will override those defined in the +root element.</p> + + <p>Another way to include a layout is to use {@link android.view.ViewStub}. It is a lightweight +View that consumes no layout space until you explicitly inflate it, at which point, it includes a +layout file defined by its {@code android:layout} attribute. For more information about using {@link +android.view.ViewStub}, read <a href="{@docRoot}resources/articles/layout-tricks-stubs.html">Layout +Tricks: ViewStubs</a>.</p> + </dd> + + <dt id="merge-element"><code><merge></code></dt> + <dd>An alternative root element that is not drawn in the layout hierarchy. Using this as the +root element is useful when you know that this layout will be placed into a layout +that already contains the appropriate parent View to contain the children of the +<code><merge></code> element. This is particularly useful when you plan to include this layout +in another layout file using <a href="#include-element"><code><include></code></a> and +this layout doesn't require a different {@link android.view.ViewGroup} container. For more +information about merging layouts, read <a +href="{@docRoot}resources/articles/layout-tricks-merging.html">Layout +Tricks: Merging</a>.</dd> + </dl> + + <h4 id="idvalue">Value for <code>android:id</code></h4> -<p>For the ID value, you should use this syntax form: <code>"@+id/<em>name</em>"</code>. The plus symbol, -{@code +}, indicates that this is a new resource ID and the aapt tool will create -a new resource number to the {@code R.java} class, if it doesn't already exist. For example:</p> +<p>For the ID value, you should usually use this syntax form: <code>"@+id/<em>name</em>"</code>. The +plus symbol, {@code +}, indicates that this is a new resource ID and the <code>aapt</code> tool will +create a new resource integer in the {@code R.java} class, if it doesn't already exist. For +example:</p> <pre> <TextView android:id="@+id/nameTextbox"/> </pre> -<p>You can then refer to it this way in Java:</p> +<p>The <code>nameTextbox</code> name is now a resource ID attached to this element. You can then +refer to the {@link android.widget.TextView} to which the ID is associated in Java:</p> <pre> findViewById(R.id.nameTextbox); </pre> +<p>This code returns the {@link android.widget.TextView} object.</p> + +<p>However, if you have already defined an <a +href="{@docRoot}guide/topics/resources/drawable-resource.html#Id">ID resource</a> (and it is not +already used), then you can apply that ID to a {@link android.view.View} element by excluding the +plus symbol in the <code>android:id</code> value.</p> <h4 id="layoutvalues">Value for <code>android:layout_height</code> and <code>android:layout_width</code>:</h4> diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd index badc403..cde72bd 100644 --- a/docs/html/guide/topics/resources/menu-resource.jd +++ b/docs/html/guide/topics/resources/menu-resource.jd @@ -35,7 +35,7 @@ In XML: <code>@[<em>package</em>:]menu.<em>filename</em></code> <pre> <?xml version="1.0" encoding="utf-8"?> <<a href="#menu-element">menu</a> xmlns:android="http://schemas.android.com/apk/res/android"> - <<a href="#item-element">item</a> android:id="@+id/<em>id_name</em>" + <<a href="#item-element">item</a> android:id="@[+][<em>package</em>:]id/<em>resource_name</em>" android:menuCategory=["container" | "system" | "secondary" | "alternative"] android:orderInCategory="<em>integer</em>" android:title="<em>string</em>" @@ -46,7 +46,7 @@ In XML: <code>@[<em>package</em>:]menu.<em>filename</em></code> android:checkable=["true" | "false"] android:visible=["visible" | "invisible" | "gone"] android:enabled=["enabled" | "disabled"] /> - <<a href="#group-element">group</a> android:id="<em>resource ID</em>" + <<a href="#group-element">group</a> android:id="@[+][<em>package</em>:]id/<em>resource name</em>" android:menuCategory=["container" | "system" | "secondary" | "alternative"] android:orderInCategory="<em>integer</em>" android:checkableBehavior=["none" | "all" | "single"] @@ -84,8 +84,8 @@ child of a <code><menu></code> element. <p class="caps">attributes:</p> <dl class="atn-list"> <dt><code>android:id</code></dt> - <dd><em>Resource name</em>. A unique resource name. The value takes the form: -<code>"@+id/<em>name</em>"</code>.</dd> + <dd><em>Resource ID</em>. A unique resource ID. To create a new resource ID for this item, use the form: +<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new ID.</dd> <dt><code>android:menuCategory</code></dt> <dd><em>Keyword</em>. Value corresponding to {@link android.view.Menu} {@code CATEGORY_*} constants, which define the group's priority. Valid values: @@ -124,8 +124,8 @@ on the data that is currently displayed.</td></tr> <p class="caps">attributes:</p> <dl class="atn-list"> <dt><code>android:id</code></dt> - <dd><em>Resource name</em>. A unique resource name. The value takes the form: -<code>"@+id/<em>name</em>"</code>.</dd> + <dd><em>Resource ID</em>. A unique resource ID. To create a new resource ID for this item, use the form: +<code>"@+id/<em>name</em>"</code>. The plus symbol indicates that this should be created as a new ID.</dd> <dt><code>android:menuCategory</code></dt> <dd><em>Keyword</em>. Value corresponding to {@link android.view.Menu} {@code CATEGORY_*} constants, which define the item's priority. Valid values: diff --git a/docs/html/guide/topics/resources/more-resources.jd b/docs/html/guide/topics/resources/more-resources.jd index 0e2b30b..22abbb2 100644 --- a/docs/html/guide/topics/resources/more-resources.jd +++ b/docs/html/guide/topics/resources/more-resources.jd @@ -12,6 +12,9 @@ parent.link=available-resources.html <dd>XML resource that carries a color value (a hexadecimal color).</dd> <dt><a href="#Dimension">Dimension</a></dt> <dd>XML resource that carries a dimension value (with a unit of measure).</dd> + <dt><a href="#Id">ID</a></dt> + <dd>XML resource that provides a unique identifier for application resources and +components.</dd> <dt><a href="#Integer">Integer</a></dt> <dd>XML resource that carries an integer value.</dd> <dt><a href="#IntegerArray">Integer Array</a></dt> @@ -111,8 +114,8 @@ boolean screenIsSmall = res.{@link android.content.res.Resources#getBoolean(int) <h2 id="Color">Color</h2> <p>A color value defined in XML. -The color is specified with an RGB value and alpha channel. A color resource can be used -any place that expects a hexadecimal color value.</p> +The color is specified with an RGB value and alpha channel. You can use color resource +any place that accepts a hexadecimal color value.</p> <p>The value always begins with a pound (#) character and then followed by the Alpha-Red-Green-Blue information in one of the following formats:</p> @@ -318,6 +321,118 @@ float fontSize = res.{@link android.content.res.Resources#getDimension(int) getD +<h2 id="Id">ID</h2> + +<p>A unique resource ID defined in XML. Using the name you provide in the {@code <item>} +element, the Android developer tools create a unique integer in your project's {@code +R.java} class, which you can use as an +identifier for an application resources (for example, a {@link android.view.View} in your UI layout) +or a unique integer for use in your application code (for example, as an ID for a dialog or a +result code).</p> + +<p class="note"><strong>Note:</strong> An ID is a simple resource that is referenced +using the value provided in the {@code name} attribute (not the name of the XML file). As +such, you can combine ID resources with other simple resources in the one XML file, +under one {@code <resources>} element. Also, remember that an ID resources does not reference +an actual resource item; it is simply a unique ID that you can attach to other resources or use +as a unique integer in your application.</p> + +<dl class="xml"> + +<dt>file location:</dt> +<dd><code>res/values/<em>filename.xml</em></code><br/> +The filename is arbitrary.</dd> + +<dt>resource reference:</dt> +<dd> +In Java: <code>R.id.<em>name</em></code><br/> +In XML: <code>@[<em>package</em>:]id/<em>name</em></code> +</dd> + +<dt>syntax:</dt> +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<<a href="#id-resources-element">resources</a>> + <<a href="#id-item-element">item</a> + type="id" + name="<em>id_name</em>" /> +</resources> +</pre> +</dd> + +<dt>elements:</dt> +<dd> +<dl class="tag-list"> + + <dt id="integer-resources-element"><code><resources></code></dt> + <dd><strong>Required.</strong> This must be the root node. + <p>No attributes.</p> + </dd> + <dt id="integer-element"><code><integer></code></dt> + <dd>Defines a unique ID. Takes no value, only attributes. + <p class="caps">attributes:</p> + <dl class="atn-list"> + <dt><code>type</code></dt> + <dd>Must be "id".</dd> + <dt><code>name</code></dt> + <dd><em>String</em>. A unique name for the ID.</dd> + </dl> + </dd> + +</dl> +</dd> <!-- end elements and attributes --> + +<dt>example:</dt> +<dd> + <p>XML file saved at <code>res/values/ids.xml</code>:</p> +<pre> +<?xml version="1.0" encoding="utf-8"?> +<resources> + <item type="id" name="button_ok" /> + <item type="id" name="dialog_exit" /> +</resources> +</pre> + + <p>Then, this layout snippet uses the "button_ok" ID for a Button widget:</p> +<pre> +<Button android:id="<b>@id/button_ok</b>" + style="@style/button_style" /> +</pre> + + <p>Notice that the {@code android:id} value does not include the plus sign in the ID reference, +because the ID already exists, as defined in the {@code ids.xml} example above. (When you specify an +ID to an XML resource using the plus sign—in the format {@code +android:id="@+id/name"}—it means that the "name" ID does not exist and should be created.)</p> + + <p>As another example, the following code snippet uses the "dialog_exit" ID as a unique identifier +for a dialog:</p> +<pre> +{@link android.app.Activity#showDialog(int) showDialog}(<b>R.id.dialog_exit</b>); +</pre> + <p>In the same application, the "dialog_exit" ID is compared when creating a dialog:</p> +<pre> +protected Dialog {@link android.app.Activity#onCreateDialog(int)}(int id) { + Dialog dialog; + switch(id) { + case <b>R.id.dialog_exit</b>: + ... + break; + default: + dialog = null; + } + return dialog; +} +</pre> +</dd> <!-- end example --> + + +</dl> + + + + + <h2 id="Integer">Integer</h2> <p>An integer defined in XML.</p> @@ -347,7 +462,7 @@ In XML: <code>@[<em>package</em>:]integer/<em>integer_name</em></code> <<a href="#integer-resources-element">resources</a>> <<a href="#integer-element">integer</a> name="<em>integer_name</em>" - ><em>integer</em></dimen> + ><em>integer</em></integer> </resources> </pre> </dd> @@ -379,8 +494,8 @@ In XML: <code>@[<em>package</em>:]integer/<em>integer_name</em></code> <pre> <?xml version="1.0" encoding="utf-8"?> <resources> - <integer name="max_speed">75</dimen> - <integer name="min_speed">5</dimen> + <integer name="max_speed">75</integer> + <integer name="min_speed">5</integer> </resources> </pre> <p>This application code retrieves an integer:</p> diff --git a/docs/html/images/resources/clip.png b/docs/html/images/resources/clip.png Binary files differnew file mode 100644 index 0000000..9196b3f --- /dev/null +++ b/docs/html/images/resources/clip.png diff --git a/docs/html/images/resources/layers.png b/docs/html/images/resources/layers.png Binary files differnew file mode 100644 index 0000000..f7e6929 --- /dev/null +++ b/docs/html/images/resources/layers.png diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index f126374..3f9f961 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -16,61 +16,84 @@ package android.graphics; -public class ImageFormat -{ - /* these constants are chosen to be binary compatible with - * their previous location in PixelFormat.java */ - - public static final int UNKNOWN = 0; +public class ImageFormat { + /* + * these constants are chosen to be binary compatible with their previous + * location in PixelFormat.java + */ - /** RGB format used for pictures encoded as RGB_565 - * see {@link android.hardware.Camera.Parameters#setPictureFormat(int)}. - */ - public static final int RGB_565 = 4; + public static final int UNKNOWN = 0; - /** - * YCbCr formats, used for video. These are not necessarily supported - * by the hardware. - */ - public static final int NV16 = 0x10; + /** + * RGB format used for pictures encoded as RGB_565 see + * {@link android.hardware.Camera.Parameters#setPictureFormat(int)}. + */ + public static final int RGB_565 = 4; - - /** YCrCb format used for images, which uses the NV21 encoding format. - * This is the default format for camera preview images, when not - * otherwise set with - * {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}. - */ - public static final int NV21 = 0x11; + /** + * Planar 4:2:0 YCrCb format. This format assumes an horizontal stride of 16 + * pixels for all planes and an implicit vertical stride of the image + * height's next multiple of two. + * y_size = stride * ALIGN(height, 2) + * c_size = ALIGN(stride/2, 16) * height + * size = y_size + c_size * 2 + * cr_offset = y_size + * cb_offset = y_size + c_size + * + * Whether this format is supported by the camera hardware can be determined + * by + * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. + */ + public static final int YV12 = 0x32315659; + /** + * YCbCr format, used for video. Whether this format is supported by the + * camera hardware can be determined by + * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. + */ + public static final int NV16 = 0x10; - /** YCbCr format used for images, which uses YUYV (YUY2) encoding format. - * This is an alternative format for camera preview images. Whether this - * format is supported by the camera hardware can be determined by - * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. - */ - public static final int YUY2 = 0x14; + /** + * YCrCb format used for images, which uses the NV21 encoding format. This + * is the default format for camera preview images, when not otherwise set + * with {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}. + */ + public static final int NV21 = 0x11; - - /** - * Encoded formats. These are not necessarily supported by the hardware. - */ - public static final int JPEG = 0x100; + /** + * YCbCr format used for images, which uses YUYV (YUY2) encoding format. + * This is an alternative format for camera preview images. Whether this + * format is supported by the camera hardware can be determined by + * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. + */ + public static final int YUY2 = 0x14; + /** + * Encoded formats. These are not necessarily supported by the hardware. + */ + public static final int JPEG = 0x100; - /** - * Use this function to retrieve the number of bits per pixel of - * an ImageFormat. - * @param format - * @return the number of bits per pixel of the given format or -1 if the - * format doesn't exist or is not supported. - */ - public static int getBitsPerPixel(int format) { - switch (format) { - case RGB_565: return 16; - case NV16: return 16; - case NV21: return 12; - case YUY2: return 16; - } - return -1; - } + /** + * Use this function to retrieve the number of bits per pixel of an + * ImageFormat. + * + * @param format + * @return the number of bits per pixel of the given format or -1 if the + * format doesn't exist or is not supported. + */ + public static int getBitsPerPixel(int format) { + switch (format) { + case RGB_565: + return 16; + case NV16: + return 16; + case YUY2: + return 16; + case YV12: + return 12; + case NV21: + return 12; + } + return -1; + } } diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index fdc4c92..e275ba8 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -64,6 +64,8 @@ import android.util.AttributeSet; * // Start the animation (looped playback by default). * frameAnimation.start() * </pre> + * <p>For more information, see the guide to <a + * href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p> * * @attr ref android.R.styleable#AnimationDrawable_visible * @attr ref android.R.styleable#AnimationDrawable_variablePadding diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 29e14d2..32111e8 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -40,7 +40,9 @@ import java.io.IOException; * A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a * BitmapDrawable from a file path, an input stream, through XML inflation, or from * a {@link android.graphics.Bitmap} object. - * <p>It can be defined in an XML file with the <code><bitmap></code> element.</p> + * <p>It can be defined in an XML file with the <code><bitmap></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> * <p> * Also see the {@link android.graphics.Bitmap} class, which handles the management and * transformation of raw bitmap graphics, and should be used when drawing to a diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index c387a9b..a772871 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -32,9 +32,14 @@ import java.io.IOException; * level value. You can control how much the child Drawable gets clipped in width * and height based on the level, as well as a gravity to control where it is * placed in its overall container. Most often used to implement things like - * progress bars. + * progress bars, by increasing the drawable's level with {@link + * android.graphics.drawable.Drawable#setLevel(int) setLevel()}. + * <p class="note"><strong>Note:</strong> The drawable is clipped completely and not visible when + * the level is 0 and fully revealed when the level is 10,000.</p> * - * <p>It can be defined in an XML file with the <code><clip></code> element.</p> + * <p>It can be defined in an XML file with the <code><clip></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> * * @attr ref android.R.styleable#ClipDrawable_clipOrientation * @attr ref android.R.styleable#ClipDrawable_gravity diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 4c1d243..7b2d9d7 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -102,8 +102,8 @@ import java.util.Arrays; * whose overall size is modified based on the current level. * </ul> * <p>For information and examples of creating drawable resources (XML or bitmap files that - * can be loaded in code), see <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources - * and Internationalization</a>. + * can be loaded in code), see <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. */ public abstract class Drawable { private static final Rect ZERO_BOUNDS_RECT = new Rect(); @@ -720,8 +720,7 @@ public abstract class Drawable { /** * Create a drawable from an XML document. For more information on how to * create resources in XML, see - * <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources and - * Internationalization</a>. + * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. */ public static Drawable createFromXml(Resources r, XmlPullParser parser) throws XmlPullParserException, IOException { diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 63d1446..33ecbea 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -42,7 +42,9 @@ import java.io.IOException; /** * A Drawable with a color gradient for buttons, backgrounds, etc. * - * <p>It can be defined in an XML file with the <code><shape></code> element.</p> + * <p>It can be defined in an XML file with the <code><shape></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> * * @attr ref android.R.styleable#GradientDrawable_visible * @attr ref android.R.styleable#GradientDrawable_shape diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 4fa9d44..a9c983e 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -32,7 +32,9 @@ import java.io.IOException; * This is used when a View needs a background that is smaller than * the View's actual bounds. * - * <p>It can be defined in an XML file with the <code><inset></code> element.</p> + * <p>It can be defined in an XML file with the <code><inset></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> * * @attr ref android.R.styleable#InsetDrawable_visible * @attr ref android.R.styleable#InsetDrawable_drawable diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index b727d47..501cca9 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -32,8 +32,9 @@ import java.io.IOException; * order, so the element with the largest index will be drawn on top. * <p> * It can be defined in an XML file with the <code><layer-list></code> element. - * Each Drawable in the layer is defined in a nested <code><item></code>. - * </p> + * Each Drawable in the layer is defined in a nested <code><item></code>. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> * * @attr ref android.R.styleable#LayerDrawableItem_left * @attr ref android.R.styleable#LayerDrawableItem_top diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java index ae8f224..21be983 100644 --- a/graphics/java/android/graphics/drawable/LevelListDrawable.java +++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java @@ -47,7 +47,10 @@ import android.util.AttributeSet; * <p>With this XML saved into the res/drawable/ folder of the project, it can be referenced as * the drawable for an {@link android.widget.ImageView}. The default image is the first in the list. * It can then be changed to one of the other levels with - * {@link android.widget.ImageView#setImageLevel(int)}.</p> + * {@link android.widget.ImageView#setImageLevel(int)}. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> + * * @attr ref android.R.styleable#LevelListDrawableItem_minLevel * @attr ref android.R.styleable#LevelListDrawableItem_maxLevel * @attr ref android.R.styleable#LevelListDrawableItem_drawable diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index 2083e05..9c47dab 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -35,7 +35,9 @@ import java.io.IOException; * value. The start and end angles of rotation can be controlled to map any * circular arc to the level values range.</p> * - * <p>It can be defined in an XML file with the <code><rotate></code> element.</p> + * <p>It can be defined in an XML file with the <code><rotate></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.</p> * * @attr ref android.R.styleable#RotateDrawable_visible * @attr ref android.R.styleable#RotateDrawable_fromDegrees diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index 275e36f..b623d80 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -34,7 +34,9 @@ import java.io.IOException; * placed in its overall container. Most often used to implement things like * progress bars. * - * <p>It can be defined in an XML file with the <code><scale></code> element.</p> + * <p>It can be defined in an XML file with the <code><scale></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> * * @attr ref android.R.styleable#ScaleDrawable_scaleWidth * @attr ref android.R.styleable#ScaleDrawable_scaleHeight diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index c699a82..be1892e 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -34,6 +34,10 @@ import java.io.IOException; * the ShapeDrawable will default to a * {@link android.graphics.drawable.shapes.RectShape}. * + * <p>It can be defined in an XML file with the <code><shape></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> + * * @attr ref android.R.styleable#ShapeDrawablePadding_left * @attr ref android.R.styleable#ShapeDrawablePadding_top * @attr ref android.R.styleable#ShapeDrawablePadding_right diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index b94df84..239be40 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -31,7 +31,9 @@ import android.util.StateSet; * ID value. * <p/> * <p>It can be defined in an XML file with the <code><selector></code> element. - * Each state Drawable is defined in a nested <code><item></code> element.</p> + * Each state Drawable is defined in a nested <code><item></code> element. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> * * @attr ref android.R.styleable#StateListDrawable_visible * @attr ref android.R.styleable#StateListDrawable_variablePadding diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index 97b45d8..4470356 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -26,8 +26,10 @@ import android.os.SystemClock; * display just the first layer, call {@link #resetTransition()}. * <p> * It can be defined in an XML file with the <code><transition></code> element. - * Each Drawable in the transition is defined in a nested <code><item></code>. - * </p> + * Each Drawable in the transition is defined in a nested <code><item></code>. For more + * information, see the guide to <a + * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> + * * @attr ref android.R.styleable#LayerDrawableItem_left * @attr ref android.R.styleable#LayerDrawableItem_top * @attr ref android.R.styleable#LayerDrawableItem_right @@ -212,7 +214,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba * Enables or disables the cross fade of the drawables. When cross fade * is disabled, the first drawable is always drawn opaque. With cross * fade enabled, the first drawable is drawn with the opposite alpha of - * the second drawable. + * the second drawable. Cross fade is disabled by default. * * @param enabled True to enable cross fading, false otherwise. */ diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h new file mode 100644 index 0000000..2316fef --- /dev/null +++ b/include/binder/BinderService.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_BINDER_SERVICE_H +#define ANDROID_BINDER_SERVICE_H + +#include <stdint.h> + +#include <utils/Errors.h> +#include <utils/String16.h> + +#include <binder/IServiceManager.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> + +// --------------------------------------------------------------------------- +namespace android { + +template<typename SERVICE> +class BinderService +{ +public: + static status_t publish() { + sp<IServiceManager> sm(defaultServiceManager()); + return sm->addService(String16(SERVICE::getServiceName()), new SERVICE()); + } + + static void publishAndJoinThreadPool() { + sp<ProcessState> proc(ProcessState::self()); + sp<IServiceManager> sm(defaultServiceManager()); + sm->addService(String16(SERVICE::getServiceName()), new SERVICE()); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + } + + static void instantiate() { publish(); } + + static status_t shutdown() { + return NO_ERROR; + } +}; + + +}; // namespace android +// --------------------------------------------------------------------------- +#endif // ANDROID_BINDER_SERVICE_H diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h new file mode 100644 index 0000000..ed4e4cc --- /dev/null +++ b/include/gui/ISensorEventConnection.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H +#define ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> + +#include <binder/IInterface.h> + +namespace android { +// ---------------------------------------------------------------------------- + +class SensorChannel; + +class ISensorEventConnection : public IInterface +{ +public: + DECLARE_META_INTERFACE(SensorEventConnection); + + virtual sp<SensorChannel> getSensorChannel() const = 0; + virtual status_t enableDisable(int handle, bool enabled) = 0; + virtual status_t setEventRate(int handle, nsecs_t ns) = 0; +}; + +// ---------------------------------------------------------------------------- + +class BnSensorEventConnection : public BnInterface<ISensorEventConnection> +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_ISENSOR_EVENT_CONNECTION_H diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h new file mode 100644 index 0000000..3e05076 --- /dev/null +++ b/include/gui/ISensorServer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_ISENSORSERVER_H +#define ANDROID_GUI_ISENSORSERVER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> + +#include <binder/IInterface.h> + +namespace android { +// ---------------------------------------------------------------------------- + +class Sensor; +class ISensorEventConnection; + +class ISensorServer : public IInterface +{ +public: + DECLARE_META_INTERFACE(SensorServer); + + virtual Vector<Sensor> getSensorList()= 0; + virtual sp<ISensorEventConnection> createSensorEventConnection() = 0; +}; + +// ---------------------------------------------------------------------------- + +class BnSensorServer : public BnInterface<ISensorServer> +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_ISENSORSERVER_H diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h new file mode 100644 index 0000000..86a16f1 --- /dev/null +++ b/include/gui/Sensor.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_SENSOR_H +#define ANDROID_GUI_SENSOR_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/String8.h> +#include <utils/Flattenable.h> + +#include <hardware/sensors.h> + +#include <android/sensor.h> + +// ---------------------------------------------------------------------------- +// Concrete types for the NDK +struct ASensor { }; + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +class Parcel; + +// ---------------------------------------------------------------------------- + +class Sensor : public ASensor, public Flattenable +{ +public: + enum { + TYPE_ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER, + TYPE_MAGNETIC_FIELD = ASENSOR_TYPE_MAGNETIC_FIELD, + TYPE_GYROSCOPE = ASENSOR_TYPE_GYROSCOPE, + TYPE_LIGHT = ASENSOR_TYPE_LIGHT, + TYPE_PROXIMITY = ASENSOR_TYPE_PROXIMITY + }; + + Sensor(); + virtual ~Sensor(); + + const String8& getName() const; + const String8& getVendor() const; + int32_t getHandle() const; + int32_t getType() const; + float getMinValue() const; + float getMaxValue() const; + float getResolution() const; + float getPowerUsage() const; + + // Flattenable interface + virtual size_t getFlattenedSize() const; + virtual size_t getFdCount() const; + virtual status_t flatten(void* buffer, size_t size, + int fds[], size_t count) const; + virtual status_t unflatten(void const* buffer, size_t size, + int fds[], size_t count); + +private: + String8 mName; + String8 mVendor; + int32_t mHandle; + int32_t mType; + float mMinValue; + float mMaxValue; + float mResolution; + float mPower; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_SENSOR_H diff --git a/include/gui/SensorChannel.h b/include/gui/SensorChannel.h new file mode 100644 index 0000000..bb54618 --- /dev/null +++ b/include/gui/SensorChannel.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_SENSOR_CHANNEL_H +#define ANDROID_GUI_SENSOR_CHANNEL_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> + + +namespace android { +// ---------------------------------------------------------------------------- +class Parcel; + +class SensorChannel : public RefBase +{ +public: + + SensorChannel(); + SensorChannel(const Parcel& data); + virtual ~SensorChannel(); + + int getFd() const; + ssize_t write(void const* vaddr, size_t size); + ssize_t read(void* vaddr, size_t size); + + status_t writeToParcel(Parcel* reply) const; + +private: + int mSendFd; + mutable int mReceiveFd; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_SENSOR_CHANNEL_H diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h new file mode 100644 index 0000000..d8d8128 --- /dev/null +++ b/include/gui/SensorEventQueue.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SENSOR_EVENT_QUEUE_H +#define ANDROID_SENSOR_EVENT_QUEUE_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> + +#include <gui/SensorChannel.h> + +// ---------------------------------------------------------------------------- + +struct ALooper; +struct ASensorEvent; + +// Concrete types for the NDK +struct ASensorEventQueue { + ALooper* looper; +}; + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +class ISensorEventConnection; +class Sensor; + +// ---------------------------------------------------------------------------- + +class SensorEventQueue : public ASensorEventQueue, public RefBase +{ +public: + SensorEventQueue(const sp<ISensorEventConnection>& connection); + virtual ~SensorEventQueue(); + virtual void onFirstRef(); + + int getFd() const; + ssize_t write(ASensorEvent const* events, size_t numEvents); + ssize_t read(ASensorEvent* events, size_t numEvents); + + status_t enableSensor(Sensor const* sensor) const; + status_t disableSensor(Sensor const* sensor) const; + status_t setEventRate(Sensor const* sensor, nsecs_t ns) const; + +private: + sp<ISensorEventConnection> mSensorEventConnection; + sp<SensorChannel> mSensorChannel; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SENSOR_EVENT_QUEUE_H diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h new file mode 100644 index 0000000..0d65334 --- /dev/null +++ b/include/gui/SensorManager.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_SENSOR_MANAGER_H +#define ANDROID_GUI_SENSOR_MANAGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Singleton.h> +#include <utils/Vector.h> + +#include <gui/SensorEventQueue.h> + +// ---------------------------------------------------------------------------- +// Concrete types for the NDK +struct ASensorManager { }; + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +class ISensorServer; +class Sensor; +class SensorEventQueue; + +// ---------------------------------------------------------------------------- + +class SensorManager : public ASensorManager, public Singleton<SensorManager> +{ +public: + SensorManager(); + ~SensorManager(); + + ssize_t getSensorList(Sensor**) const; + Sensor* getDefaultSensor(int type); + sp<SensorEventQueue> createEventQueue(); + +private: + sp<ISensorServer> mSensorServer; + Sensor* mSensorList; + Vector<Sensor> mSensors; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_SENSOR_MANAGER_H diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 962b38b..232583a 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -52,6 +52,7 @@ public: void endBox(); uint32_t interleaveDuration() const { return mInterleaveDurationUs; } status_t setInterleaveDuration(uint32_t duration); + int32_t getTimeScale() const { return mTimeScale; } protected: virtual ~MPEG4Writer(); @@ -72,6 +73,7 @@ private: bool mStreamableFile; off_t mEstimatedMoovBoxSize; uint32_t mInterleaveDurationUs; + int32_t mTimeScale; int64_t mStartTimestampUs; Mutex mLock; diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 73f5547..cdbf483 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -68,6 +68,7 @@ enum { kKeyDiscNumber = 'dnum', // cstring kKeyDate = 'date', // cstring kKeyWriter = 'writ', // cstring + kKeyTimeScale = 'tmsl', // int32_t // video profile and level kKeyVideoProfile = 'vprf', // int32_t diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk new file mode 100644 index 0000000..249558a --- /dev/null +++ b/libs/gui/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + ISensorEventConnection.cpp \ + ISensorServer.cpp \ + Sensor.cpp \ + SensorChannel.cpp \ + SensorEventQueue.cpp \ + SensorManager.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libhardware \ + libhardware_legacy + +LOCAL_MODULE:= libgui + +ifeq ($(TARGET_SIMULATOR),true) + LOCAL_LDLIBS += -lpthread +endif + +include $(BUILD_SHARED_LIBRARY) diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp new file mode 100644 index 0000000..3e9d456 --- /dev/null +++ b/libs/gui/ISensorEventConnection.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> + +#include <binder/Parcel.h> +#include <binder/IInterface.h> + +#include <gui/ISensorEventConnection.h> +#include <gui/SensorChannel.h> + +namespace android { +// ---------------------------------------------------------------------------- + +enum { + GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, + ENABLE_DISABLE, + SET_EVENT_RATE +}; + +class BpSensorEventConnection : public BpInterface<ISensorEventConnection> +{ +public: + BpSensorEventConnection(const sp<IBinder>& impl) + : BpInterface<ISensorEventConnection>(impl) + { + } + + virtual sp<SensorChannel> getSensorChannel() const + { + Parcel data, reply; + remote()->transact(GET_SENSOR_CHANNEL, data, &reply); + return new SensorChannel(reply); + } + + virtual status_t enableDisable(int handle, bool enabled) + { + Parcel data, reply; + data.writeInt32(handle); + data.writeInt32(enabled); + remote()->transact(ENABLE_DISABLE, data, &reply); + return reply.readInt32(); + } + + virtual status_t setEventRate(int handle, nsecs_t ns) + { + Parcel data, reply; + data.writeInt32(handle); + data.writeInt64(ns); + remote()->transact(SET_EVENT_RATE, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection"); + +// ---------------------------------------------------------------------------- + +status_t BnSensorEventConnection::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case GET_SENSOR_CHANNEL: { + CHECK_INTERFACE(ISensorEventConnection, data, reply); + sp<SensorChannel> channel(getSensorChannel()); + channel->writeToParcel(reply); + return NO_ERROR; + } break; + case ENABLE_DISABLE: { + CHECK_INTERFACE(ISensorEventConnection, data, reply); + int handle = data.readInt32(); + int enabled = data.readInt32(); + status_t result = enableDisable(handle, enabled); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_EVENT_RATE: { + CHECK_INTERFACE(ISensorEventConnection, data, reply); + int handle = data.readInt32(); + int ns = data.readInt64(); + status_t result = setEventRate(handle, ns); + reply->writeInt32(result); + return NO_ERROR; + } break; + } + return BBinder::onTransact(code, data, reply, flags); +} + +// ---------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp new file mode 100644 index 0000000..c6177bc --- /dev/null +++ b/libs/gui/ISensorServer.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Vector.h> +#include <utils/Timers.h> + +#include <binder/Parcel.h> +#include <binder/IInterface.h> + +#include <gui/Sensor.h> +#include <gui/ISensorServer.h> +#include <gui/ISensorEventConnection.h> + +namespace android { +// ---------------------------------------------------------------------------- + +enum { + GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION, + CREATE_SENSOR_EVENT_CONNECTION, +}; + +class BpSensorServer : public BpInterface<ISensorServer> +{ +public: + BpSensorServer(const sp<IBinder>& impl) + : BpInterface<ISensorServer>(impl) + { + } + + virtual Vector<Sensor> getSensorList() + { + Parcel data, reply; + remote()->transact(GET_SENSOR_LIST, data, &reply); + Sensor s; + Vector<Sensor> v; + int32_t n = reply.readInt32(); + v.setCapacity(n); + while (n--) { + reply.read(static_cast<Flattenable&>(s)); + v.add(s); + } + return v; + } + + virtual sp<ISensorEventConnection> createSensorEventConnection() + { + Parcel data, reply; + remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply); + return interface_cast<ISensorEventConnection>(reply.readStrongBinder()); + } +}; + +IMPLEMENT_META_INTERFACE(SensorServer, "android.gui.SensorServer"); + +// ---------------------------------------------------------------------- + +status_t BnSensorServer::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case GET_SENSOR_LIST: { + CHECK_INTERFACE(ISensorServer, data, reply); + Vector<Sensor> v(getSensorList()); + size_t n = v.size(); + reply->writeInt32(n); + for (size_t i=0 ; i<n ; i++) { + reply->write(static_cast<const Flattenable&>(v[i])); + } + return NO_ERROR; + } break; + case CREATE_SENSOR_EVENT_CONNECTION: { + CHECK_INTERFACE(ISensorServer, data, reply); + sp<ISensorEventConnection> connection(createSensorEventConnection()); + reply->writeStrongBinder(connection->asBinder()); + return NO_ERROR; + } break; + } + return BBinder::onTransact(code, data, reply, flags); +} + +// ---------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp new file mode 100644 index 0000000..1fdd285 --- /dev/null +++ b/libs/gui/Sensor.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/String8.h> +#include <utils/Flattenable.h> + +#include <hardware/sensors.h> + +#include <gui/Sensor.h> + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +Sensor::Sensor() + : mHandle(0), mType(0), + mMinValue(0), mMaxValue(0), mResolution(0), + mPower(0) +{ +} + +Sensor::~Sensor() +{ +} + +const String8& Sensor::getName() const { + return mName; +} + +const String8& Sensor::getVendor() const { + return mVendor; +} + +int32_t Sensor::getHandle() const { + return mHandle; +} + +int32_t Sensor::getType() const { + return mType; +} + +float Sensor::getMinValue() const { + return mMinValue; +} + +float Sensor::getMaxValue() const { + return mMaxValue; +} + +float Sensor::getResolution() const { + return mResolution; +} + +float Sensor::getPowerUsage() const { + return mPower; +} + +size_t Sensor::getFlattenedSize() const +{ + return sizeof(int32_t) + ((mName.length() + 3) & ~3) + + sizeof(int32_t) + ((mVendor.length() + 3) & ~3) + + sizeof(int32_t) * 2 + + sizeof(float) * 3; +} + +size_t Sensor::getFdCount() const +{ + return 0; +} + +static inline +size_t write(void* buffer, size_t offset, const String8& value) { + memcpy(static_cast<char*>(buffer) + offset, value.string(), value.length()); + return (value.length() + 3) & ~3; +} + +static inline +size_t write(void* buffer, size_t offset, float value) { + *reinterpret_cast<float*>(static_cast<char*>(buffer) + offset) = value; + return sizeof(float); +} + +static inline +size_t write(void* buffer, size_t offset, int32_t value) { + *reinterpret_cast<int32_t*>(static_cast<char*>(buffer) + offset) = value; + return sizeof(int32_t); +} + +status_t Sensor::flatten(void* buffer, size_t size, + int fds[], size_t count) const +{ + if (size < Sensor::getFlattenedSize()) + return -ENOMEM; + + size_t offset = 0; + offset += write(buffer, offset, int32_t(mName.length())); + offset += write(buffer, offset, mName); + offset += write(buffer, offset, int32_t(mVendor.length())); + offset += write(buffer, offset, mVendor); + offset += write(buffer, offset, mHandle); + offset += write(buffer, offset, mType); + offset += write(buffer, offset, mMinValue); + offset += write(buffer, offset, mMaxValue); + offset += write(buffer, offset, mResolution); + offset += write(buffer, offset, mPower); + + return NO_ERROR; +} + +static inline +size_t read(void const* buffer, size_t offset, String8* value, int32_t len) { + value->setTo(static_cast<char const*>(buffer) + offset, len); + return (len + 3) & ~3; +} + +static inline +size_t read(void const* buffer, size_t offset, float* value) { + *value = *reinterpret_cast<float const*>(static_cast<char const*>(buffer) + offset); + return sizeof(float); +} + +static inline +size_t read(void const* buffer, size_t offset, int32_t* value) { + *value = *reinterpret_cast<int32_t const*>(static_cast<char const*>(buffer) + offset); + return sizeof(int32_t); +} + +status_t Sensor::unflatten(void const* buffer, size_t size, + int fds[], size_t count) +{ + int32_t len; + size_t offset = 0; + offset += read(buffer, offset, &len); + offset += read(buffer, offset, &mName, len); + offset += read(buffer, offset, &len); + offset += read(buffer, offset, &mVendor, len); + offset += read(buffer, offset, &mHandle); + offset += read(buffer, offset, &mType); + offset += read(buffer, offset, &mMinValue); + offset += read(buffer, offset, &mMaxValue); + offset += read(buffer, offset, &mResolution); + offset += read(buffer, offset, &mPower); + + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/gui/SensorChannel.cpp b/libs/gui/SensorChannel.cpp new file mode 100644 index 0000000..147e1c2 --- /dev/null +++ b/libs/gui/SensorChannel.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <unistd.h> +#include <fcntl.h> + +#include <utils/Errors.h> + +#include <binder/Parcel.h> + +#include <gui/SensorChannel.h> + +namespace android { +// ---------------------------------------------------------------------------- + +SensorChannel::SensorChannel() + : mSendFd(-1), mReceiveFd(-1) +{ + int fds[2]; + if (pipe(fds) == 0) { + mReceiveFd = fds[0]; + mSendFd = fds[1]; + fcntl(mReceiveFd, F_SETFL, O_NONBLOCK); + fcntl(mSendFd, F_SETFL, O_NONBLOCK); + } +} + +SensorChannel::SensorChannel(const Parcel& data) + : mSendFd(-1), mReceiveFd(-1) +{ + mReceiveFd = dup(data.readFileDescriptor()); + fcntl(mReceiveFd, F_SETFL, O_NONBLOCK); +} + +SensorChannel::~SensorChannel() +{ + if (mSendFd >= 0) + close(mSendFd); + + if (mReceiveFd >= 0) + close(mReceiveFd); +} + +int SensorChannel::getFd() const +{ + return mReceiveFd; +} + +ssize_t SensorChannel::write(void const* vaddr, size_t size) +{ + ssize_t len = ::write(mSendFd, vaddr, size); + if (len < 0) + return -errno; + return len; +} + +ssize_t SensorChannel::read(void* vaddr, size_t size) +{ + ssize_t len = ::read(mReceiveFd, vaddr, size); + if (len < 0) + return -errno; + return len; +} + +status_t SensorChannel::writeToParcel(Parcel* reply) const +{ + if (mReceiveFd < 0) + return -EINVAL; + + status_t result = reply->writeDupFileDescriptor(mReceiveFd); + close(mReceiveFd); + mReceiveFd = -1; + return result; +} + +// ---------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp new file mode 100644 index 0000000..f922ac4 --- /dev/null +++ b/libs/gui/SensorEventQueue.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> + +#include <gui/Sensor.h> +#include <gui/SensorChannel.h> +#include <gui/SensorEventQueue.h> +#include <gui/ISensorEventConnection.h> + +#include <android/sensor.h> + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection) + : mSensorEventConnection(connection) +{ +} + +SensorEventQueue::~SensorEventQueue() +{ +} + +void SensorEventQueue::onFirstRef() +{ + mSensorChannel = mSensorEventConnection->getSensorChannel(); +} + +int SensorEventQueue::getFd() const +{ + return mSensorChannel->getFd(); +} + +ssize_t SensorEventQueue::write(ASensorEvent const* events, size_t numEvents) +{ + ssize_t size = mSensorChannel->write(events, numEvents * sizeof(events[0])); + if (size >= 0) { + if (size % sizeof(events[0])) { + // partial write!!! should never happen. + return -EINVAL; + } + // returns number of events written + size /= sizeof(events[0]); + } + return size; +} + +ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) +{ + ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0])); + if (size >= 0) { + if (size % sizeof(events[0])) { + // partial write!!! should never happen. + return -EINVAL; + } + // returns number of events read + size /= sizeof(events[0]); + } + return size; +} + +status_t SensorEventQueue::enableSensor(Sensor const* sensor) const +{ + return mSensorEventConnection->enableDisable(sensor->getHandle(), true); +} + +status_t SensorEventQueue::disableSensor(Sensor const* sensor) const +{ + return mSensorEventConnection->enableDisable(sensor->getHandle(), false); +} + +status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const +{ + return mSensorEventConnection->setEventRate(sensor->getHandle(), ns); +} + +// ---------------------------------------------------------------------------- +}; // namespace android + diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp new file mode 100644 index 0000000..cd89285 --- /dev/null +++ b/libs/gui/SensorManager.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Errors.h> +#include <utils/RefBase.h> +#include <utils/Singleton.h> + +#include <gui/ISensorServer.h> +#include <gui/ISensorEventConnection.h> +#include <gui/Sensor.h> +#include <gui/SensorManager.h> +#include <gui/SensorEventQueue.h> + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(SensorManager) + +SensorManager::SensorManager() + : mSensorList(0) +{ + mSensors = mSensorServer->getSensorList(); + // TODO: needs implementation +} + +SensorManager::~SensorManager() +{ + // TODO: needs implementation +} + +ssize_t SensorManager::getSensorList(Sensor** list) const +{ + *list = mSensorList; + return mSensors.size(); +} + +Sensor* SensorManager::getDefaultSensor(int type) +{ + // TODO: needs implementation + return mSensorList; +} + +sp<SensorEventQueue> SensorManager::createEventQueue() +{ + sp<SensorEventQueue> result = new SensorEventQueue( + mSensorServer->createSensorEventConnection()); + return result; +} + +// ---------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 40c80fa..ba5be03 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -88,6 +88,9 @@ public: void copyTo(float* v) const; void copyTo(SkMatrix& v) const; + /** + * Does not apply rotations! + */ void mapRect(Rect& r) const; float getTranslateX(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 9739b9b..12b0dea 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -406,7 +406,7 @@ bool OpenGLRenderer::quickReject(float left, float top, float right, float botto } bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) { - bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom); + bool clipped = mSnapshot->clip(left, top, right, bottom); if (clipped) { mSnapshot->flags |= Snapshot::kFlagClipSet; setScissorFromClip(); @@ -492,8 +492,8 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, } void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { - const Rect& clip = mSnapshot->clipRect; - drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode); + const Rect& clip = mSnapshot->getMappedClip(); + drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); } void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { @@ -524,7 +524,7 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, /////////////////////////////////////////////////////////////////////////////// void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, - int color, SkXfermode::Mode mode) { + int color, SkXfermode::Mode mode, bool ignoreTransform) { const int alpha = (color >> 24) & 0xFF; const GLfloat a = alpha / 255.0f; const GLfloat r = ((color >> 16) & 0xFF) / 255.0f; @@ -538,7 +538,12 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot mModelView.scale(right - left, bottom - top, 1.0f); const bool inUse = useShader(mDrawColorShader); - mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform); + if (!ignoreTransform) { + mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform); + } else { + mat4 identity; + mDrawColorShader->set(mOrthoMatrix, mModelView, identity); + } if (!inUse) { const GLvoid* p = &gDrawColorVertices[0].position[0]; diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 1165ab6..8083038 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -160,9 +160,10 @@ private: * @param bottom The bottom coordinate of the rectangle * @param color The rectangle's ARGB color, defined as a packed 32 bits word * @param mode The Skia xfermode to use + * @param ignoreTransform True if the current transform should be ignored */ void drawColorRect(float left, float top, float right, float bottom, - int color, SkXfermode::Mode mode); + int color, SkXfermode::Mode mode, bool ignoreTransform = false); /** * Draws a textured rectangle with the specified texture. The specified coordinates diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index ef9269f..7265d91 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -56,6 +56,8 @@ public: previous(s), layer(NULL), fbo(s->fbo) { + mappedClip.set(s->clipRect); + transform.mapRect(mappedClip); } /** @@ -87,12 +89,20 @@ public: * Returns the current clip region mapped by the current transform. */ const Rect& getMappedClip() { + return mappedClip; + } + + /** + * Intersects the current clip with the new clip rectangle. + */ + bool clip(float left, float top, float right, float bottom) { + bool clipped = clipRect.intersect(left, top, right, bottom); if (flags & kFlagDirtyTransform) { flags &= ~kFlagDirtyTransform; mappedClip.set(clipRect); transform.mapRect(mappedClip); } - return mappedClip; + return clipped; } /** diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index b205418..edf1aed 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -60,7 +60,6 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info) switch (format) { case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: - case HAL_PIXEL_FORMAT_YV16: info->bitsPerPixel = 16; goto done; case HAL_PIXEL_FORMAT_YCrCb_420_SP: diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk index 46d7493..62f824f 100644 --- a/libs/ui/tests/Android.mk +++ b/libs/ui/tests/Android.mk @@ -2,6 +2,9 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifneq ($(TARGET_SIMULATOR),true) + +# Build the unit tests. test_src_files := \ InputChannel_test.cpp \ InputDispatcher_test.cpp \ @@ -43,3 +46,5 @@ $(foreach file,$(test_src_files), \ # Build the manual test programs. include $(call all-subdir-makefiles) + +endif
\ No newline at end of file diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk index f1b8cd5..b9f206a 100644 --- a/libs/utils/tests/Android.mk +++ b/libs/utils/tests/Android.mk @@ -2,6 +2,9 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) +ifneq ($(TARGET_SIMULATOR),true) + +# Build the unit tests. test_src_files := \ ObbFile_test.cpp \ PollLoop_test.cpp @@ -37,3 +40,5 @@ $(foreach file,$(test_src_files), \ $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ $(eval include $(BUILD_EXECUTABLE)) \ ) + +endif
\ No newline at end of file diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 6fe3c3b..653532c 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -40,7 +40,9 @@ else LOCAL_CFLAGS += -DNO_OPENCORE endif +ifneq ($(TARGET_SIMULATOR),true) LOCAL_STATIC_LIBRARIES := libmtp libusbhost +endif LOCAL_C_INCLUDES += \ external/tremor/Tremor \ diff --git a/media/jni/android_media_MtpClient.cpp b/media/jni/android_media_MtpClient.cpp index 5c397a6..f69053c 100644 --- a/media/jni/android_media_MtpClient.cpp +++ b/media/jni/android_media_MtpClient.cpp @@ -38,6 +38,8 @@ static jmethodID method_deviceAdded; static jmethodID method_deviceRemoved; static jfieldID field_context; +#ifdef HAVE_ANDROID_OS + static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { LOGE("An exception was thrown by callback '%s'.", methodName); @@ -94,52 +96,66 @@ void MyClient::deviceRemoved(MtpDevice *device) { checkAndClearExceptionFromCallback(env, __FUNCTION__); } +#endif // HAVE_ANDROID_OS + // ---------------------------------------------------------------------------- static void android_media_MtpClient_setup(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("setup\n"); MyClient* client = new MyClient(env, thiz); client->start(); env->SetIntField(thiz, field_context, (int)client); +#endif } static void android_media_MtpClient_finalize(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("finalize\n"); MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); client->cleanup(env); delete client; env->SetIntField(thiz, field_context, 0); +#endif } static jboolean android_media_MtpClient_start(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("start\n"); MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); return client->start(); +#else + return false; +#endif } static void android_media_MtpClient_stop(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("stop\n"); MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); client->stop(); +#endif } static jboolean android_media_MtpClient_delete_object(JNIEnv *env, jobject thiz, jint device_id, jint object_id) { +#ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); MtpDevice* device = client->getDevice(device_id); if (device) return device->deleteObject(object_id); else + #endif return NULL; } @@ -147,11 +163,13 @@ static jint android_media_MtpClient_get_parent(JNIEnv *env, jobject thiz, jint device_id, jint object_id) { +#ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); MtpDevice* device = client->getDevice(device_id); if (device) return device->getParent(object_id); else +#endif return -1; } @@ -159,11 +177,13 @@ static jint android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz, jint device_id, jint object_id) { + #ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); MtpDevice* device = client->getDevice(device_id); if (device) return device->getStorageID(object_id); else +#endif return -1; } diff --git a/media/jni/android_media_MtpCursor.cpp b/media/jni/android_media_MtpCursor.cpp index 470fa05..6228b5d 100644 --- a/media/jni/android_media_MtpCursor.cpp +++ b/media/jni/android_media_MtpCursor.cpp @@ -51,6 +51,7 @@ static void android_media_MtpCursor_setup(JNIEnv *env, jobject thiz, jobject javaClient, jint queryType, jint deviceID, jint storageID, jint objectID, jintArray javaColumns) { +#ifdef HAVE_ANDROID_OS LOGD("android_media_MtpCursor_setup queryType: %d deviceID: %d storageID: %d objectID: %d\n", queryType, deviceID, storageID, objectID); @@ -68,19 +69,23 @@ android_media_MtpCursor_setup(JNIEnv *env, jobject thiz, jobject javaClient, if (columns) env->ReleaseIntArrayElements(javaColumns, columns, 0); env->SetIntField(thiz, field_context, (int)cursor); +#endif } static void android_media_MtpCursor_finalize(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("finalize\n"); MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context); delete cursor; +#endif } static jint android_media_MtpCursor_fill_window(JNIEnv *env, jobject thiz, jobject javaWindow, jint startPos) { +#ifdef HAVE_ANDROID_OS CursorWindow* window = get_window_from_object(env, javaWindow); if (!window) { LOGE("Invalid CursorWindow"); @@ -91,6 +96,9 @@ android_media_MtpCursor_fill_window(JNIEnv *env, jobject thiz, jobject javaWindo MtpCursor *cursor = (MtpCursor *)env->GetIntField(thiz, field_context); return cursor->fillWindow(window, startPos); +#else + return 0; +#endif } // ---------------------------------------------------------------------------- diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp index 53e41e8..be59362 100644 --- a/media/jni/android_media_MtpDatabase.cpp +++ b/media/jni/android_media_MtpDatabase.cpp @@ -49,6 +49,7 @@ MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) { return (MtpDatabase *)env->GetIntField(database, field_context); } +#ifdef HAVE_ANDROID_OS // ---------------------------------------------------------------------------- class MyMtpDatabase : public MtpDatabase { @@ -368,26 +369,32 @@ static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodNa } } +#endif // HAVE_ANDROID_OS + // ---------------------------------------------------------------------------- static void android_media_MtpDatabase_setup(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("setup\n"); MyMtpDatabase* database = new MyMtpDatabase(env, thiz); env->SetIntField(thiz, field_context, (int)database); checkAndClearExceptionFromCallback(env, __FUNCTION__); +#endif } static void android_media_MtpDatabase_finalize(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("finalize\n"); MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context); database->cleanup(env); delete database; env->SetIntField(thiz, field_context, 0); checkAndClearExceptionFromCallback(env, __FUNCTION__); +#endif } // ---------------------------------------------------------------------------- diff --git a/media/jni/android_media_MtpServer.cpp b/media/jni/android_media_MtpServer.cpp index 0883527..eddad57 100644 --- a/media/jni/android_media_MtpServer.cpp +++ b/media/jni/android_media_MtpServer.cpp @@ -42,6 +42,8 @@ extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database); // ---------------------------------------------------------------------------- +#ifdef HAVE_ANDROID_OS + static bool ExceptionCheck(void* env) { return ((JNIEnv *)env)->ExceptionCheck(); @@ -111,9 +113,12 @@ public: } }; +#endif // HAVE_ANDROID_OS + static void android_media_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jstring storagePath) { +#ifdef HAVE_ANDROID_OS LOGD("setup\n"); MtpDatabase* database = getMtpDatabase(env, javaDatabase); @@ -123,6 +128,7 @@ android_media_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, j env->SetIntField(thiz, field_context, (int)thread); env->ReleaseStringUTFChars(storagePath, storagePathStr); +#endif } static void @@ -135,42 +141,50 @@ android_media_MtpServer_finalize(JNIEnv *env, jobject thiz) static void android_media_MtpServer_start(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("start\n"); MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); thread->run("MtpThread"); +#endif // HAVE_ANDROID_OS } static void android_media_MtpServer_stop(JNIEnv *env, jobject thiz) { +#ifdef HAVE_ANDROID_OS LOGD("stop\n"); MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); if (thread) { thread->setDone(); env->SetIntField(thiz, field_context, 0); } +#endif } static void android_media_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle) { +#ifdef HAVE_ANDROID_OS LOGD("send_object_added %d\n", handle); MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); if (thread) thread->sendObjectAdded(handle); else LOGE("sendObjectAdded called while disconnected\n"); +#endif } static void android_media_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle) { +#ifdef HAVE_ANDROID_OS LOGD("send_object_removed %d\n", handle); MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context); if (thread) thread->sendObjectRemoved(handle); else LOGE("sendObjectRemoved called while disconnected\n"); +#endif } // ---------------------------------------------------------------------------- diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp index 24426ff..ba98f04 100644 --- a/media/libmedia/MediaScanner.cpp +++ b/media/libmedia/MediaScanner.cpp @@ -81,13 +81,13 @@ status_t MediaScanner::processDirectory( } static bool fileMatchesExtension(const char* path, const char* extensions) { - char* extension = strrchr(path, '.'); + const char* extension = strrchr(path, '.'); if (!extension) return false; ++extension; // skip the dot if (extension[0] == 0) return false; while (extensions[0]) { - char* comma = strchr(extensions, ','); + const char* comma = strchr(extensions, ','); size_t length = (comma ? comma - extensions : strlen(extensions)); if (length == strlen(extension) && strncasecmp(extension, extensions, length) == 0) return true; extensions += length; diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 3beae7f..24b0e7b 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -381,12 +381,12 @@ status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) { return OK; } -// If interval < 0, only the first frame is I frame, and rest are all P frames -// If interval == 0, all frames are encoded as I frames. No P frames -// If interval > 0, it is the time spacing (seconds) between 2 neighboring I frames -status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t interval) { - LOGV("setParamVideoIFramesInterval: %d seconds", interval); - mIFramesInterval = interval; +// If seconds < 0, only the first frame is I frame, and rest are all P frames +// If seconds == 0, all frames are encoded as I frames. No P frames +// If seconds > 0, it is the time spacing (seconds) between 2 neighboring I frames +status_t StagefrightRecorder::setParamVideoIFramesInterval(int32_t seconds) { + LOGV("setParamVideoIFramesInterval: %d seconds", seconds); + mIFramesIntervalSec = seconds; return OK; } @@ -444,6 +444,44 @@ status_t StagefrightRecorder::setParamVideoEncoderLevel(int32_t level) { return OK; } +status_t StagefrightRecorder::setParamMovieTimeScale(int32_t timeScale) { + LOGV("setParamMovieTimeScale: %d", timeScale); + + // The range is set to be the same as the audio's time scale range + // since audio's time scale has a wider range. + if (timeScale < 600 || timeScale > 96000) { + LOGE("Time scale (%d) for movie is out of range [600, 96000]", timeScale); + return BAD_VALUE; + } + mMovieTimeScale = timeScale; + return OK; +} + +status_t StagefrightRecorder::setParamVideoTimeScale(int32_t timeScale) { + LOGV("setParamVideoTimeScale: %d", timeScale); + + // 60000 is chosen to make sure that each video frame from a 60-fps + // video has 1000 ticks. + if (timeScale < 600 || timeScale > 60000) { + LOGE("Time scale (%d) for video is out of range [600, 60000]", timeScale); + return BAD_VALUE; + } + mVideoTimeScale = timeScale; + return OK; +} + +status_t StagefrightRecorder::setParamAudioTimeScale(int32_t timeScale) { + LOGV("setParamAudioTimeScale: %d", timeScale); + + // 96000 Hz is the highest sampling rate support in AAC. + if (timeScale < 600 || timeScale > 96000) { + LOGE("Time scale (%d) for audio is out of range [600, 96000]", timeScale); + return BAD_VALUE; + } + mAudioTimeScale = timeScale; + return OK; +} + status_t StagefrightRecorder::setParameter( const String8 &key, const String8 &value) { LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string()); @@ -462,6 +500,11 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &durationUs)) { return setParamInterleaveDuration(durationUs); } + } else if (key == "param-movie-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamMovieTimeScale(timeScale); + } } else if (key == "param-use-64bit-offset") { int32_t use64BitOffset; if (safe_strtoi32(value.string(), &use64BitOffset)) { @@ -492,15 +535,20 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &audio_bitrate)) { return setParamAudioEncodingBitRate(audio_bitrate); } + } else if (key == "audio-param-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamAudioTimeScale(timeScale); + } } else if (key == "video-param-encoding-bitrate") { int32_t video_bitrate; if (safe_strtoi32(value.string(), &video_bitrate)) { return setParamVideoEncodingBitRate(video_bitrate); } } else if (key == "video-param-i-frames-interval") { - int32_t interval; - if (safe_strtoi32(value.string(), &interval)) { - return setParamVideoIFramesInterval(interval); + int32_t seconds; + if (safe_strtoi32(value.string(), &seconds)) { + return setParamVideoIFramesInterval(seconds); } } else if (key == "video-param-encoder-profile") { int32_t profile; @@ -517,6 +565,11 @@ status_t StagefrightRecorder::setParameter( if (safe_strtoi32(value.string(), &cameraId)) { return setParamVideoCameraId(cameraId); } + } else if (key == "video-param-time-scale") { + int32_t timeScale; + if (safe_strtoi32(value.string(), &timeScale)) { + return setParamVideoTimeScale(timeScale); + } } else { LOGE("setParameter: failed to find key %s", key.string()); } @@ -637,6 +690,7 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() { encMeta->setInt32(kKeyChannelCount, mAudioChannels); encMeta->setInt32(kKeySampleRate, mSampleRate); encMeta->setInt32(kKeyBitRate, mAudioBitRate); + encMeta->setInt32(kKeyTimeScale, mAudioTimeScale); OMXClient client; CHECK_EQ(client.connect(), OK); @@ -880,10 +934,11 @@ status_t StagefrightRecorder::setupVideoEncoder(const sp<MediaWriter>& writer) { enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyHeight, height); - enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval); + enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec); enc_meta->setInt32(kKeyStride, stride); enc_meta->setInt32(kKeySliceHeight, sliceHeight); enc_meta->setInt32(kKeyColorFormat, colorFormat); + enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale); if (mVideoEncoderProfile != -1) { enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile); } @@ -921,6 +976,7 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) { if (audioEncoder == NULL) { return UNKNOWN_ERROR; } + writer->addSource(audioEncoder); return OK; } @@ -957,6 +1013,7 @@ status_t StagefrightRecorder::startMPEG4Recording() { meta->setInt32(kKeyFileType, mOutputFormat); meta->setInt32(kKeyBitRate, totalBitRate); meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); + meta->setInt32(kKeyTimeScale, mMovieTimeScale); if (mTrackEveryNumberOfFrames > 0) { meta->setInt32(kKeyTrackFrameStatus, mTrackEveryNumberOfFrames); } @@ -1027,9 +1084,12 @@ status_t StagefrightRecorder::reset() { mAudioChannels = 1; mAudioBitRate = 12200; mInterleaveDurationUs = 0; - mIFramesInterval = 1; + mIFramesIntervalSec = 1; mAudioSourceNode = 0; mUse64BitFileOffset = false; + mMovieTimeScale = 1000; + mAudioTimeScale = 1000; + mVideoTimeScale = 1000; mCameraId = 0; mVideoEncoderProfile = -1; mVideoEncoderLevel = -1; @@ -1112,7 +1172,7 @@ status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const { result.append(buffer); snprintf(buffer, SIZE, " Encoder level: %d\n", mVideoEncoderLevel); result.append(buffer); - snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesInterval); + snprintf(buffer, SIZE, " I frames interval (s): %d\n", mIFramesIntervalSec); result.append(buffer); snprintf(buffer, SIZE, " Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight); result.append(buffer); diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 58f0031..f51d7f8 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -81,10 +81,13 @@ private: int32_t mAudioChannels; int32_t mSampleRate; int32_t mInterleaveDurationUs; - int32_t mIFramesInterval; + int32_t mIFramesIntervalSec; int32_t mCameraId; int32_t mVideoEncoderProfile; int32_t mVideoEncoderLevel; + int32_t mMovieTimeScale; + int32_t mVideoTimeScale; + int32_t mAudioTimeScale; int64_t mMaxFileSizeBytes; int64_t mMaxFileDurationUs; int32_t mTrackEveryNumberOfFrames; @@ -111,17 +114,20 @@ private: status_t setParamAudioEncodingBitRate(int32_t bitRate); status_t setParamAudioNumberOfChannels(int32_t channles); status_t setParamAudioSamplingRate(int32_t sampleRate); + status_t setParamAudioTimeScale(int32_t timeScale); status_t setParamVideoEncodingBitRate(int32_t bitRate); - status_t setParamVideoIFramesInterval(int32_t interval); + status_t setParamVideoIFramesInterval(int32_t seconds); status_t setParamVideoEncoderProfile(int32_t profile); status_t setParamVideoEncoderLevel(int32_t level); status_t setParamVideoCameraId(int32_t cameraId); + status_t setParamVideoTimeScale(int32_t timeScale); status_t setParamTrackTimeStatus(int64_t timeDurationUs); status_t setParamTrackFrameStatus(int32_t nFrames); status_t setParamInterleaveDuration(int32_t durationUs); status_t setParam64BitFileOffset(bool use64BitFileOffset); status_t setParamMaxFileDurationUs(int64_t timeUs); status_t setParamMaxFileSizeBytes(int64_t bytes); + status_t setParamMovieTimeScale(int32_t timeScale); void clipVideoBitRate(); void clipVideoFrameRate(); void clipVideoFrameWidth(); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 6a4a131..b7388bb 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -41,6 +41,7 @@ namespace android { class MPEG4Writer::Track { public: Track(MPEG4Writer *owner, const sp<MediaSource> &source); + ~Track(); status_t start(MetaData *params); @@ -61,12 +62,13 @@ private: volatile bool mResumed; int64_t mMaxTimeStampUs; int64_t mEstimatedTrackSizeBytes; + int32_t mTimeScale; pthread_t mThread; struct SampleInfo { size_t size; - int64_t timestamp; + int64_t timestampUs; }; List<SampleInfo> mSampleInfos; bool mSamplesHaveSameSize; @@ -92,11 +94,11 @@ private: struct SttsTableEntry { - SttsTableEntry(uint32_t count, uint32_t duration) - : sampleCount(count), sampleDuration(duration) {} + SttsTableEntry(uint32_t count, uint32_t durationUs) + : sampleCount(count), sampleDurationUs(durationUs) {} uint32_t sampleCount; - uint32_t sampleDuration; + uint32_t sampleDurationUs; }; List<SttsTableEntry> mSttsTableEntries; @@ -270,6 +272,13 @@ status_t MPEG4Writer::start(MetaData *param) { return OK; } + if (!param || + !param->findInt32(kKeyTimeScale, &mTimeScale)) { + mTimeScale = 1000; + } + CHECK(mTimeScale > 0); + LOGV("movie time scale: %d", mTimeScale); + mStreamableFile = true; mWriteMoovBoxToMemory = false; mMoovBoxBuffer = NULL; @@ -336,14 +345,14 @@ void MPEG4Writer::stop() { return; } - int64_t max_duration = 0; + int64_t maxDurationUs = 0; for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { (*it)->stop(); - int64_t duration = (*it)->getDurationUs(); - if (duration > max_duration) { - max_duration = duration; + int64_t durationUs = (*it)->getDurationUs(); + if (durationUs > maxDurationUs) { + maxDurationUs = durationUs; } } @@ -367,8 +376,7 @@ void MPEG4Writer::stop() { mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize); mMoovBoxBufferOffset = 0; CHECK(mMoovBoxBuffer != NULL); - int32_t timeScale = 1000; - int32_t duration = max_duration / timeScale; + int32_t duration = (maxDurationUs * mTimeScale) / 1E6; beginBox("moov"); @@ -376,7 +384,7 @@ void MPEG4Writer::stop() { writeInt32(0); // version=0, flags=0 writeInt32(now); // creation time writeInt32(now); // modification time - writeInt32(timeScale); // timescale + writeInt32(mTimeScale); // mvhd timescale writeInt32(duration); writeInt32(0x10000); // rate: 1.0 writeInt16(0x100); // volume @@ -655,7 +663,6 @@ void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { } int64_t MPEG4Writer::getStartTimestampUs() { - LOGI("getStartTimestampUs: %lld", mStartTimestampUs); Mutex::Autolock autoLock(mLock); return mStartTimestampUs; } @@ -683,6 +690,11 @@ MPEG4Writer::Track::Track( mGotAllCodecSpecificData(false), mReachedEOS(false) { getCodecSpecificDataFromInputFormatIfPossible(); + + if (!mMeta->findInt32(kKeyTimeScale, &mTimeScale)) { + mTimeScale = 1000; + } + CHECK(mTimeScale > 0); } void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { @@ -927,9 +939,9 @@ void MPEG4Writer::Track::threadEntry() { int64_t chunkTimestampUs = 0; int32_t nChunks = 0; int32_t nZeroLengthFrames = 0; - int64_t lastTimestamp = 0; // Timestamp of the previous sample - int64_t lastDuration = 0; // Time spacing between the previous two samples - int32_t sampleCount = 1; // Sample count in the current stts table entry + int64_t lastTimestampUs = 0; // Previous sample time stamp in ms + int64_t lastDurationUs = 0; // Between the previous two samples in ms + int32_t sampleCount = 1; // Sample count in the current stts table entry uint32_t previousSampleSize = 0; // Size of the previous sample int64_t previousPausedDurationUs = 0; sp<MetaData> meta_data; @@ -1113,7 +1125,7 @@ void MPEG4Writer::Track::threadEntry() { } if (mResumed) { - previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration); + previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - lastDurationUs); mResumed = false; } @@ -1124,12 +1136,11 @@ void MPEG4Writer::Track::threadEntry() { mMaxTimeStampUs = timestampUs; } - // Our timestamp is in ms. - info.timestamp = (timestampUs + 500) / 1000; + info.timestampUs = timestampUs; mSampleInfos.push_back(info); if (mSampleInfos.size() > 2) { - if (lastDuration != info.timestamp - lastTimestamp) { - SttsTableEntry sttsEntry(sampleCount, lastDuration); + if (lastDurationUs != info.timestampUs - lastTimestampUs) { + SttsTableEntry sttsEntry(sampleCount, lastDurationUs); mSttsTableEntries.push_back(sttsEntry); sampleCount = 1; } else { @@ -1142,8 +1153,8 @@ void MPEG4Writer::Track::threadEntry() { } previousSampleSize = info.size; } - lastDuration = info.timestamp - lastTimestamp; - lastTimestamp = info.timestamp; + lastDurationUs = info.timestampUs - lastTimestampUs; + lastTimestampUs = info.timestampUs; if (isSync != 0) { mStssTableEntries.push_back(mSampleInfos.size()); @@ -1213,11 +1224,11 @@ void MPEG4Writer::Track::threadEntry() { // there is no frame time after it, just repeat the previous // frame's duration. if (mSampleInfos.size() == 1) { - lastDuration = 0; // A single sample's duration + lastDurationUs = 0; // A single sample's duration } else { ++sampleCount; // Count for the last sample } - SttsTableEntry sttsEntry(sampleCount, lastDuration); + SttsTableEntry sttsEntry(sampleCount, lastDurationUs); mSttsTableEntries.push_back(sttsEntry); mReachedEOS = true; LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s", @@ -1249,12 +1260,13 @@ void MPEG4Writer::Track::trackProgressStatus(int32_t nFrames, int64_t timeUs) { void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs( int32_t *min, int32_t *avg, int32_t *max) { CHECK(!mSampleInfos.empty()); - int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000/ mSampleInfos.size(); + int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000 / mSampleInfos.size(); int32_t minSampleDurationMs = 0x7FFFFFFF; int32_t maxSampleDurationMs = 0; for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); it != mSttsTableEntries.end(); ++it) { - int32_t sampleDurationMs = static_cast<int32_t>(it->sampleDuration); + int32_t sampleDurationMs = + (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000; if (sampleDurationMs > maxSampleDurationMs) { maxSampleDurationMs = sampleDurationMs; } else if (sampleDurationMs < minSampleDurationMs) { @@ -1370,10 +1382,13 @@ void MPEG4Writer::Track::writeTrackHeader( CHECK(success); bool is_audio = !strncasecmp(mime, "audio/", 6); - int32_t timeScale = 1000; - int32_t duration = getDurationUs() / timeScale; + LOGV("%s track time scale: %d", + is_audio? "Audio": "Video", mTimeScale); + time_t now = time(NULL); + int32_t mvhdTimeScale = mOwner->getTimeScale(); + int64_t trakDurationUs = getDurationUs(); mOwner->beginBox("trak"); @@ -1385,7 +1400,9 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->writeInt32(now); // modification time mOwner->writeInt32(trackID); mOwner->writeInt32(0); // reserved - mOwner->writeInt32(duration); + int32_t tkhdDuration = + (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; + mOwner->writeInt32(tkhdDuration); // in mvhd timescale mOwner->writeInt32(0); // reserved mOwner->writeInt32(0); // reserved mOwner->writeInt16(0); // layer @@ -1423,12 +1440,17 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->beginBox("elst"); mOwner->writeInt32(0); // version=0, flags=0: 32-bit time mOwner->writeInt32(2); // never ends with an empty list - int64_t durationMs = - (mStartTimestampUs - moovStartTimeUs) / 1000; - mOwner->writeInt32(durationMs); // edit duration - mOwner->writeInt32(-1); // empty edit box to signal starting time offset - mOwner->writeInt32(1 << 16); // x1 rate - mOwner->writeInt32(duration); + + // First elst entry: specify the starting time offset + int64_t offsetUs = mStartTimestampUs - moovStartTimeUs; + int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6; + mOwner->writeInt32(seg); // in mvhd timecale + mOwner->writeInt32(-1); // starting time offset + mOwner->writeInt32(1 << 16); // rate = 1.0 + + // Second elst entry: specify the track duration + seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6; + mOwner->writeInt32(seg); // in mvhd timescale mOwner->writeInt32(0); mOwner->writeInt32(1 << 16); mOwner->endBox(); @@ -1441,8 +1463,9 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time - mOwner->writeInt32(timeScale); // timescale - mOwner->writeInt32(duration); // duration + mOwner->writeInt32(mTimeScale); // media timescale + int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; + mOwner->writeInt32(mdhdDuration); // use media timescale // Language follows the three letter standard ISO-639-2/T // 'e', 'n', 'g' for "English", for instance. // Each character is packed as the difference between its ASCII value and 0x60. @@ -1664,7 +1687,8 @@ void MPEG4Writer::Track::writeTrackHeader( for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin(); it != mSttsTableEntries.end(); ++it) { mOwner->writeInt32(it->sampleCount); - mOwner->writeInt32(it->sampleDuration); + int32_t dur = (it->sampleDurationUs * mTimeScale + 5E5) / 1E6; + mOwner->writeInt32(dur); } mOwner->endBox(); // stts @@ -1717,7 +1741,7 @@ void MPEG4Writer::Track::writeTrackHeader( mOwner->writeInt64((*it)); } } - mOwner->endBox(); // co64 + mOwner->endBox(); // stco or co64 mOwner->endBox(); // stbl mOwner->endBox(); // minf diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp index ab9285d..332bab3 100644 --- a/media/libstagefright/NuHTTPDataSource.cpp +++ b/media/libstagefright/NuHTTPDataSource.cpp @@ -42,7 +42,7 @@ static bool ParseURL( path->setTo(slashPos); } - char *colonPos = strchr(host->string(), ':'); + const char *colonPos = strchr(host->string(), ':'); if (colonPos != NULL) { unsigned long x; diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 077e123..157897b 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -3212,6 +3212,12 @@ void OMXCodec::dumpPortStatus(OMX_U32 portIndex) { void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { mOutputFormat = new MetaData; mOutputFormat->setCString(kKeyDecoderComponent, mComponentName); + if (mIsEncoder) { + int32_t timeScale; + if (inputFormat->findInt32(kKeyTimeScale, &timeScale)) { + mOutputFormat->setInt32(kKeyTimeScale, timeScale); + } + } OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index edd8648..17771c4 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -90,7 +90,7 @@ static bool MakeURL(const char *baseURL, const char *url, AString *out) { out->setTo(baseURL); out->append(url); } else { - char *slashPos = strrchr(baseURL, '/'); + const char *slashPos = strrchr(baseURL, '/'); if (slashPos > &baseURL[6]) { out->setTo(baseURL, slashPos - baseURL); diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index e9162c0..9826990 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -116,7 +116,7 @@ bool ARTSPConnection::ParseURL( path->setTo(slashPos); } - char *colonPos = strchr(host->c_str(), ':'); + const char *colonPos = strchr(host->c_str(), ':'); if (colonPos != NULL) { unsigned long x; diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp index ca4c55e..25b9ce2 100644 --- a/media/libstagefright/rtsp/ASessionDescription.cpp +++ b/media/libstagefright/rtsp/ASessionDescription.cpp @@ -164,7 +164,7 @@ void ASessionDescription::getFormatType( AString format; getFormat(index, &format); - char *lastSpacePos = strrchr(format.c_str(), ' '); + const char *lastSpacePos = strrchr(format.c_str(), ' '); CHECK(lastSpacePos != NULL); char *end; diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 74bb798..719ebf3 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -419,7 +419,7 @@ private: out->setTo(baseURL); out->append(url); } else { - char *slashPos = strrchr(baseURL, '/'); + const char *slashPos = strrchr(baseURL, '/'); if (slashPos > &baseURL[6]) { out->setTo(baseURL, slashPos - baseURL); diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index a92cea8..0559812 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -14,8 +14,8 @@ LOCAL_SHARED_LIBRARIES := \ base := $(LOCAL_PATH)/../.. LOCAL_C_INCLUDES := \ - $(base)/libs/audioflinger \ - $(base)/camera/libcameraservice \ + $(base)/services/audioflinger \ + $(base)/services/camera/libcameraservice \ $(base)/media/libmediaplayerservice LOCAL_MODULE:= mediaserver diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk index 4659709..40adf18 100644 --- a/media/mtp/Android.mk +++ b/media/mtp/Android.mk @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # + +ifneq ($(TARGET_SIMULATOR),true) + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -41,3 +44,5 @@ LOCAL_MODULE:= libmtp LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST include $(BUILD_STATIC_LIBRARY) + +endif diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp index 651761e..089278e 100644 --- a/media/mtp/MtpEventPacket.cpp +++ b/media/mtp/MtpEventPacket.cpp @@ -21,7 +21,7 @@ #include <fcntl.h> #include <sys/ioctl.h> -#include <f_mtp.h> +#include <linux/usb/f_mtp.h> #include "MtpEventPacket.h" diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index fda5f8f..163c05b 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -31,7 +31,7 @@ #include "MtpStorage.h" #include "MtpStringBuffer.h" -#include "f_mtp.h" +#include <linux/usb/f_mtp.h> namespace android { diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h deleted file mode 100644 index 426c6b5..0000000 --- a/media/mtp/f_mtp.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Gadget Function Driver for MTP - * - * Copyright (C) 2010 Google, Inc. - * Author: Mike Lockwood <lockwood@android.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef __LINUX_USB_F_MTP_H -#define __LINUX_USB_F_MTP_H - -/* Constants for MTP_SET_INTERFACE_MODE */ -#define MTP_INTERFACE_MODE_MTP 0 -#define MTP_INTERFACE_MODE_PTP 1 - - -struct mtp_file_range { - /* file descriptor for file to transfer */ - int fd; - /* offset in file for start of transfer */ - loff_t offset; - /* number of bytes to transfer */ - size_t length; -}; - -struct mtp_event { - /* size of the event */ - size_t length; - /* event data to send */ - void *data; -}; - -/* Sends the specified file range to the host */ -#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range) -/* Receives data from the host and writes it to a file. - * The file is created if it does not exist. - */ -#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range) -/* Sets the driver mode to either MTP or PTP */ -#define MTP_SET_INTERFACE_MODE _IOW('M', 2, int) -/* Sends an event to the host via the interrupt endpoint */ -#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event) - -#endif /* __LINUX_USB_F_MTP_H */ diff --git a/native/android/Android.mk b/native/android/Android.mk index 509a379..2fe0679 100644 --- a/native/android/Android.mk +++ b/native/android/Android.mk @@ -9,13 +9,15 @@ LOCAL_SRC_FILES:= \ input.cpp \ looper.cpp \ native_activity.cpp \ - native_window.cpp + native_window.cpp \ + sensor.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libbinder \ libui \ + libgui \ libsurfaceflinger_client \ libandroid_runtime diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp new file mode 100644 index 0000000..7a3907e --- /dev/null +++ b/native/android/sensor.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "sensor" +#include <utils/Log.h> + +#include <android/looper.h> +#include <android/sensor.h> + +#include <utils/RefBase.h> +#include <utils/PollLoop.h> +#include <utils/Timers.h> + +#include <gui/Sensor.h> +#include <gui/SensorManager.h> +#include <gui/SensorEventQueue.h> + +#include <poll.h> + +using android::sp; +using android::Sensor; +using android::SensorManager; +using android::SensorEventQueue; +using android::String8; + +/*****************************************************************************/ + +ASensorManager* ASensorManager_getInstance() +{ + return &SensorManager::getInstance(); +} + +int ASensorManager_getSensorList(ASensorManager* manager, ASensor** list) +{ + Sensor* l; + int c = static_cast<SensorManager*>(manager)->getSensorList(&l); + if (list) { + *list = l; + } + return c; +} + +ASensor* ASensorManager_getDefaultSensor(ASensorManager* manager, int type) +{ + return static_cast<SensorManager*>(manager)->getDefaultSensor(type); +} + +ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager, + ALooper* looper, ALooper_callbackFunc* callback, void* data) +{ + sp<SensorEventQueue> queue = + static_cast<SensorManager*>(manager)->createEventQueue(); + if (queue != 0) { + ALooper_addFd(looper, queue->getFd(), POLLIN, callback, data); + queue->looper = looper; + queue->incStrong(manager); + } + return static_cast<ASensorEventQueue*>(queue.get()); +} + +int ASensorManager_destroyEventQueue(ASensorManager* manager, + ASensorEventQueue* inQueue) +{ + sp<SensorEventQueue> queue = static_cast<SensorEventQueue*>(inQueue); + ALooper_removeFd(queue->looper, queue->getFd()); + queue->decStrong(manager); + return 0; +} + +/*****************************************************************************/ + +int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor* sensor) +{ + return static_cast<SensorEventQueue*>(queue)->enableSensor( + static_cast<Sensor*>(sensor)); +} + +int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor* sensor) +{ + return static_cast<SensorEventQueue*>(queue)->disableSensor( + static_cast<Sensor*>(sensor)); +} + +int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor* sensor, + int32_t usec) +{ + return static_cast<SensorEventQueue*>(queue)->setEventRate( + static_cast<Sensor*>(sensor), us2ns(usec)); +} + +int ASensorEventQueue_hasEvents(ASensorEventQueue* queue) +{ + struct pollfd pfd; + pfd.fd = static_cast<SensorEventQueue*>(queue)->getFd(); + pfd.events = POLLIN; + pfd.revents = 0; + + int nfd = poll(&pfd, 1, 0); + + if (nfd < 0) + return -errno; + + if (pfd.revents != POLLIN) + return -1; + + return (nfd == 0) ? 0 : 1; +} + +ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, + ASensorEvent* events, size_t count) +{ + return static_cast<SensorEventQueue*>(queue)->read(events, count); +} + + +/*****************************************************************************/ + +const char* ASensor_getName(ASensor* sensor) +{ + return static_cast<Sensor*>(sensor)->getName().string(); +} + +const char* ASensor_getVendor(ASensor* sensor) +{ + return static_cast<Sensor*>(sensor)->getVendor().string(); +} + +int ASensor_getType(ASensor* sensor) +{ + return static_cast<Sensor*>(sensor)->getType(); +} + +float ASensor_getResolution(ASensor* sensor) +{ + return static_cast<Sensor*>(sensor)->getResolution(); +} + diff --git a/native/glue/threaded_app/Android.mk b/native/glue/threaded_app/Android.mk deleted file mode 100644 index cfc9b2a..0000000 --- a/native/glue/threaded_app/Android.mk +++ /dev/null @@ -1,18 +0,0 @@ -BASE_PATH := $(call my-dir) -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -# our source files -# -LOCAL_SRC_FILES:= \ - threaded_app.c - -LOCAL_C_INCLUDES += \ - frameworks/base/native/include \ - frameworks/base/core/jni/android \ - dalvik/libnativehelper/include/nativehelper - -LOCAL_MODULE:= libthreaded_app - -include $(BUILD_STATIC_LIBRARY) diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c deleted file mode 100644 index 452c735..0000000 --- a/native/glue/threaded_app/threaded_app.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include <jni.h> - -#include <errno.h> -#include <fcntl.h> -#include <string.h> -#include <unistd.h> -#include <sys/resource.h> - -#include <android_glue/threaded_app.h> - -#include <android/log.h> - -#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) -#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__)) - -int8_t android_app_read_cmd(struct android_app* android_app) { - int8_t cmd; - if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { - return cmd; - } else { - LOGW("No data on command pipe!"); - } - return -1; -} - -int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd) { - switch (cmd) { - case APP_CMD_INPUT_CHANGED: - LOGI("APP_CMD_INPUT_CHANGED\n"); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) { - AInputQueue_detachLooper(android_app->inputQueue); - } - android_app->inputQueue = android_app->pendingInputQueue; - if (android_app->inputQueue != NULL) { - LOGI("Attaching input queue to looper"); - AInputQueue_attachLooper(android_app->inputQueue, - android_app->looper, NULL, (void*)LOOPER_ID_EVENT); - } - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_WINDOW_CHANGED: - LOGI("APP_CMD_WINDOW_CHANGED\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = android_app->pendingWindow; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_START: - case APP_CMD_RESUME: - case APP_CMD_PAUSE: - case APP_CMD_STOP: - LOGI("activityState=%d\n", cmd); - pthread_mutex_lock(&android_app->mutex); - android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_WINDOW_REDRAW_NEEDED: - LOGI("APP_CMD_WINDOW_REDRAW_NEEDED\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->redrawNeeded = 0; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_CONTENT_RECT_CHANGED: - LOGI("APP_CMD_CONTENT_RECT_CHANGED\n"); - android_app->contentRect = android_app->pendingContentRect; - break; - - case APP_CMD_DESTROY: - LOGI("APP_CMD_DESTROY\n"); - android_app->destroyRequested = 1; - break; - } - - return android_app->destroyRequested ? 0 : 1; -} - -static void android_app_destroy(struct android_app* android_app) { - LOGI("android_app_destroy!"); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) { - AInputQueue_detachLooper(android_app->inputQueue); - } - android_app->destroyed = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - // Can't touch android_app object after this. -} - -static void* android_app_entry(void* param) { - struct android_app* android_app = (struct android_app*)param; - - ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, (void*)LOOPER_ID_MAIN); - android_app->looper = looper; - - pthread_mutex_lock(&android_app->mutex); - android_app->running = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - - android_main(android_app); - - android_app_destroy(android_app); - return NULL; -} - -// -------------------------------------------------------------------- -// Native activity interaction (called from main thread) -// -------------------------------------------------------------------- - -static struct android_app* android_app_create(ANativeActivity* activity) { - struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); - memset(android_app, 0, sizeof(struct android_app)); - android_app->activity = activity; - - pthread_mutex_init(&android_app->mutex, NULL); - pthread_cond_init(&android_app->cond, NULL); - - int msgpipe[2]; - if (pipe(msgpipe)) { - LOGI("could not create pipe: %s", strerror(errno)); - } - android_app->msgread = msgpipe[0]; - android_app->msgwrite = msgpipe[1]; - int result = fcntl(android_app->msgread, F_SETFL, O_NONBLOCK); - if (result != 0) LOGW("Could not make message read pipe " - "non-blocking: %s", strerror(errno)); - result = fcntl(android_app->msgwrite, F_SETFL, O_NONBLOCK); - if (result != 0) LOGW("Could not make message write pipe " - "non-blocking: %s", strerror(errno)); - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&android_app->thread, &attr, android_app_entry, android_app); - - // Wait for thread to start. - pthread_mutex_lock(&android_app->mutex); - while (!android_app->running) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); - - return android_app; -} - -static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { - if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { - LOGI("Failure writing android_app cmd: %s\n", strerror(errno)); - } -} - -static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { - pthread_mutex_lock(&android_app->mutex); - android_app->pendingInputQueue = inputQueue; - android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); - while (android_app->inputQueue != android_app->pendingInputQueue) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { - pthread_mutex_lock(&android_app->mutex); - android_app->pendingWindow = window; - android_app_write_cmd(android_app, APP_CMD_WINDOW_CHANGED); - while (android_app->window != android_app->pendingWindow) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, cmd); - while (android_app->activityState != cmd) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_wait_redraw(struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); - android_app->redrawNeeded = 1; - android_app_write_cmd(android_app, APP_CMD_WINDOW_REDRAW_NEEDED); - while (android_app->redrawNeeded) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_content_rect(struct android_app* android_app, const ARect* rect) { - pthread_mutex_lock(&android_app->mutex); - android_app->pendingContentRect = *rect; - android_app_write_cmd(android_app, APP_CMD_CONTENT_RECT_CHANGED); - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_free(struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, APP_CMD_DESTROY); - while (!android_app->destroyed) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); - - close(android_app->msgread); - close(android_app->msgwrite); - pthread_cond_destroy(&android_app->cond); - pthread_mutex_destroy(&android_app->mutex); - free(android_app); -} - -static void onDestroy(ANativeActivity* activity) { - LOGI("Destroy: %p\n", activity); - android_app_free((struct android_app*)activity->instance); -} - -static void onStart(ANativeActivity* activity) { - LOGI("Start: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); -} - -static void onResume(ANativeActivity* activity) { - LOGI("Resume: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); -} - -static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { - LOGI("SaveInstanceState: %p\n", activity); - return NULL; -} - -static void onPause(ANativeActivity* activity) { - LOGI("Pause: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); -} - -static void onStop(ANativeActivity* activity) { - LOGI("Stop: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); -} - -static void onLowMemory(ANativeActivity* activity) { - LOGI("LowMemory: %p\n", activity); - android_app_write_cmd((struct android_app*)activity->instance, - APP_CMD_LOW_MEMORY); -} - -static void onWindowFocusChanged(ANativeActivity* activity, int focused) { - LOGI("WindowFocusChanged: %p -- %d\n", activity, focused); - android_app_write_cmd((struct android_app*)activity->instance, - focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); -} - -static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { - LOGI("NativeWindowCreated: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, window); -} - -static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) { - LOGI("NativeWindowResized: %p -- %p\n", activity, window); - android_app_write_cmd((struct android_app*)activity->instance, - APP_CMD_WINDOW_RESIZED); -} - -static void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window) { - LOGI("NativeWindowRedrawNeeded: %p -- %p\n", activity, window); - android_app_wait_redraw((struct android_app*)activity->instance); -} - -static void onContentRectChanged(ANativeActivity* activity, const ARect* rect) { - LOGI("ContentRectChanged: %p -- (%d,%d)-(%d,%d)\n", activity, rect->left, - rect->top, rect->right, rect->bottom); - android_app_set_content_rect((struct android_app*)activity->instance, rect); -} - -static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { - LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, NULL); -} - -static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { - LOGI("InputQueueCreated: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, queue); -} - -static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { - LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, NULL); -} - -void ANativeActivity_onCreate(ANativeActivity* activity, - void* savedState, size_t savedStateSize) { - LOGI("Creating: %p\n", activity); - activity->callbacks->onDestroy = onDestroy; - activity->callbacks->onStart = onStart; - activity->callbacks->onResume = onResume; - activity->callbacks->onSaveInstanceState = onSaveInstanceState; - activity->callbacks->onPause = onPause; - activity->callbacks->onStop = onStop; - activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; - activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; - activity->callbacks->onNativeWindowResized = onNativeWindowResized; - activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded; - activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; - activity->callbacks->onInputQueueCreated = onInputQueueCreated; - activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; - activity->callbacks->onContentRectChanged = onContentRectChanged; - activity->callbacks->onLowMemory = onLowMemory; - - activity->instance = android_app_create(activity); -} diff --git a/native/include/android/tts.h b/native/include/android/tts.h index e5c99f7..fb15108 100644 --- a/native/include/android/tts.h +++ b/native/include/android/tts.h @@ -87,6 +87,11 @@ typedef struct { */ extern android_tts_engine_t *android_getTtsEngine(); +/* Including the old version for legacy support (Froyo compatibility). + * This should return the same thing as android_getTtsEngine. + */ +extern "C" android_tts_engine_t *getTtsEngine(); + // A callback type used to notify the framework of new synthetized // audio samples, status will be SYNTH_DONE for the last sample of // the last request, of SYNTH_PENDING otherwise. diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h deleted file mode 100644 index 2b58e9c..0000000 --- a/native/include/android_glue/threaded_app.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include <poll.h> -#include <pthread.h> -#include <sched.h> - -#include <android/native_activity.h> -#include <android/looper.h> - -/** - * This is the interface for the standard glue code of a threaded - * application. In this model, the application's code is running - * in its own thread separate from the main thread of the process. - * It is not required that this thread be associated with the Java - * VM, although it will need to be in order to make JNI calls any - * Java objects. - */ -struct android_app { - // The application can place a pointer to its own state object - // here if it likes. - void* userData; - - // The ANativeActivity object instance that this app is running in. - ANativeActivity* activity; - - // The ALooper associated with the app's thread. - ALooper* looper; - - // When non-NULL, this is the input queue from which the app will - // receive user input events. - AInputQueue* inputQueue; - - // When non-NULL, this is the window surface that the app can draw in. - ANativeWindow* window; - - // Current content rectangle of the window; this is the area where the - // window's content should be placed to be seen by the user. - ARect contentRect; - - // Current state of the app's activity. May be either APP_CMD_START, - // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. - int activityState; - - // ------------------------------------------------- - // Below are "private" implementation of the glue code. - - pthread_mutex_t mutex; - pthread_cond_t cond; - - int msgread; - int msgwrite; - - pthread_t thread; - - // This is non-zero when the application's NativeActivity is being - // destroyed and waiting for the app thread to complete. - int destroyRequested; - - int running; - int destroyed; - int redrawNeeded; - AInputQueue* pendingInputQueue; - ANativeWindow* pendingWindow; - ARect pendingContentRect; -}; - -enum { - /** - * Looper data ID of commands coming from the app's main thread. - * These can be retrieved and processed with android_app_read_cmd() - * and android_app_exec_cmd(). - */ - LOOPER_ID_MAIN = 1, - - /** - * Looper data ID of events coming from the AInputQueue of the - * application's window. These can be read via the inputQueue - * object of android_app. - */ - LOOPER_ID_EVENT = 2 -}; - -enum { - /** - * Command from main thread: the AInputQueue has changed. Upon processing - * this command, android_app->inputQueue will be updated to the new queue - * (or NULL). - */ - APP_CMD_INPUT_CHANGED, - - /** - * Command from main thread: the ANativeWindow has changed. Upon processing - * this command, android_app->window will be updated to the new window surface - * (or NULL). - */ - APP_CMD_WINDOW_CHANGED, - - /** - * Command from main thread: the current ANativeWindow has been resized. - * Please redraw with its new size. - */ - APP_CMD_WINDOW_RESIZED, - - /** - * Command from main thread: the system needs that the current ANativeWindow - * be redrawn. You should redraw the window before handing this to - * android_app_exec_cmd() in order to avoid transient drawing glitches. - */ - APP_CMD_WINDOW_REDRAW_NEEDED, - - /** - * Command from main thread: the content area of the window has changed, - * such as from the soft input window being shown or hidden. You can - * find the new content rect in android_app::contentRect. - */ - APP_CMD_CONTENT_RECT_CHANGED, - - /** - * Command from main thread: the app's activity window has gained - * input focus. - */ - APP_CMD_GAINED_FOCUS, - - /** - * Command from main thread: the app's activity window has lost - * input focus. - */ - APP_CMD_LOST_FOCUS, - - /** - * Command from main thread: the system is running low on memory. - * Try to reduce your memory use. - */ - APP_CMD_LOW_MEMORY, - - /** - * Command from main thread: the app's activity has been started. - */ - APP_CMD_START, - - /** - * Command from main thread: the app's activity has been resumed. - */ - APP_CMD_RESUME, - - /** - * Command from main thread: the app's activity has been paused. - */ - APP_CMD_PAUSE, - - /** - * Command from main thread: the app's activity has been stopped. - */ - APP_CMD_STOP, - - /** - * Command from main thread: the app's activity is being destroyed, - * and waiting for the app thread to clean up and exit before proceeding. - */ - APP_CMD_DESTROY, -}; - -/** - * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next - * app command message. - */ -int8_t android_app_read_cmd(struct android_app* android_app); - -/** - * Call with the command returned by android_app_read_cmd() to do the - * default processing of the given command. - * - * Important: returns 0 if the app should exit. You must ALWAYS check for - * a zero return and, if found, exit your android_main() function. - */ -int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd); - -/** - * This is the function that application code must implement, representing - * the main entry to the app. - */ -extern void android_main(struct android_app* app); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 75045d7..6d77a3a 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -12,7 +12,12 @@ android:icon="@drawable/ic_launcher_settings"> <service - android:name=".statusbar.StatusBarService" + android:name=".statusbar.PhoneStatusBarService" + android:exported="false" + /> + + <service + android:name=".statusbar.tablet.TabletStatusBarService" android:exported="false" /> diff --git a/packages/SystemUI/res/drawable/notification_dragger.png b/packages/SystemUI/res/drawable/notification_dragger.png Binary files differnew file mode 100644 index 0000000..fad1f32 --- /dev/null +++ b/packages/SystemUI/res/drawable/notification_dragger.png diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml new file mode 100644 index 0000000..1e93bee --- /dev/null +++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* apps/common/assets/default/default/skins/StatusBar.xml +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- android:background="@drawable/status_bar_closed_default_background" --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" + android:background="@drawable/status_bar_background" + android:orientation="vertical" + android:focusable="true" + android:descendantFocusability="afterDescendants" + > + + <RelativeLayout android:id="@+id/icons" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal"> + +<!-- + <LinearLayout android:id="@+id/statusIcons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_alignParentRight="true" + android:paddingRight="6dip" + android:gravity="center_vertical" + android:orientation="horizontal"/> +--> + + <com.android.systemui.statusbar.tablet.NotificationIconArea + android:id="@+id/notificationIcons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_alignParentLeft="true" + android:layout_marginLeft="10dp" + android:paddingLeft="6dip" + android:gravity="center_vertical" + android:orientation="horizontal" + /> + + <RelativeLayout android:id="@+id/icons" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerInParent="true" + > + + <com.android.systemui.statusbar.Clock + android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerHorizontal="true" + android:singleLine="true" + android:textSize="16sp" + android:textStyle="bold" + /> + </RelativeLayout> + + <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back" + android:layout_width="wrap_content" + android:layout_height="@*android:dimen/status_bar_height" + android:layout_toLeftOf="@+id/menu" + android:layout_marginRight="10dp" + android:src="@drawable/status_bar_back" + systemui:keyCode="4" + /> + <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu" + android:layout_width="wrap_content" + android:layout_height="@*android:dimen/status_bar_height" + android:layout_toLeftOf="@+id/home" + android:src="@drawable/status_bar_menu" + android:layout_marginRight="10dp" + systemui:keyCode="82" + /> + <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home" + android:layout_width="wrap_content" + android:layout_height="@*android:dimen/status_bar_height" + android:layout_alignParentRight="true" + android:layout_marginRight="10dp" + android:src="@drawable/status_bar_home" + systemui:keyCode="3" + /> + + </RelativeLayout> +<!-- + + <LinearLayout android:id="@+id/ticker" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="6dip" + android:animationCache="false" + android:orientation="horizontal" > + <ImageSwitcher android:id="@+id/tickerIcon" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_marginRight="8dip" + > + <com.android.systemui.statusbar.AnimatedImageView + android:layout_width="25dip" + android:layout_height="25dip" + /> + <com.android.systemui.statusbar.AnimatedImageView + android:layout_width="25dip" + android:layout_height="25dip" + /> + </ImageSwitcher> + <com.android.systemui.statusbar.TickerView android:id="@+id/tickerText" + android:layout_width="0dip" + android:layout_weight="1" + android:layout_height="wrap_content" + android:paddingTop="2dip" + android:paddingRight="10dip"> + <TextView + android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + /> + <TextView + android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + /> + </com.android.systemui.statusbar.TickerView> + </LinearLayout> + + <com.android.systemui.statusbar.DateView android:id="@+id/date" + android:textAppearance="@*android:style/TextAppearance.StatusBar.Icon" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:singleLine="true" + android:gravity="center_vertical|left" + android:paddingLeft="6px" + android:paddingRight="6px" + android:background="@drawable/status_bar_background" + /> +--> +</FrameLayout> + diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 4667149..2f1b36e 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -60,33 +60,6 @@ android:textStyle="bold" android:gravity="center_vertical|left" /> - - <LinearLayout android:id="@+id/buttons" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:paddingLeft="6dip" - android:orientation="horizontal" > - - <com.android.systemui.statusbar.KeyButtonView android:id="@+id/back" - android:layout_width="wrap_content" - android:layout_height="@*android:dimen/status_bar_height" - android:src="@drawable/status_bar_back" - systemui:keyCode="4" - /> - <com.android.systemui.statusbar.KeyButtonView android:id="@+id/menu" - android:layout_width="wrap_content" - android:layout_height="@*android:dimen/status_bar_height" - android:src="@drawable/status_bar_menu" - systemui:keyCode="82" - /> - <com.android.systemui.statusbar.KeyButtonView android:id="@+id/home" - android:layout_width="wrap_content" - android:layout_height="@*android:dimen/status_bar_height" - android:src="@drawable/status_bar_home" - systemui:keyCode="3" - /> - </LinearLayout> - </LinearLayout> <LinearLayout android:id="@+id/ticker" diff --git a/packages/SystemUI/res/layout/unused.xml b/packages/SystemUI/res/layout/unused.xml deleted file mode 100644 index 05a7d7d..0000000 --- a/packages/SystemUI/res/layout/unused.xml +++ /dev/null @@ -1,4 +0,0 @@ -<Unused - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/buttons"> -</Unused> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java index f45caf5..0f6723e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CloseDragHandle.java @@ -23,7 +23,7 @@ import android.widget.LinearLayout; public class CloseDragHandle extends LinearLayout { - StatusBarService mService; + PhoneStatusBarService mService; public CloseDragHandle(Context context, AttributeSet attrs) { super(context, attrs); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index f9347b1..2c0af65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -32,7 +32,7 @@ import com.android.internal.statusbar.StatusBarNotification; * coalescing these calls so they don't stack up. For the calls * are coalesced, note that they are all idempotent. */ -class CommandQueue extends IStatusBar.Stub { +public class CommandQueue extends IStatusBar.Stub { private static final String TAG = "StatusBar.CommandQueue"; private static final int MSG_MASK = 0xffff0000; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java index 3d85f27..a2d4b95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandedView.java @@ -27,7 +27,7 @@ import android.util.Slog; public class ExpandedView extends LinearLayout { - StatusBarService mService; + PhoneStatusBarService mService; int mPrevHeight = -1; public ExpandedView(Context context, AttributeSet attrs) { @@ -53,7 +53,7 @@ public class ExpandedView extends LinearLayout { //Slog.d(StatusBarService.TAG, "height changed old=" + mPrevHeight // + " new=" + height); mPrevHeight = height; - mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE); + mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java new file mode 100644 index 0000000..eff9a1d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java @@ -0,0 +1,1552 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar; + +import android.app.Service; +import android.app.ActivityManagerNative; +import android.app.Dialog; +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.app.StatusBarManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.Binder; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.util.Slog; +import android.util.Log; +import android.view.Display; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.view.WindowManagerImpl; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RemoteViews; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.FrameLayout; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; + +import com.android.internal.statusbar.IStatusBar; +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.statusbar.StatusBarIconList; +import com.android.internal.statusbar.StatusBarNotification; + +import com.android.systemui.R; +import com.android.systemui.statusbar.policy.StatusBarPolicy; + + + +public class PhoneStatusBarService extends StatusBarService { + static final String TAG = "PhoneStatusBarService"; + static final boolean SPEW = false; + + public static final String ACTION_STATUSBAR_START + = "com.android.internal.policy.statusbar.START"; + + static final int EXPANDED_LEAVE_ALONE = -10000; + static final int EXPANDED_FULL_OPEN = -10001; + + private static final int MSG_ANIMATE = 1000; + private static final int MSG_ANIMATE_REVEAL = 1001; + private static final int MSG_SHOW_INTRUDER = 1002; + private static final int MSG_HIDE_INTRUDER = 1003; + + // will likely move to a resource or other tunable param at some point + private static final int INTRUDER_ALERT_DECAY_MS = 10000; + + StatusBarPolicy mIconPolicy; + + int mIconSize; + Display mDisplay; + + StatusBarView mStatusBarView; + int mPixelFormat; + H mHandler = new H(); + Object mQueueLock = new Object(); + + // icons + LinearLayout mIcons; + IconMerger mNotificationIcons; + LinearLayout mStatusIcons; + + // expanded notifications + Dialog mExpandedDialog; + ExpandedView mExpandedView; + WindowManager.LayoutParams mExpandedParams; + ScrollView mScrollView; + View mNotificationLinearLayout; + View mExpandedContents; + // top bar + TextView mNoNotificationsTitle; + TextView mClearButton; + // drag bar + CloseDragHandle mCloseView; + // ongoing + NotificationData mOngoing = new NotificationData(); + TextView mOngoingTitle; + LinearLayout mOngoingItems; + // latest + NotificationData mLatest = new NotificationData(); + TextView mLatestTitle; + LinearLayout mLatestItems; + // position + int[] mPositionTmp = new int[2]; + boolean mExpanded; + boolean mExpandedVisible; + + // the date view + DateView mDateView; + + // for immersive activities + private View mIntruderAlertView; + + // the tracker view + TrackingView mTrackingView; + WindowManager.LayoutParams mTrackingParams; + int mTrackingPosition; // the position of the top of the tracking view. + private boolean mPanelSlightlyVisible; + + // ticker + private Ticker mTicker; + private View mTickerView; + private boolean mTicking; + + // Tracking finger for opening/closing. + int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore + boolean mTracking; + VelocityTracker mVelocityTracker; + + static final int ANIM_FRAME_DURATION = (1000/60); + + boolean mAnimating; + long mCurAnimationTime; + float mDisplayHeight; + float mAnimY; + float mAnimVel; + float mAnimAccel; + long mAnimLastTime; + boolean mAnimatingReveal = false; + int mViewDelta; + int[] mAbsPos = new int[2]; + + // for disabling the status bar + int mDisabled = 0; + + private class ExpandedDialog extends Dialog { + ExpandedDialog(Context context) { + super(context, com.android.internal.R.style.Theme_Light_NoTitleBar); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + boolean down = event.getAction() == KeyEvent.ACTION_DOWN; + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_BACK: + if (!down) { + animateCollapse(); + } + return true; + } + return super.dispatchKeyEvent(event); + } + } + + @Override + public void onCreate() { + mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + + super.onCreate(); + + addIntruderView(); + + // Lastly, call to the icon policy to install/update all the icons. + mIconPolicy = new StatusBarPolicy(this); + } + + @Override + public void onDestroy() { + // we're never destroyed + } + + // ================================================================================ + // Constructing the view + // ================================================================================ + protected View makeStatusBarView() { + final Context context = this; + + Resources res = context.getResources(); + + mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); + + ExpandedView expanded = (ExpandedView)View.inflate(context, + R.layout.status_bar_expanded, null); + expanded.mService = this; + + mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null); + mIntruderAlertView.setVisibility(View.GONE); + mIntruderAlertView.setClickable(true); + + StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null); + sb.mService = this; + + // figure out which pixel-format to use for the status bar. + mPixelFormat = PixelFormat.TRANSLUCENT; + Drawable bg = sb.getBackground(); + if (bg != null) { + mPixelFormat = bg.getOpacity(); + } + + mStatusBarView = sb; + mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons); + mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons); + mIcons = (LinearLayout)sb.findViewById(R.id.icons); + mTickerView = sb.findViewById(R.id.ticker); + mDateView = (DateView)sb.findViewById(R.id.date); + + mExpandedDialog = new ExpandedDialog(context); + mExpandedView = expanded; + mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout); + mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle); + mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems); + mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle); + mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems); + mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle); + mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button); + mClearButton.setOnClickListener(mClearButtonListener); + mScrollView = (ScrollView)expanded.findViewById(R.id.scroll); + mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout); + + mOngoingTitle.setVisibility(View.GONE); + mLatestTitle.setVisibility(View.GONE); + + mTicker = new MyTicker(context, sb); + + TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText); + tickerView.mTicker = mTicker; + + mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null); + mTrackingView.mService = this; + mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close); + mCloseView.mService = this; + + mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); + + // the more notifications icon + StatusBarIconView moreView = new StatusBarIconView(this, "more"); + moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0)); + mNotificationIcons.addMoreView(moreView, + new LinearLayout.LayoutParams(mIconSize, mIconSize)); + + // set the inital view visibility + setAreThereNotifications(); + mDateView.setVisibility(View.INVISIBLE); + + // receive broadcasts + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + filter.addAction(Intent.ACTION_SCREEN_OFF); + context.registerReceiver(mBroadcastReceiver, filter); + + return sb; + } + + protected int getStatusBarGravity() { + return Gravity.TOP | Gravity.FILL_HORIZONTAL; + } + + private void addIntruderView() { + final Resources res = getResources(); + final int height= res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); + + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + PixelFormat.TRANSLUCENT); + lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; + lp.y += height * 1.5; // FIXME + lp.setTitle("IntruderAlert"); + lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert; + + WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp); + } + + public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { + if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex + + " icon=" + icon); + StatusBarIconView view = new StatusBarIconView(this, slot); + view.set(icon); + mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); + } + + public void updateIcon(String slot, int index, int viewIndex, + StatusBarIcon old, StatusBarIcon icon) { + if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex + + " old=" + old + " icon=" + icon); + StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex); + view.set(icon); + } + + public void removeIcon(String slot, int index, int viewIndex) { + if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); + mStatusIcons.removeViewAt(viewIndex); + } + + public void addNotification(IBinder key, StatusBarNotification notification) { + StatusBarIconView iconView = addNotificationViews(key, notification); + if (iconView == null) return; + + boolean immersive = false; + try { + immersive = ActivityManagerNative.getDefault().isTopActivityImmersive(); + Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive")); + } catch (RemoteException ex) { + } + if (immersive) { + if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) { + Slog.d(TAG, "Presenting high-priority notification in immersive activity"); + // @@@ special new transient ticker mode + // 1. Populate mIntruderAlertView + + ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon); + TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText); + alertIcon.setImageDrawable(StatusBarIconView.getIcon( + alertIcon.getContext(), + iconView.getStatusBarIcon())); + alertText.setText(notification.notification.tickerText); + + View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content); + button.setOnClickListener( + new Launcher(notification.notification.contentIntent, + notification.pkg, notification.tag, notification.id)); + + // 2. Animate mIntruderAlertView in + mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER); + + // 3. Set alarm to age the notification off (TODO) + mHandler.removeMessages(MSG_HIDE_INTRUDER); + mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS); + } + } else if (notification.notification.fullScreenIntent != null) { + // not immersive & a full-screen alert should be shown + Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;" + + " sending fullScreenIntent"); + try { + notification.notification.fullScreenIntent.send(); + } catch (PendingIntent.CanceledException e) { + } + } else { + // usual case: status bar visible & not immersive + + // show the ticker + tick(notification); + } + + // Recalculate the position of the sliding windows and the titles. + setAreThereNotifications(); + updateExpandedViewPos(EXPANDED_LEAVE_ALONE); + } + + public void updateNotification(IBinder key, StatusBarNotification notification) { + Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification); + + NotificationData oldList; + int oldIndex = mOngoing.findEntry(key); + if (oldIndex >= 0) { + oldList = mOngoing; + } else { + oldIndex = mLatest.findEntry(key); + if (oldIndex < 0) { + Slog.w(TAG, "updateNotification for unknown key: " + key); + return; + } + oldList = mLatest; + } + final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex); + final StatusBarNotification oldNotification = oldEntry.notification; + final RemoteViews oldContentView = oldNotification.notification.contentView; + + final RemoteViews contentView = notification.notification.contentView; + + if (false) { + Slog.d(TAG, "old notification: when=" + oldNotification.notification.when + + " ongoing=" + oldNotification.isOngoing() + + " expanded=" + oldEntry.expanded + + " contentView=" + oldContentView); + Slog.d(TAG, "new notification: when=" + notification.notification.when + + " ongoing=" + oldNotification.isOngoing() + + " contentView=" + contentView); + } + + // Can we just reapply the RemoteViews in place? If when didn't change, the order + // didn't change. + if (notification.notification.when == oldNotification.notification.when + && notification.isOngoing() == oldNotification.isOngoing() + && oldEntry.expanded != null + && contentView != null && oldContentView != null + && contentView.getPackage() != null + && oldContentView.getPackage() != null + && oldContentView.getPackage().equals(contentView.getPackage()) + && oldContentView.getLayoutId() == contentView.getLayoutId()) { + if (SPEW) Slog.d(TAG, "reusing notification"); + oldEntry.notification = notification; + try { + // Reapply the RemoteViews + contentView.reapply(this, oldEntry.content); + // update the contentIntent + final PendingIntent contentIntent = notification.notification.contentIntent; + if (contentIntent != null) { + oldEntry.content.setOnClickListener(new Launcher(contentIntent, + notification.pkg, notification.tag, notification.id)); + } + // Update the icon. + final StatusBarIcon ic = new StatusBarIcon(notification.pkg, + notification.notification.icon, notification.notification.iconLevel, + notification.notification.number); + if (!oldEntry.icon.set(ic)) { + handleNotificationError(key, notification, "Couldn't update icon: " + ic); + return; + } + } + catch (RuntimeException e) { + // It failed to add cleanly. Log, and remove the view from the panel. + Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e); + removeNotificationViews(key); + addNotificationViews(key, notification); + } + } else { + if (SPEW) Slog.d(TAG, "not reusing notification"); + removeNotificationViews(key); + addNotificationViews(key, notification); + } + + // Restart the ticker if it's still running + tick(notification); + + // Recalculate the position of the sliding windows and the titles. + setAreThereNotifications(); + updateExpandedViewPos(EXPANDED_LEAVE_ALONE); + } + + public void removeNotification(IBinder key) { + if (SPEW) Slog.d(TAG, "removeNotification key=" + key); + StatusBarNotification old = removeNotificationViews(key); + + if (old != null) { + // Cancel the ticker if it's still running + mTicker.removeEntry(old); + + // Recalculate the position of the sliding windows and the titles. + setAreThereNotifications(); + updateExpandedViewPos(EXPANDED_LEAVE_ALONE); + } + } + + private int chooseIconIndex(boolean isOngoing, int viewIndex) { + final int latestSize = mLatest.size(); + if (isOngoing) { + return latestSize + (mOngoing.size() - viewIndex); + } else { + return latestSize - viewIndex; + } + } + + View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) { + Notification n = notification.notification; + RemoteViews remoteViews = n.contentView; + if (remoteViews == null) { + return null; + } + + // create the row view + LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false); + + // bind the click event to the content area + ViewGroup content = (ViewGroup)row.findViewById(R.id.content); + content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + content.setOnFocusChangeListener(mFocusChangeListener); + PendingIntent contentIntent = n.contentIntent; + if (contentIntent != null) { + content.setOnClickListener(new Launcher(contentIntent, notification.pkg, + notification.tag, notification.id)); + } + + View expanded = null; + Exception exception = null; + try { + expanded = remoteViews.apply(this, content); + } + catch (RuntimeException e) { + exception = e; + } + if (expanded == null) { + String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id); + Slog.e(TAG, "couldn't inflate view for notification " + ident, exception); + return null; + } else { + content.addView(expanded); + row.setDrawingCacheEnabled(true); + } + + return new View[] { row, content, expanded }; + } + + StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) { + NotificationData list; + ViewGroup parent; + final boolean isOngoing = notification.isOngoing(); + if (isOngoing) { + list = mOngoing; + parent = mOngoingItems; + } else { + list = mLatest; + parent = mLatestItems; + } + // Construct the expanded view. + final View[] views = makeNotificationView(notification, parent); + if (views == null) { + handleNotificationError(key, notification, "Couldn't expand RemoteViews for: " + + notification); + return null; + } + final View row = views[0]; + final View content = views[1]; + final View expanded = views[2]; + // Construct the icon. + final StatusBarIconView iconView = new StatusBarIconView(this, + notification.pkg + "/0x" + Integer.toHexString(notification.id)); + final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon, + notification.notification.iconLevel, notification.notification.number); + if (!iconView.set(ic)) { + handleNotificationError(key, notification, "Coulding create icon: " + ic); + return null; + } + // Add the expanded view. + final int viewIndex = list.add(key, notification, row, content, expanded, iconView); + parent.addView(row, viewIndex); + // Add the icon. + final int iconIndex = chooseIconIndex(isOngoing, viewIndex); + mNotificationIcons.addView(iconView, iconIndex, + new LinearLayout.LayoutParams(mIconSize, mIconSize)); + return iconView; + } + + StatusBarNotification removeNotificationViews(IBinder key) { + NotificationData.Entry entry = mOngoing.remove(key); + if (entry == null) { + entry = mLatest.remove(key); + if (entry == null) { + Slog.w(TAG, "removeNotification for unknown key: " + key); + return null; + } + } + // Remove the expanded view. + ((ViewGroup)entry.row.getParent()).removeView(entry.row); + // Remove the icon. + ((ViewGroup)entry.icon.getParent()).removeView(entry.icon); + + return entry.notification; + } + + private void setAreThereNotifications() { + boolean ongoing = mOngoing.hasVisibleItems(); + boolean latest = mLatest.hasVisibleItems(); + + // (no ongoing notifications are clearable) + if (mLatest.hasClearableItems()) { + mClearButton.setVisibility(View.VISIBLE); + } else { + mClearButton.setVisibility(View.INVISIBLE); + } + + mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE); + mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE); + + if (ongoing || latest) { + mNoNotificationsTitle.setVisibility(View.GONE); + } else { + mNoNotificationsTitle.setVisibility(View.VISIBLE); + } + } + + + /** + * State is one or more of the DISABLE constants from StatusBarManager. + */ + public void disable(int state) { + final int old = mDisabled; + final int diff = state ^ old; + mDisabled = state; + + if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { + if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { + Slog.d(TAG, "DISABLE_EXPAND: yes"); + animateCollapse(); + } + } + if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { + if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { + Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); + if (mTicking) { + mTicker.halt(); + } else { + setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out); + } + } else { + Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no"); + if (!mExpandedVisible) { + setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); + } + } + } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { + if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { + Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes"); + mTicker.halt(); + } + } + } + + /** + * All changes to the status bar and notifications funnel through here and are batched. + */ + private class H extends Handler { + public void handleMessage(Message m) { + switch (m.what) { + case MSG_ANIMATE: + doAnimation(); + break; + case MSG_ANIMATE_REVEAL: + doRevealAnimation(); + break; + case MSG_SHOW_INTRUDER: + setIntruderAlertVisibility(true); + break; + case MSG_HIDE_INTRUDER: + setIntruderAlertVisibility(false); + break; + } + } + } + + View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() { + public void onFocusChange(View v, boolean hasFocus) { + // Because 'v' is a ViewGroup, all its children will be (un)selected + // too, which allows marqueeing to work. + v.setSelected(hasFocus); + } + }; + + private void makeExpandedVisible() { + if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); + if (mExpandedVisible) { + return; + } + mExpandedVisible = true; + visibilityChanged(true); + + updateExpandedViewPos(EXPANDED_LEAVE_ALONE); + mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mExpandedDialog.getWindow().setAttributes(mExpandedParams); + mExpandedView.requestFocus(View.FOCUS_FORWARD); + mTrackingView.setVisibility(View.VISIBLE); + + if (!mTicking) { + setDateViewVisibility(true, com.android.internal.R.anim.fade_in); + } + } + + public void animateExpand() { + if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded); + if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { + return ; + } + if (mExpanded) { + return; + } + + prepareTracking(0, true); + performFling(0, 2000.0f, true); + } + + public void animateCollapse() { + if (SPEW) { + Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded + + " mExpandedVisible=" + mExpandedVisible + + " mExpanded=" + mExpanded + + " mAnimating=" + mAnimating + + " mAnimY=" + mAnimY + + " mAnimVel=" + mAnimVel); + } + + if (!mExpandedVisible) { + return; + } + + int y; + if (mAnimating) { + y = (int)mAnimY; + } else { + y = mDisplay.getHeight()-1; + } + // Let the fling think that we're open so it goes in the right direction + // and doesn't try to re-open the windowshade. + mExpanded = true; + prepareTracking(y, false); + performFling(y, -2000.0f, true); + } + + void performExpand() { + if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded); + if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { + return ; + } + if (mExpanded) { + return; + } + + mExpanded = true; + makeExpandedVisible(); + updateExpandedViewPos(EXPANDED_FULL_OPEN); + + if (false) postStartTracing(); + } + + void performCollapse() { + if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded + + " mExpandedVisible=" + mExpandedVisible); + + if (!mExpandedVisible) { + return; + } + mExpandedVisible = false; + visibilityChanged(false); + mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + mExpandedDialog.getWindow().setAttributes(mExpandedParams); + mTrackingView.setVisibility(View.GONE); + + if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) { + setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); + } + setDateViewVisibility(false, com.android.internal.R.anim.fade_out); + + if (!mExpanded) { + return; + } + mExpanded = false; + } + + void doAnimation() { + if (mAnimating) { + if (SPEW) Slog.d(TAG, "doAnimation"); + if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY); + incrementAnim(); + if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY); + if (mAnimY >= mDisplay.getHeight()-1) { + if (SPEW) Slog.d(TAG, "Animation completed to expanded state."); + mAnimating = false; + updateExpandedViewPos(EXPANDED_FULL_OPEN); + performExpand(); + } + else if (mAnimY < mStatusBarView.getHeight()) { + if (SPEW) Slog.d(TAG, "Animation completed to collapsed state."); + mAnimating = false; + updateExpandedViewPos(0); + performCollapse(); + } + else { + updateExpandedViewPos((int)mAnimY); + mCurAnimationTime += ANIM_FRAME_DURATION; + mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); + } + } + } + + void stopTracking() { + mTracking = false; + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + + void incrementAnim() { + long now = SystemClock.uptimeMillis(); + float t = ((float)(now - mAnimLastTime)) / 1000; // ms -> s + final float y = mAnimY; + final float v = mAnimVel; // px/s + final float a = mAnimAccel; // px/s/s + mAnimY = y + (v*t) + (0.5f*a*t*t); // px + mAnimVel = v + (a*t); // px/s + mAnimLastTime = now; // ms + //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY + // + " mAnimAccel=" + mAnimAccel); + } + + void doRevealAnimation() { + final int h = mCloseView.getHeight() + mStatusBarView.getHeight(); + if (mAnimatingReveal && mAnimating && mAnimY < h) { + incrementAnim(); + if (mAnimY >= h) { + mAnimY = h; + updateExpandedViewPos((int)mAnimY); + } else { + updateExpandedViewPos((int)mAnimY); + mCurAnimationTime += ANIM_FRAME_DURATION; + mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), + mCurAnimationTime); + } + } + } + + void prepareTracking(int y, boolean opening) { + mTracking = true; + mVelocityTracker = VelocityTracker.obtain(); + if (opening) { + mAnimAccel = 2000.0f; + mAnimVel = 200; + mAnimY = mStatusBarView.getHeight(); + updateExpandedViewPos((int)mAnimY); + mAnimating = true; + mAnimatingReveal = true; + mHandler.removeMessages(MSG_ANIMATE); + mHandler.removeMessages(MSG_ANIMATE_REVEAL); + long now = SystemClock.uptimeMillis(); + mAnimLastTime = now; + mCurAnimationTime = now + ANIM_FRAME_DURATION; + mAnimating = true; + mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), + mCurAnimationTime); + makeExpandedVisible(); + } else { + // it's open, close it? + if (mAnimating) { + mAnimating = false; + mHandler.removeMessages(MSG_ANIMATE); + } + updateExpandedViewPos(y + mViewDelta); + } + } + + void performFling(int y, float vel, boolean always) { + mAnimatingReveal = false; + mDisplayHeight = mDisplay.getHeight(); + + mAnimY = y; + mAnimVel = vel; + + //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel); + + if (mExpanded) { + if (!always && ( + vel > 200.0f + || (y > (mDisplayHeight-25) && vel > -200.0f))) { + // We are expanded, but they didn't move sufficiently to cause + // us to retract. Animate back to the expanded position. + mAnimAccel = 2000.0f; + if (vel < 0) { + mAnimVel = 0; + } + } + else { + // We are expanded and are now going to animate away. + mAnimAccel = -2000.0f; + if (vel > 0) { + mAnimVel = 0; + } + } + } else { + if (always || ( + vel > 200.0f + || (y > (mDisplayHeight/2) && vel > -200.0f))) { + // We are collapsed, and they moved enough to allow us to + // expand. Animate in the notifications. + mAnimAccel = 2000.0f; + if (vel < 0) { + mAnimVel = 0; + } + } + else { + // We are collapsed, but they didn't move sufficiently to cause + // us to retract. Animate back to the collapsed position. + mAnimAccel = -2000.0f; + if (vel > 0) { + mAnimVel = 0; + } + } + } + //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel + // + " mAnimAccel=" + mAnimAccel); + + long now = SystemClock.uptimeMillis(); + mAnimLastTime = now; + mCurAnimationTime = now + ANIM_FRAME_DURATION; + mAnimating = true; + mHandler.removeMessages(MSG_ANIMATE); + mHandler.removeMessages(MSG_ANIMATE_REVEAL); + mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); + stopTracking(); + } + + boolean interceptTouchEvent(MotionEvent event) { + if (SPEW) { + Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" + + mDisabled); + } + + if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { + return false; + } + + final int statusBarSize = mStatusBarView.getHeight(); + final int hitSize = statusBarSize*2; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + final int y = (int)event.getRawY(); + + if (!mExpanded) { + mViewDelta = statusBarSize - y; + } else { + mTrackingView.getLocationOnScreen(mAbsPos); + mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y; + } + if ((!mExpanded && y < hitSize) || + (mExpanded && y > (mDisplay.getHeight()-hitSize))) { + + // We drop events at the edge of the screen to make the windowshade come + // down by accident less, especially when pushing open a device with a keyboard + // that rotates (like g1 and droid) + int x = (int)event.getRawX(); + final int edgeBorder = mEdgeBorder; + if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) { + prepareTracking(y, !mExpanded);// opening if we're not already fully visible + mVelocityTracker.addMovement(event); + } + } + } else if (mTracking) { + mVelocityTracker.addMovement(event); + final int minY = statusBarSize + mCloseView.getHeight(); + if (event.getAction() == MotionEvent.ACTION_MOVE) { + int y = (int)event.getRawY(); + if (mAnimatingReveal && y < minY) { + // nothing + } else { + mAnimatingReveal = false; + updateExpandedViewPos(y + mViewDelta); + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { + mVelocityTracker.computeCurrentVelocity(1000); + + float yVel = mVelocityTracker.getYVelocity(); + boolean negative = yVel < 0; + + float xVel = mVelocityTracker.getXVelocity(); + if (xVel < 0) { + xVel = -xVel; + } + if (xVel > 150.0f) { + xVel = 150.0f; // limit how much we care about the x axis + } + + float vel = (float)Math.hypot(yVel, xVel); + if (negative) { + vel = -vel; + } + + performFling((int)event.getRawY(), vel, false); + } + + } + return false; + } + + private class Launcher implements View.OnClickListener { + private PendingIntent mIntent; + private String mPkg; + private String mTag; + private int mId; + + Launcher(PendingIntent intent, String pkg, String tag, int id) { + mIntent = intent; + mPkg = pkg; + mTag = tag; + mId = id; + } + + public void onClick(View v) { + try { + // The intent we are sending is for the application, which + // won't have permission to immediately start an activity after + // the user switches to home. We know it is safe to do at this + // point, so make sure new activity switches are now allowed. + ActivityManagerNative.getDefault().resumeAppSwitches(); + } catch (RemoteException e) { + } + + if (mIntent != null) { + int[] pos = new int[2]; + v.getLocationOnScreen(pos); + Intent overlay = new Intent(); + overlay.setSourceBounds( + new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight())); + try { + mIntent.send(PhoneStatusBarService.this, 0, overlay); + } catch (PendingIntent.CanceledException e) { + // the stack trace isn't very helpful here. Just log the exception message. + Slog.w(TAG, "Sending contentIntent failed: " + e); + } + } + + try { + mBarService.onNotificationClick(mPkg, mTag, mId); + } catch (RemoteException ex) { + // system process is dead if we're here. + } + + // close the shade if it was open + animateCollapse(); + + // If this click was on the intruder alert, hide that instead + mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER); + } + } + + private void tick(StatusBarNotification n) { + // Show the ticker if one is requested. Also don't do this + // until status bar window is attached to the window manager, + // because... well, what's the point otherwise? And trying to + // run a ticker without being attached will crash! + if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) { + if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS + | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) { + mTicker.addEntry(n); + } + } + } + + /** + * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService + * about the failure. + * + * WARNING: this will call back into us. Don't hold any locks. + */ + void handleNotificationError(IBinder key, StatusBarNotification n, String message) { + removeNotification(key); + try { + mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message); + } catch (RemoteException ex) { + // The end is nigh. + } + } + + private class MyTicker extends Ticker { + MyTicker(Context context, StatusBarView sb) { + super(context, sb); + } + + @Override + void tickerStarting() { + mTicking = true; + mIcons.setVisibility(View.GONE); + mTickerView.setVisibility(View.VISIBLE); + mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); + mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); + if (mExpandedVisible) { + setDateViewVisibility(false, com.android.internal.R.anim.push_up_out); + } + } + + @Override + void tickerDone() { + mIcons.setVisibility(View.VISIBLE); + mTickerView.setVisibility(View.GONE); + mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); + mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, + mTickingDoneListener)); + if (mExpandedVisible) { + setDateViewVisibility(true, com.android.internal.R.anim.push_down_in); + } + } + + void tickerHalting() { + mIcons.setVisibility(View.VISIBLE); + mTickerView.setVisibility(View.GONE); + mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); + mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out, + mTickingDoneListener)); + if (mExpandedVisible) { + setDateViewVisibility(true, com.android.internal.R.anim.fade_in); + } + } + } + + Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; + public void onAnimationEnd(Animation animation) { + mTicking = false; + } + public void onAnimationRepeat(Animation animation) { + } + public void onAnimationStart(Animation animation) { + } + }; + + private Animation loadAnim(int id, Animation.AnimationListener listener) { + Animation anim = AnimationUtils.loadAnimation(PhoneStatusBarService.this, id); + if (listener != null) { + anim.setAnimationListener(listener); + } + return anim; + } + + public String viewInfo(View v) { + return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() + + " " + v.getWidth() + "x" + v.getHeight() + ")"; + } + + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump StatusBar from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + synchronized (mQueueLock) { + pw.println("Current Status Bar state:"); + pw.println(" mExpanded=" + mExpanded + + ", mExpandedVisible=" + mExpandedVisible); + pw.println(" mTicking=" + mTicking); + pw.println(" mTracking=" + mTracking); + pw.println(" mAnimating=" + mAnimating + + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel + + ", mAnimAccel=" + mAnimAccel); + pw.println(" mCurAnimationTime=" + mCurAnimationTime + + " mAnimLastTime=" + mAnimLastTime); + pw.println(" mDisplayHeight=" + mDisplayHeight + + " mAnimatingReveal=" + mAnimatingReveal + + " mViewDelta=" + mViewDelta); + pw.println(" mDisplayHeight=" + mDisplayHeight); + pw.println(" mExpandedParams: " + mExpandedParams); + pw.println(" mExpandedView: " + viewInfo(mExpandedView)); + pw.println(" mExpandedDialog: " + mExpandedDialog); + pw.println(" mTrackingParams: " + mTrackingParams); + pw.println(" mTrackingView: " + viewInfo(mTrackingView)); + pw.println(" mOngoingTitle: " + viewInfo(mOngoingTitle)); + pw.println(" mOngoingItems: " + viewInfo(mOngoingItems)); + pw.println(" mLatestTitle: " + viewInfo(mLatestTitle)); + pw.println(" mLatestItems: " + viewInfo(mLatestItems)); + pw.println(" mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle)); + pw.println(" mCloseView: " + viewInfo(mCloseView)); + pw.println(" mTickerView: " + viewInfo(mTickerView)); + pw.println(" mScrollView: " + viewInfo(mScrollView) + + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY()); + pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout)); + } + /* + synchronized (mNotificationData) { + int N = mNotificationData.ongoingCount(); + pw.println(" ongoingCount.size=" + N); + for (int i=0; i<N; i++) { + StatusBarNotification n = mNotificationData.getOngoing(i); + pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); + pw.println(" data=" + n.data); + } + N = mNotificationData.latestCount(); + pw.println(" ongoingCount.size=" + N); + for (int i=0; i<N; i++) { + StatusBarNotification n = mNotificationData.getLatest(i); + pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); + pw.println(" data=" + n.data); + } + } + */ + + if (false) { + pw.println("see the logcat for a dump of the views we have created."); + // must happen on ui thread + mHandler.post(new Runnable() { + public void run() { + mStatusBarView.getLocationOnScreen(mAbsPos); + Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] + + ") " + mStatusBarView.getWidth() + "x" + + mStatusBarView.getHeight()); + mStatusBarView.debug(); + + mExpandedView.getLocationOnScreen(mAbsPos); + Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] + + ") " + mExpandedView.getWidth() + "x" + + mExpandedView.getHeight()); + mExpandedView.debug(); + + mTrackingView.getLocationOnScreen(mAbsPos); + Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] + + ") " + mTrackingView.getWidth() + "x" + + mTrackingView.getHeight()); + mTrackingView.debug(); + } + }); + } + } + + void onBarViewAttached() { + WindowManager.LayoutParams lp; + int pixelFormat; + Drawable bg; + + /// ---------- Tracking View -------------- + pixelFormat = PixelFormat.RGBX_8888; + bg = mTrackingView.getBackground(); + if (bg != null) { + pixelFormat = bg.getOpacity(); + } + + lp = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + pixelFormat); +// lp.token = mStatusBarView.getWindowToken(); + lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; + lp.setTitle("TrackingView"); + lp.y = mTrackingPosition; + mTrackingParams = lp; + + WindowManagerImpl.getDefault().addView(mTrackingView, lp); + } + + void onTrackingViewAttached() { + WindowManager.LayoutParams lp; + int pixelFormat; + Drawable bg; + + /// ---------- Expanded View -------------- + pixelFormat = PixelFormat.TRANSLUCENT; + + final int disph = mDisplay.getHeight(); + lp = mExpandedDialog.getWindow().getAttributes(); + lp.width = ViewGroup.LayoutParams.MATCH_PARENT; + lp.height = getExpandedHeight(); + lp.x = 0; + mTrackingPosition = lp.y = -disph; // sufficiently large negative + lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; + lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_DITHER + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + lp.format = pixelFormat; + lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; + lp.setTitle("StatusBarExpanded"); + mExpandedDialog.getWindow().setAttributes(lp); + mExpandedDialog.getWindow().setFormat(pixelFormat); + mExpandedParams = lp; + + mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); + mExpandedDialog.setContentView(mExpandedView, + new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + mExpandedDialog.getWindow().setBackgroundDrawable(null); + mExpandedDialog.show(); + FrameLayout hack = (FrameLayout)mExpandedView.getParent(); + } + + void setDateViewVisibility(boolean visible, int anim) { + mDateView.setUpdates(visible); + mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + mDateView.startAnimation(loadAnim(anim, null)); + } + + void setNotificationIconVisibility(boolean visible, int anim) { + int old = mNotificationIcons.getVisibility(); + int v = visible ? View.VISIBLE : View.INVISIBLE; + if (old != v) { + mNotificationIcons.setVisibility(v); + mNotificationIcons.startAnimation(loadAnim(anim, null)); + } + } + + void updateExpandedViewPos(int expandedPosition) { + if (SPEW) { + Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition + + " mTrackingParams.y=" + mTrackingParams.y + + " mTrackingPosition=" + mTrackingPosition); + } + + int h = mStatusBarView.getHeight(); + int disph = mDisplay.getHeight(); + + // If the expanded view is not visible, make sure they're still off screen. + // Maybe the view was resized. + if (!mExpandedVisible) { + if (mTrackingView != null) { + mTrackingPosition = -disph; + if (mTrackingParams != null) { + mTrackingParams.y = mTrackingPosition; + WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams); + } + } + if (mExpandedParams != null) { + mExpandedParams.y = -disph; + mExpandedDialog.getWindow().setAttributes(mExpandedParams); + } + return; + } + + // tracking view... + int pos; + if (expandedPosition == EXPANDED_FULL_OPEN) { + pos = h; + } + else if (expandedPosition == EXPANDED_LEAVE_ALONE) { + pos = mTrackingPosition; + } + else { + if (expandedPosition <= disph) { + pos = expandedPosition; + } else { + pos = disph; + } + pos -= disph-h; + } + mTrackingPosition = mTrackingParams.y = pos; + mTrackingParams.height = disph-h; + WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams); + + if (mExpandedParams != null) { + mCloseView.getLocationInWindow(mPositionTmp); + final int closePos = mPositionTmp[1]; + + mExpandedContents.getLocationInWindow(mPositionTmp); + final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight(); + + mExpandedParams.y = pos + mTrackingView.getHeight() + - (mTrackingParams.height-closePos) - contentsBottom; + int max = h; + if (mExpandedParams.y > max) { + mExpandedParams.y = max; + } + int min = mTrackingPosition; + if (mExpandedParams.y < min) { + mExpandedParams.y = min; + } + + boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h; + if (!visible) { + // if the contents aren't visible, move the expanded view way off screen + // because the window itself extends below the content view. + mExpandedParams.y = -disph; + } + mExpandedDialog.getWindow().setAttributes(mExpandedParams); + + // As long as this isn't just a repositioning that's not supposed to affect + // the user's perception of what's showing, call to say that the visibility + // has changed. (Otherwise, someone else will call to do that). + if (expandedPosition != EXPANDED_LEAVE_ALONE) { + if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")"); + visibilityChanged(visible); + } + } + + if (SPEW) { + Slog.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition + + " mTrackingParams.y=" + mTrackingParams.y + + " mTrackingPosition=" + mTrackingPosition + + " mExpandedParams.y=" + mExpandedParams.y + + " mExpandedParams.height=" + mExpandedParams.height); + } + } + + int getExpandedHeight() { + return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight(); + } + + void updateExpandedHeight() { + if (mExpandedView != null) { + mExpandedParams.height = getExpandedHeight(); + mExpandedDialog.getWindow().setAttributes(mExpandedParams); + } + } + + /** + * The LEDs are turned o)ff when the notification panel is shown, even just a little bit. + * This was added last-minute and is inconsistent with the way the rest of the notifications + * are handled, because the notification isn't really cancelled. The lights are just + * turned off. If any other notifications happen, the lights will turn back on. Steve says + * this is what he wants. (see bug 1131461) + */ + void visibilityChanged(boolean visible) { + if (mPanelSlightlyVisible != visible) { + mPanelSlightlyVisible = visible; + try { + mBarService.onPanelRevealed(); + } catch (RemoteException ex) { + // Won't fail unless the world has ended. + } + } + } + + void performDisableActions(int net) { + int old = mDisabled; + int diff = net ^ old; + mDisabled = net; + + // act accordingly + if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { + if ((net & StatusBarManager.DISABLE_EXPAND) != 0) { + Slog.d(TAG, "DISABLE_EXPAND: yes"); + animateCollapse(); + } + } + if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { + if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { + Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); + if (mTicking) { + mNotificationIcons.setVisibility(View.INVISIBLE); + mTicker.halt(); + } else { + setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out); + } + } else { + Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no"); + if (!mExpandedVisible) { + setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); + } + } + } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { + if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { + mTicker.halt(); + } + } + } + + private View.OnClickListener mClearButtonListener = new View.OnClickListener() { + public void onClick(View v) { + try { + mBarService.onClearAllNotifications(); + } catch (RemoteException ex) { + // system process is dead if we're here. + } + animateCollapse(); + } + }; + + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) + || Intent.ACTION_SCREEN_OFF.equals(action)) { + //collapse(); + } + else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { + updateResources(); + } + } + }; + + private void setIntruderAlertVisibility(boolean vis) { + mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE); + } + + /** + * Reload some of our resources when the configuration changes. + * + * We don't reload everything when the configuration changes -- we probably + * should, but getting that smooth is tough. Someday we'll fix that. In the + * meantime, just update the things that we know change. + */ + void updateResources() { + Resources res = getResources(); + + mClearButton.setText(getText(R.string.status_bar_clear_all_button)); + mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title)); + mLatestTitle.setText(getText(R.string.status_bar_latest_events_title)); + mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title)); + + mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); + + if (false) Slog.v(TAG, "updateResources"); + } + + // + // tracing + // + + void postStartTracing() { + mHandler.postDelayed(mStartTracing, 3000); + } + + void vibrate() { + android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE); + vib.vibrate(250); + } + + Runnable mStartTracing = new Runnable() { + public void run() { + vibrate(); + SystemClock.sleep(250); + Slog.d(TAG, "startTracing"); + android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); + mHandler.postDelayed(mStopTracing, 10000); + } + }; + + Runnable mStopTracing = new Runnable() { + public void run() { + android.os.Debug.stopMethodTracing(); + Slog.d(TAG, "stopTracing"); + vibrate(); + } + }; +} + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java index 0d02447..a64c3e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java @@ -17,194 +17,53 @@ package com.android.systemui.statusbar; import android.app.Service; -import com.android.internal.statusbar.IStatusBar; -import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.statusbar.StatusBarIcon; -import com.android.internal.statusbar.StatusBarIconList; -import com.android.internal.statusbar.StatusBarNotification; - -import android.app.ActivityManagerNative; -import android.app.Dialog; -import android.app.Notification; -import android.app.PendingIntent; -import android.app.Service; -import android.app.StatusBarManager; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.IBinder; import android.os.RemoteException; -import android.os.Binder; -import android.os.Handler; -import android.os.Message; import android.os.ServiceManager; -import android.os.SystemClock; import android.util.Slog; import android.util.Log; -import android.view.Display; import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; -import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RemoteViews; -import android.widget.ScrollView; -import android.widget.TextView; -import android.widget.FrameLayout; -import java.io.FileDescriptor; -import java.io.PrintWriter; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Set; - -import com.android.systemui.R; -import com.android.systemui.statusbar.policy.StatusBarPolicy; +import com.android.internal.statusbar.IStatusBar; +import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.statusbar.StatusBarIconList; +import com.android.internal.statusbar.StatusBarNotification; +import com.android.systemui.R; -public class StatusBarService extends Service implements CommandQueue.Callbacks { +public abstract class StatusBarService extends Service implements CommandQueue.Callbacks { static final String TAG = "StatusBarService"; - static final boolean SPEW = false; - - public static final String ACTION_STATUSBAR_START - = "com.android.internal.policy.statusbar.START"; - - static final int EXPANDED_LEAVE_ALONE = -10000; - static final int EXPANDED_FULL_OPEN = -10001; - - private static final int MSG_ANIMATE = 1000; - private static final int MSG_ANIMATE_REVEAL = 1001; - private static final int MSG_SHOW_INTRUDER = 1002; - private static final int MSG_HIDE_INTRUDER = 1003; - - // will likely move to a resource or other tunable param at some point - private static final int INTRUDER_ALERT_DECAY_MS = 10000; - - static final int POSITION_TOP = 0; - static final int POSITION_BOTTOM = 1; - - StatusBarPolicy mIconPolicy; - - CommandQueue mCommandQueue; - IStatusBarService mBarService; - - int mIconSize; - Display mDisplay; - int mPosition; - - StatusBarView mStatusBarView; - int mPixelFormat; - H mHandler = new H(); - Object mQueueLock = new Object(); - - // icons - LinearLayout mIcons; - IconMerger mNotificationIcons; - LinearLayout mStatusIcons; - - // expanded notifications - Dialog mExpandedDialog; - ExpandedView mExpandedView; - WindowManager.LayoutParams mExpandedParams; - ScrollView mScrollView; - View mNotificationLinearLayout; - View mExpandedContents; - // top bar - TextView mNoNotificationsTitle; - TextView mClearButton; - // drag bar - CloseDragHandle mCloseView; - // ongoing - NotificationData mOngoing = new NotificationData(); - TextView mOngoingTitle; - LinearLayout mOngoingItems; - // latest - NotificationData mLatest = new NotificationData(); - TextView mLatestTitle; - LinearLayout mLatestItems; - // position - int[] mPositionTmp = new int[2]; - boolean mExpanded; - boolean mExpandedVisible; - // the date view - DateView mDateView; + protected CommandQueue mCommandQueue; + protected IStatusBarService mBarService; - // the tracker view - TrackingView mTrackingView; - WindowManager.LayoutParams mTrackingParams; - int mTrackingPosition; // the position of the top of the tracking view. - private boolean mPanelSlightlyVisible; + // Up-call methods + protected abstract View makeStatusBarView(); + protected abstract int getStatusBarGravity(); - // ticker - private Ticker mTicker; - private View mTickerView; - private boolean mTicking; - - // Tracking finger for opening/closing. - int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore - boolean mTracking; - VelocityTracker mVelocityTracker; - - static final int ANIM_FRAME_DURATION = (1000/60); - - boolean mAnimating; - long mCurAnimationTime; - float mDisplayHeight; - float mAnimY; - float mAnimVel; - float mAnimAccel; - long mAnimLastTime; - boolean mAnimatingReveal = false; - int mViewDelta; - int[] mAbsPos = new int[2]; - - // for disabling the status bar - int mDisabled = 0; - - private class ExpandedDialog extends Dialog { - ExpandedDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Light_NoTitleBar); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - boolean down = event.getAction() == KeyEvent.ACTION_DOWN; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_BACK: - if (!down) { - animateCollapse(); - } - return true; - } - return super.dispatchKeyEvent(event); - } + /** + * Nobody binds to us. + */ + @Override + public IBinder onBind(Intent intent) { + return null; } @Override public void onCreate() { // First set up our views and stuff. - final Resources res = getResources(); - mPosition = res.getInteger(R.integer.config_status_bar_position); - mDisplay = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - makeStatusBarView(this); + View sb = makeStatusBarView(); // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); @@ -242,1379 +101,22 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks } // Put up the view - addStatusBarView(); - - // Lastly, call to the icon policy to install/update all the icons. - mIconPolicy = new StatusBarPolicy(this); - } - - @Override - public void onDestroy() { - // we're never destroyed - } - - // for immersive activities - private View mIntruderAlertView; - - /** - * Nobody binds to us. - */ - @Override - public IBinder onBind(Intent intent) { - return null; - } - - // ================================================================================ - // Constructing the view - // ================================================================================ - private void makeStatusBarView(Context context) { - Resources res = context.getResources(); - - mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); - - ExpandedView expanded = (ExpandedView)View.inflate(context, - R.layout.status_bar_expanded, null); - expanded.mService = this; - - mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null); - mIntruderAlertView.setVisibility(View.GONE); - mIntruderAlertView.setClickable(true); - - StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null); - sb.mService = this; - - // figure out which pixel-format to use for the status bar. - mPixelFormat = PixelFormat.TRANSLUCENT; - Drawable bg = sb.getBackground(); - if (bg != null) { - mPixelFormat = bg.getOpacity(); - } - - mStatusBarView = sb; - mStatusIcons = (LinearLayout)sb.findViewById(R.id.statusIcons); - mNotificationIcons = (IconMerger)sb.findViewById(R.id.notificationIcons); - mIcons = (LinearLayout)sb.findViewById(R.id.icons); - mTickerView = sb.findViewById(R.id.ticker); - mDateView = (DateView)sb.findViewById(R.id.date); - - mExpandedDialog = new ExpandedDialog(context); - mExpandedView = expanded; - mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout); - mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle); - mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems); - mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle); - mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems); - mNoNotificationsTitle = (TextView)expanded.findViewById(R.id.noNotificationsTitle); - mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button); - mClearButton.setOnClickListener(mClearButtonListener); - mScrollView = (ScrollView)expanded.findViewById(R.id.scroll); - mNotificationLinearLayout = expanded.findViewById(R.id.notificationLinearLayout); - - mOngoingTitle.setVisibility(View.GONE); - mLatestTitle.setVisibility(View.GONE); - - mTicker = new MyTicker(context, sb); - - TickerView tickerView = (TickerView)sb.findViewById(R.id.tickerText); - tickerView.mTicker = mTicker; - - mTrackingView = (TrackingView)View.inflate(context, R.layout.status_bar_tracking, null); - mTrackingView.mService = this; - mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close); - mCloseView.mService = this; - - mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); - - // the more notifications icon - StatusBarIconView moreView = new StatusBarIconView(this, "more"); - moreView.set(new StatusBarIcon(null, R.drawable.stat_notify_more, 0)); - mNotificationIcons.addMoreView(moreView, - new LinearLayout.LayoutParams(mIconSize, mIconSize)); - - // set the inital view visibility - setAreThereNotifications(); - mDateView.setVisibility(View.INVISIBLE); - - // receive broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - filter.addAction(Intent.ACTION_SCREEN_OFF); - context.registerReceiver(mBroadcastReceiver, filter); - } - - protected void addStatusBarView() { - Resources res = getResources(); + final Resources res = getResources(); final int height= res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); - final StatusBarView view = mStatusBarView; - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, height, WindowManager.LayoutParams.TYPE_STATUS_BAR, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING, PixelFormat.RGBX_8888); - if (mPosition == POSITION_TOP) { - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - } else { - lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL; - } + lp.gravity = getStatusBarGravity(); lp.setTitle("StatusBar"); // TODO lp.windowAnimations = R.style.Animation_StatusBar; + WindowManagerImpl.getDefault().addView(sb, lp); - WindowManagerImpl.getDefault().addView(view, lp); - - lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - PixelFormat.TRANSLUCENT); - if (mPosition == POSITION_TOP) { - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - } else { - lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL; - } - lp.y += height * 1.5; // FIXME - lp.setTitle("IntruderAlert"); - lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert; - - WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp); - } - - public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { - if (SPEW) Slog.d(TAG, "addIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex - + " icon=" + icon); - StatusBarIconView view = new StatusBarIconView(this, slot); - view.set(icon); - mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(mIconSize, mIconSize)); + Slog.d(TAG, "Added status bar view w/ gravity 0x" + Integer.toHexString(lp.gravity)); } - - public void updateIcon(String slot, int index, int viewIndex, - StatusBarIcon old, StatusBarIcon icon) { - if (SPEW) Slog.d(TAG, "updateIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex - + " old=" + old + " icon=" + icon); - StatusBarIconView view = (StatusBarIconView)mStatusIcons.getChildAt(viewIndex); - view.set(icon); - } - - public void removeIcon(String slot, int index, int viewIndex) { - if (SPEW) Slog.d(TAG, "removeIcon slot=" + slot + " index=" + index + " viewIndex=" + viewIndex); - mStatusIcons.removeViewAt(viewIndex); - } - - public void addNotification(IBinder key, StatusBarNotification notification) { - StatusBarIconView iconView = addNotificationViews(key, notification); - if (iconView == null) return; - - boolean immersive = false; - try { - immersive = ActivityManagerNative.getDefault().isTopActivityImmersive(); - Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive")); - } catch (RemoteException ex) { - } - if (immersive) { - if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) { - Slog.d(TAG, "Presenting high-priority notification in immersive activity"); - // @@@ special new transient ticker mode - // 1. Populate mIntruderAlertView - - ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon); - TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText); - alertIcon.setImageDrawable(StatusBarIconView.getIcon( - alertIcon.getContext(), - iconView.getStatusBarIcon())); - alertText.setText(notification.notification.tickerText); - - View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content); - button.setOnClickListener( - new Launcher(notification.notification.contentIntent, - notification.pkg, notification.tag, notification.id)); - - // 2. Animate mIntruderAlertView in - mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER); - - // 3. Set alarm to age the notification off (TODO) - mHandler.removeMessages(MSG_HIDE_INTRUDER); - mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS); - } - } else if (notification.notification.fullScreenIntent != null) { - // not immersive & a full-screen alert should be shown - Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;" - + " sending fullScreenIntent"); - try { - notification.notification.fullScreenIntent.send(); - } catch (PendingIntent.CanceledException e) { - } - } else { - // usual case: status bar visible & not immersive - - // show the ticker - tick(notification); - } - - // Recalculate the position of the sliding windows and the titles. - setAreThereNotifications(); - updateExpandedViewPos(EXPANDED_LEAVE_ALONE); - } - - public void updateNotification(IBinder key, StatusBarNotification notification) { - Slog.d(TAG, "updateNotification key=" + key + " notification=" + notification); - - NotificationData oldList; - int oldIndex = mOngoing.findEntry(key); - if (oldIndex >= 0) { - oldList = mOngoing; - } else { - oldIndex = mLatest.findEntry(key); - if (oldIndex < 0) { - Slog.w(TAG, "updateNotification for unknown key: " + key); - return; - } - oldList = mLatest; - } - final NotificationData.Entry oldEntry = oldList.getEntryAt(oldIndex); - final StatusBarNotification oldNotification = oldEntry.notification; - final RemoteViews oldContentView = oldNotification.notification.contentView; - - final RemoteViews contentView = notification.notification.contentView; - - if (false) { - Slog.d(TAG, "old notification: when=" + oldNotification.notification.when - + " ongoing=" + oldNotification.isOngoing() - + " expanded=" + oldEntry.expanded - + " contentView=" + oldContentView); - Slog.d(TAG, "new notification: when=" + notification.notification.when - + " ongoing=" + oldNotification.isOngoing() - + " contentView=" + contentView); - } - - // Can we just reapply the RemoteViews in place? If when didn't change, the order - // didn't change. - if (notification.notification.when == oldNotification.notification.when - && notification.isOngoing() == oldNotification.isOngoing() - && oldEntry.expanded != null - && contentView != null && oldContentView != null - && contentView.getPackage() != null - && oldContentView.getPackage() != null - && oldContentView.getPackage().equals(contentView.getPackage()) - && oldContentView.getLayoutId() == contentView.getLayoutId()) { - if (SPEW) Slog.d(TAG, "reusing notification"); - oldEntry.notification = notification; - try { - // Reapply the RemoteViews - contentView.reapply(this, oldEntry.content); - // update the contentIntent - final PendingIntent contentIntent = notification.notification.contentIntent; - if (contentIntent != null) { - oldEntry.content.setOnClickListener(new Launcher(contentIntent, - notification.pkg, notification.tag, notification.id)); - } - // Update the icon. - final StatusBarIcon ic = new StatusBarIcon(notification.pkg, - notification.notification.icon, notification.notification.iconLevel, - notification.notification.number); - if (!oldEntry.icon.set(ic)) { - handleNotificationError(key, notification, "Couldn't update icon: " + ic); - return; - } - } - catch (RuntimeException e) { - // It failed to add cleanly. Log, and remove the view from the panel. - Slog.w(TAG, "Couldn't reapply views for package " + contentView.getPackage(), e); - removeNotificationViews(key); - addNotificationViews(key, notification); - } - } else { - if (SPEW) Slog.d(TAG, "not reusing notification"); - removeNotificationViews(key); - addNotificationViews(key, notification); - } - - // Restart the ticker if it's still running - tick(notification); - - // Recalculate the position of the sliding windows and the titles. - setAreThereNotifications(); - updateExpandedViewPos(EXPANDED_LEAVE_ALONE); - } - - public void removeNotification(IBinder key) { - if (SPEW) Slog.d(TAG, "removeNotification key=" + key); - StatusBarNotification old = removeNotificationViews(key); - - if (old != null) { - // Cancel the ticker if it's still running - mTicker.removeEntry(old); - - // Recalculate the position of the sliding windows and the titles. - setAreThereNotifications(); - updateExpandedViewPos(EXPANDED_LEAVE_ALONE); - } - } - - private int chooseIconIndex(boolean isOngoing, int viewIndex) { - final int latestSize = mLatest.size(); - if (isOngoing) { - return latestSize + (mOngoing.size() - viewIndex); - } else { - return latestSize - viewIndex; - } - } - - View[] makeNotificationView(StatusBarNotification notification, ViewGroup parent) { - Notification n = notification.notification; - RemoteViews remoteViews = n.contentView; - if (remoteViews == null) { - return null; - } - - // create the row view - LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View row = inflater.inflate(R.layout.status_bar_latest_event, parent, false); - - // bind the click event to the content area - ViewGroup content = (ViewGroup)row.findViewById(R.id.content); - content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - content.setOnFocusChangeListener(mFocusChangeListener); - PendingIntent contentIntent = n.contentIntent; - if (contentIntent != null) { - content.setOnClickListener(new Launcher(contentIntent, notification.pkg, - notification.tag, notification.id)); - } - - View expanded = null; - Exception exception = null; - try { - expanded = remoteViews.apply(this, content); - } - catch (RuntimeException e) { - exception = e; - } - if (expanded == null) { - String ident = notification.pkg + "/0x" + Integer.toHexString(notification.id); - Slog.e(TAG, "couldn't inflate view for notification " + ident, exception); - return null; - } else { - content.addView(expanded); - row.setDrawingCacheEnabled(true); - } - - return new View[] { row, content, expanded }; - } - - StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) { - NotificationData list; - ViewGroup parent; - final boolean isOngoing = notification.isOngoing(); - if (isOngoing) { - list = mOngoing; - parent = mOngoingItems; - } else { - list = mLatest; - parent = mLatestItems; - } - // Construct the expanded view. - final View[] views = makeNotificationView(notification, parent); - if (views == null) { - handleNotificationError(key, notification, "Couldn't expand RemoteViews for: " - + notification); - return null; - } - final View row = views[0]; - final View content = views[1]; - final View expanded = views[2]; - // Construct the icon. - final StatusBarIconView iconView = new StatusBarIconView(this, - notification.pkg + "/0x" + Integer.toHexString(notification.id)); - final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon, - notification.notification.iconLevel, notification.notification.number); - if (!iconView.set(ic)) { - handleNotificationError(key, notification, "Coulding create icon: " + ic); - return null; - } - // Add the expanded view. - final int viewIndex = list.add(key, notification, row, content, expanded, iconView); - parent.addView(row, viewIndex); - // Add the icon. - final int iconIndex = chooseIconIndex(isOngoing, viewIndex); - mNotificationIcons.addView(iconView, iconIndex, - new LinearLayout.LayoutParams(mIconSize, mIconSize)); - return iconView; - } - - StatusBarNotification removeNotificationViews(IBinder key) { - NotificationData.Entry entry = mOngoing.remove(key); - if (entry == null) { - entry = mLatest.remove(key); - if (entry == null) { - Slog.w(TAG, "removeNotification for unknown key: " + key); - return null; - } - } - // Remove the expanded view. - ((ViewGroup)entry.row.getParent()).removeView(entry.row); - // Remove the icon. - ((ViewGroup)entry.icon.getParent()).removeView(entry.icon); - - return entry.notification; - } - - private void setAreThereNotifications() { - boolean ongoing = mOngoing.hasVisibleItems(); - boolean latest = mLatest.hasVisibleItems(); - - // (no ongoing notifications are clearable) - if (mLatest.hasClearableItems()) { - mClearButton.setVisibility(View.VISIBLE); - } else { - mClearButton.setVisibility(View.INVISIBLE); - } - - mOngoingTitle.setVisibility(ongoing ? View.VISIBLE : View.GONE); - mLatestTitle.setVisibility(latest ? View.VISIBLE : View.GONE); - - if (ongoing || latest) { - mNoNotificationsTitle.setVisibility(View.GONE); - } else { - mNoNotificationsTitle.setVisibility(View.VISIBLE); - } - } - - - /** - * State is one or more of the DISABLE constants from StatusBarManager. - */ - public void disable(int state) { - final int old = mDisabled; - final int diff = state ^ old; - mDisabled = state; - - if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { - if ((state & StatusBarManager.DISABLE_EXPAND) != 0) { - Slog.d(TAG, "DISABLE_EXPAND: yes"); - animateCollapse(); - } - } - if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); - if (mTicking) { - mTicker.halt(); - } else { - setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out); - } - } else { - Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no"); - if (!mExpandedVisible) { - setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); - } - } - } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { - if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { - Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes"); - mTicker.halt(); - } - } - } - - /** - * All changes to the status bar and notifications funnel through here and are batched. - */ - private class H extends Handler { - public void handleMessage(Message m) { - switch (m.what) { - case MSG_ANIMATE: - doAnimation(); - break; - case MSG_ANIMATE_REVEAL: - doRevealAnimation(); - break; - case MSG_SHOW_INTRUDER: - setIntruderAlertVisibility(true); - break; - case MSG_HIDE_INTRUDER: - setIntruderAlertVisibility(false); - break; - } - } - } - - View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() { - public void onFocusChange(View v, boolean hasFocus) { - // Because 'v' is a ViewGroup, all its children will be (un)selected - // too, which allows marqueeing to work. - v.setSelected(hasFocus); - } - }; - - private void makeExpandedVisible() { - if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible); - if (mExpandedVisible) { - return; - } - mExpandedVisible = true; - visibilityChanged(true); - - updateExpandedViewPos(EXPANDED_LEAVE_ALONE); - mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - mExpandedDialog.getWindow().setAttributes(mExpandedParams); - mExpandedView.requestFocus(View.FOCUS_FORWARD); - mTrackingView.setVisibility(View.VISIBLE); - - if (!mTicking) { - setDateViewVisibility(true, com.android.internal.R.anim.fade_in); - } - } - - public void animateExpand() { - if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded); - if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { - return ; - } - if (mExpanded) { - return; - } - - prepareTracking(0, true); - performFling(0, 2000.0f, true); - } - - public void animateCollapse() { - if (SPEW) { - Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded - + " mExpandedVisible=" + mExpandedVisible - + " mExpanded=" + mExpanded - + " mAnimating=" + mAnimating - + " mAnimY=" + mAnimY - + " mAnimVel=" + mAnimVel); - } - - if (!mExpandedVisible) { - return; - } - - int y; - if (mAnimating) { - y = (int)mAnimY; - } else { - y = mDisplay.getHeight()-1; - } - // Let the fling think that we're open so it goes in the right direction - // and doesn't try to re-open the windowshade. - mExpanded = true; - prepareTracking(y, false); - performFling(y, -2000.0f, true); - } - - void performExpand() { - if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded); - if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { - return ; - } - if (mExpanded) { - return; - } - - mExpanded = true; - makeExpandedVisible(); - updateExpandedViewPos(EXPANDED_FULL_OPEN); - - if (false) postStartTracing(); - } - - void performCollapse() { - if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded - + " mExpandedVisible=" + mExpandedVisible); - - if (!mExpandedVisible) { - return; - } - mExpandedVisible = false; - visibilityChanged(false); - mExpandedParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mExpandedParams.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - mExpandedDialog.getWindow().setAttributes(mExpandedParams); - mTrackingView.setVisibility(View.GONE); - - if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) { - setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); - } - setDateViewVisibility(false, com.android.internal.R.anim.fade_out); - - if (!mExpanded) { - return; - } - mExpanded = false; - } - - void doAnimation() { - if (mAnimating) { - if (SPEW) Slog.d(TAG, "doAnimation"); - if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY); - incrementAnim(); - if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY); - if (mAnimY >= mDisplay.getHeight()-1) { - if (SPEW) Slog.d(TAG, "Animation completed to expanded state."); - mAnimating = false; - updateExpandedViewPos(EXPANDED_FULL_OPEN); - performExpand(); - } - else if (mAnimY < mStatusBarView.getHeight()) { - if (SPEW) Slog.d(TAG, "Animation completed to collapsed state."); - mAnimating = false; - updateExpandedViewPos(0); - performCollapse(); - } - else { - updateExpandedViewPos((int)mAnimY); - mCurAnimationTime += ANIM_FRAME_DURATION; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); - } - } - } - - void stopTracking() { - mTracking = false; - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - - void incrementAnim() { - long now = SystemClock.uptimeMillis(); - float t = ((float)(now - mAnimLastTime)) / 1000; // ms -> s - final float y = mAnimY; - final float v = mAnimVel; // px/s - final float a = mAnimAccel; // px/s/s - mAnimY = y + (v*t) + (0.5f*a*t*t); // px - mAnimVel = v + (a*t); // px/s - mAnimLastTime = now; // ms - //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY - // + " mAnimAccel=" + mAnimAccel); - } - - void doRevealAnimation() { - final int h = mCloseView.getHeight() + mStatusBarView.getHeight(); - if (mAnimatingReveal && mAnimating && mAnimY < h) { - incrementAnim(); - if (mAnimY >= h) { - mAnimY = h; - updateExpandedViewPos((int)mAnimY); - } else { - updateExpandedViewPos((int)mAnimY); - mCurAnimationTime += ANIM_FRAME_DURATION; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), - mCurAnimationTime); - } - } - } - - void prepareTracking(int y, boolean opening) { - mTracking = true; - mVelocityTracker = VelocityTracker.obtain(); - if (opening) { - mAnimAccel = 2000.0f; - mAnimVel = 200; - mAnimY = mStatusBarView.getHeight(); - updateExpandedViewPos((int)mAnimY); - mAnimating = true; - mAnimatingReveal = true; - mHandler.removeMessages(MSG_ANIMATE); - mHandler.removeMessages(MSG_ANIMATE_REVEAL); - long now = SystemClock.uptimeMillis(); - mAnimLastTime = now; - mCurAnimationTime = now + ANIM_FRAME_DURATION; - mAnimating = true; - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE_REVEAL), - mCurAnimationTime); - makeExpandedVisible(); - } else { - // it's open, close it? - if (mAnimating) { - mAnimating = false; - mHandler.removeMessages(MSG_ANIMATE); - } - updateExpandedViewPos(y + mViewDelta); - } - } - - void performFling(int y, float vel, boolean always) { - mAnimatingReveal = false; - mDisplayHeight = mDisplay.getHeight(); - - mAnimY = y; - mAnimVel = vel; - - //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel); - - if (mExpanded) { - if (!always && ( - vel > 200.0f - || (y > (mDisplayHeight-25) && vel > -200.0f))) { - // We are expanded, but they didn't move sufficiently to cause - // us to retract. Animate back to the expanded position. - mAnimAccel = 2000.0f; - if (vel < 0) { - mAnimVel = 0; - } - } - else { - // We are expanded and are now going to animate away. - mAnimAccel = -2000.0f; - if (vel > 0) { - mAnimVel = 0; - } - } - } else { - if (always || ( - vel > 200.0f - || (y > (mDisplayHeight/2) && vel > -200.0f))) { - // We are collapsed, and they moved enough to allow us to - // expand. Animate in the notifications. - mAnimAccel = 2000.0f; - if (vel < 0) { - mAnimVel = 0; - } - } - else { - // We are collapsed, but they didn't move sufficiently to cause - // us to retract. Animate back to the collapsed position. - mAnimAccel = -2000.0f; - if (vel > 0) { - mAnimVel = 0; - } - } - } - //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel - // + " mAnimAccel=" + mAnimAccel); - - long now = SystemClock.uptimeMillis(); - mAnimLastTime = now; - mCurAnimationTime = now + ANIM_FRAME_DURATION; - mAnimating = true; - mHandler.removeMessages(MSG_ANIMATE); - mHandler.removeMessages(MSG_ANIMATE_REVEAL); - mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE), mCurAnimationTime); - stopTracking(); - } - - boolean interceptTouchEvent(MotionEvent event) { - if (SPEW) { - Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled=" - + mDisabled); - } - - if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) { - return false; - } - - final int statusBarSize = mStatusBarView.getHeight(); - final int hitSize = statusBarSize*2; - if (event.getAction() == MotionEvent.ACTION_DOWN) { - final int y = (int)event.getRawY(); - - if (!mExpanded) { - mViewDelta = statusBarSize - y; - } else { - mTrackingView.getLocationOnScreen(mAbsPos); - mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y; - } - if ((!mExpanded && y < hitSize) || - (mExpanded && y > (mDisplay.getHeight()-hitSize))) { - - // We drop events at the edge of the screen to make the windowshade come - // down by accident less, especially when pushing open a device with a keyboard - // that rotates (like g1 and droid) - int x = (int)event.getRawX(); - final int edgeBorder = mEdgeBorder; - if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) { - prepareTracking(y, !mExpanded);// opening if we're not already fully visible - mVelocityTracker.addMovement(event); - } - } - } else if (mTracking) { - mVelocityTracker.addMovement(event); - final int minY = statusBarSize + mCloseView.getHeight(); - if (event.getAction() == MotionEvent.ACTION_MOVE) { - int y = (int)event.getRawY(); - if (mAnimatingReveal && y < minY) { - // nothing - } else { - mAnimatingReveal = false; - updateExpandedViewPos(y + mViewDelta); - } - } else if (event.getAction() == MotionEvent.ACTION_UP) { - mVelocityTracker.computeCurrentVelocity(1000); - - float yVel = mVelocityTracker.getYVelocity(); - boolean negative = yVel < 0; - - float xVel = mVelocityTracker.getXVelocity(); - if (xVel < 0) { - xVel = -xVel; - } - if (xVel > 150.0f) { - xVel = 150.0f; // limit how much we care about the x axis - } - - float vel = (float)Math.hypot(yVel, xVel); - if (negative) { - vel = -vel; - } - - performFling((int)event.getRawY(), vel, false); - } - - } - return false; - } - - private class Launcher implements View.OnClickListener { - private PendingIntent mIntent; - private String mPkg; - private String mTag; - private int mId; - - Launcher(PendingIntent intent, String pkg, String tag, int id) { - mIntent = intent; - mPkg = pkg; - mTag = tag; - mId = id; - } - - public void onClick(View v) { - try { - // The intent we are sending is for the application, which - // won't have permission to immediately start an activity after - // the user switches to home. We know it is safe to do at this - // point, so make sure new activity switches are now allowed. - ActivityManagerNative.getDefault().resumeAppSwitches(); - } catch (RemoteException e) { - } - - if (mIntent != null) { - int[] pos = new int[2]; - v.getLocationOnScreen(pos); - Intent overlay = new Intent(); - overlay.setSourceBounds( - new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight())); - try { - mIntent.send(StatusBarService.this, 0, overlay); - } catch (PendingIntent.CanceledException e) { - // the stack trace isn't very helpful here. Just log the exception message. - Slog.w(TAG, "Sending contentIntent failed: " + e); - } - } - - try { - mBarService.onNotificationClick(mPkg, mTag, mId); - } catch (RemoteException ex) { - // system process is dead if we're here. - } - - // close the shade if it was open - animateCollapse(); - - // If this click was on the intruder alert, hide that instead - mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER); - } - } - - private void tick(StatusBarNotification n) { - // Show the ticker if one is requested. Also don't do this - // until status bar window is attached to the window manager, - // because... well, what's the point otherwise? And trying to - // run a ticker without being attached will crash! - if (n.notification.tickerText != null && mStatusBarView.getWindowToken() != null) { - if (0 == (mDisabled & (StatusBarManager.DISABLE_NOTIFICATION_ICONS - | StatusBarManager.DISABLE_NOTIFICATION_TICKER))) { - mTicker.addEntry(n); - } - } - } - - /** - * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService - * about the failure. - * - * WARNING: this will call back into us. Don't hold any locks. - */ - void handleNotificationError(IBinder key, StatusBarNotification n, String message) { - removeNotification(key); - try { - mBarService.onNotificationError(n.pkg, n.tag, n.id, n.uid, n.initialPid, message); - } catch (RemoteException ex) { - // The end is nigh. - } - } - - private class MyTicker extends Ticker { - MyTicker(Context context, StatusBarView sb) { - super(context, sb); - } - - @Override - void tickerStarting() { - mTicking = true; - mIcons.setVisibility(View.GONE); - mTickerView.setVisibility(View.VISIBLE); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_up_in, null)); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_up_out, null)); - if (mExpandedVisible) { - setDateViewVisibility(false, com.android.internal.R.anim.push_up_out); - } - } - - @Override - void tickerDone() { - mIcons.setVisibility(View.VISIBLE); - mTickerView.setVisibility(View.GONE); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.push_down_in, null)); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.push_down_out, - mTickingDoneListener)); - if (mExpandedVisible) { - setDateViewVisibility(true, com.android.internal.R.anim.push_down_in); - } - } - - void tickerHalting() { - mIcons.setVisibility(View.VISIBLE); - mTickerView.setVisibility(View.GONE); - mIcons.startAnimation(loadAnim(com.android.internal.R.anim.fade_in, null)); - mTickerView.startAnimation(loadAnim(com.android.internal.R.anim.fade_out, - mTickingDoneListener)); - if (mExpandedVisible) { - setDateViewVisibility(true, com.android.internal.R.anim.fade_in); - } - } - } - - Animation.AnimationListener mTickingDoneListener = new Animation.AnimationListener() {; - public void onAnimationEnd(Animation animation) { - mTicking = false; - } - public void onAnimationRepeat(Animation animation) { - } - public void onAnimationStart(Animation animation) { - } - }; - - private Animation loadAnim(int id, Animation.AnimationListener listener) { - Animation anim = AnimationUtils.loadAnimation(StatusBarService.this, id); - if (listener != null) { - anim.setAnimationListener(listener); - } - return anim; - } - - public String viewInfo(View v) { - return "(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom() - + " " + v.getWidth() + "x" + v.getHeight() + ")"; - } - - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump StatusBar from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - synchronized (mQueueLock) { - pw.println("Current Status Bar state:"); - pw.println(" mExpanded=" + mExpanded - + ", mExpandedVisible=" + mExpandedVisible); - pw.println(" mTicking=" + mTicking); - pw.println(" mTracking=" + mTracking); - pw.println(" mAnimating=" + mAnimating - + ", mAnimY=" + mAnimY + ", mAnimVel=" + mAnimVel - + ", mAnimAccel=" + mAnimAccel); - pw.println(" mCurAnimationTime=" + mCurAnimationTime - + " mAnimLastTime=" + mAnimLastTime); - pw.println(" mDisplayHeight=" + mDisplayHeight - + " mAnimatingReveal=" + mAnimatingReveal - + " mViewDelta=" + mViewDelta); - pw.println(" mDisplayHeight=" + mDisplayHeight); - pw.println(" mExpandedParams: " + mExpandedParams); - pw.println(" mExpandedView: " + viewInfo(mExpandedView)); - pw.println(" mExpandedDialog: " + mExpandedDialog); - pw.println(" mTrackingParams: " + mTrackingParams); - pw.println(" mTrackingView: " + viewInfo(mTrackingView)); - pw.println(" mOngoingTitle: " + viewInfo(mOngoingTitle)); - pw.println(" mOngoingItems: " + viewInfo(mOngoingItems)); - pw.println(" mLatestTitle: " + viewInfo(mLatestTitle)); - pw.println(" mLatestItems: " + viewInfo(mLatestItems)); - pw.println(" mNoNotificationsTitle: " + viewInfo(mNoNotificationsTitle)); - pw.println(" mCloseView: " + viewInfo(mCloseView)); - pw.println(" mTickerView: " + viewInfo(mTickerView)); - pw.println(" mScrollView: " + viewInfo(mScrollView) - + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY()); - pw.println("mNotificationLinearLayout: " + viewInfo(mNotificationLinearLayout)); - } - /* - synchronized (mNotificationData) { - int N = mNotificationData.ongoingCount(); - pw.println(" ongoingCount.size=" + N); - for (int i=0; i<N; i++) { - StatusBarNotification n = mNotificationData.getOngoing(i); - pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); - pw.println(" data=" + n.data); - } - N = mNotificationData.latestCount(); - pw.println(" ongoingCount.size=" + N); - for (int i=0; i<N; i++) { - StatusBarNotification n = mNotificationData.getLatest(i); - pw.println(" [" + i + "] key=" + n.key + " view=" + n.view); - pw.println(" data=" + n.data); - } - } - */ - - if (false) { - pw.println("see the logcat for a dump of the views we have created."); - // must happen on ui thread - mHandler.post(new Runnable() { - public void run() { - mStatusBarView.getLocationOnScreen(mAbsPos); - Slog.d(TAG, "mStatusBarView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mStatusBarView.getWidth() + "x" - + mStatusBarView.getHeight()); - mStatusBarView.debug(); - - mExpandedView.getLocationOnScreen(mAbsPos); - Slog.d(TAG, "mExpandedView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mExpandedView.getWidth() + "x" - + mExpandedView.getHeight()); - mExpandedView.debug(); - - mTrackingView.getLocationOnScreen(mAbsPos); - Slog.d(TAG, "mTrackingView: ----- (" + mAbsPos[0] + "," + mAbsPos[1] - + ") " + mTrackingView.getWidth() + "x" - + mTrackingView.getHeight()); - mTrackingView.debug(); - } - }); - } - } - - void onBarViewAttached() { - WindowManager.LayoutParams lp; - int pixelFormat; - Drawable bg; - - /// ---------- Tracking View -------------- - pixelFormat = PixelFormat.RGBX_8888; - bg = mTrackingView.getBackground(); - if (bg != null) { - pixelFormat = bg.getOpacity(); - } - - lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - pixelFormat); -// lp.token = mStatusBarView.getWindowToken(); - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - lp.setTitle("TrackingView"); - lp.y = mTrackingPosition; - mTrackingParams = lp; - - WindowManagerImpl.getDefault().addView(mTrackingView, lp); - } - - void onTrackingViewAttached() { - WindowManager.LayoutParams lp; - int pixelFormat; - Drawable bg; - - /// ---------- Expanded View -------------- - pixelFormat = PixelFormat.TRANSLUCENT; - - final int disph = mDisplay.getHeight(); - lp = mExpandedDialog.getWindow().getAttributes(); - lp.width = ViewGroup.LayoutParams.MATCH_PARENT; - lp.height = getExpandedHeight(); - lp.x = 0; - mTrackingPosition = lp.y = -disph; // sufficiently large negative - lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; - lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_DITHER - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - lp.format = pixelFormat; - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - lp.setTitle("StatusBarExpanded"); - mExpandedDialog.getWindow().setAttributes(lp); - mExpandedDialog.getWindow().setFormat(pixelFormat); - mExpandedParams = lp; - - mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); - mExpandedDialog.setContentView(mExpandedView, - new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - mExpandedDialog.getWindow().setBackgroundDrawable(null); - mExpandedDialog.show(); - FrameLayout hack = (FrameLayout)mExpandedView.getParent(); - } - - void setDateViewVisibility(boolean visible, int anim) { - mDateView.setUpdates(visible); - mDateView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); - mDateView.startAnimation(loadAnim(anim, null)); - } - - void setNotificationIconVisibility(boolean visible, int anim) { - int old = mNotificationIcons.getVisibility(); - int v = visible ? View.VISIBLE : View.INVISIBLE; - if (old != v) { - mNotificationIcons.setVisibility(v); - mNotificationIcons.startAnimation(loadAnim(anim, null)); - } - } - - void updateExpandedViewPos(int expandedPosition) { - if (SPEW) { - Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition - + " mTrackingParams.y=" + mTrackingParams.y - + " mTrackingPosition=" + mTrackingPosition); - } - - int h = mStatusBarView.getHeight(); - int disph = mDisplay.getHeight(); - - // If the expanded view is not visible, make sure they're still off screen. - // Maybe the view was resized. - if (!mExpandedVisible) { - if (mTrackingView != null) { - mTrackingPosition = -disph; - if (mTrackingParams != null) { - mTrackingParams.y = mTrackingPosition; - WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams); - } - } - if (mExpandedParams != null) { - mExpandedParams.y = -disph; - mExpandedDialog.getWindow().setAttributes(mExpandedParams); - } - return; - } - - // tracking view... - int pos; - if (expandedPosition == EXPANDED_FULL_OPEN) { - pos = h; - } - else if (expandedPosition == EXPANDED_LEAVE_ALONE) { - pos = mTrackingPosition; - } - else { - if (expandedPosition <= disph) { - pos = expandedPosition; - } else { - pos = disph; - } - pos -= disph-h; - } - mTrackingPosition = mTrackingParams.y = pos; - mTrackingParams.height = disph-h; - WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams); - - if (mExpandedParams != null) { - mCloseView.getLocationInWindow(mPositionTmp); - final int closePos = mPositionTmp[1]; - - mExpandedContents.getLocationInWindow(mPositionTmp); - final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight(); - - mExpandedParams.y = pos + mTrackingView.getHeight() - - (mTrackingParams.height-closePos) - contentsBottom; - int max = h; - if (mExpandedParams.y > max) { - mExpandedParams.y = max; - } - int min = mTrackingPosition; - if (mExpandedParams.y < min) { - mExpandedParams.y = min; - } - - boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h; - if (!visible) { - // if the contents aren't visible, move the expanded view way off screen - // because the window itself extends below the content view. - mExpandedParams.y = -disph; - } - mExpandedDialog.getWindow().setAttributes(mExpandedParams); - - // As long as this isn't just a repositioning that's not supposed to affect - // the user's perception of what's showing, call to say that the visibility - // has changed. (Otherwise, someone else will call to do that). - if (expandedPosition != EXPANDED_LEAVE_ALONE) { - if (SPEW) Slog.d(TAG, "updateExpandedViewPos visibilityChanged(" + visible + ")"); - visibilityChanged(visible); - } - } - - if (SPEW) { - Slog.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition - + " mTrackingParams.y=" + mTrackingParams.y - + " mTrackingPosition=" + mTrackingPosition - + " mExpandedParams.y=" + mExpandedParams.y - + " mExpandedParams.height=" + mExpandedParams.height); - } - } - - int getExpandedHeight() { - return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight(); - } - - void updateExpandedHeight() { - if (mExpandedView != null) { - mExpandedParams.height = getExpandedHeight(); - mExpandedDialog.getWindow().setAttributes(mExpandedParams); - } - } - - /** - * The LEDs are turned o)ff when the notification panel is shown, even just a little bit. - * This was added last-minute and is inconsistent with the way the rest of the notifications - * are handled, because the notification isn't really cancelled. The lights are just - * turned off. If any other notifications happen, the lights will turn back on. Steve says - * this is what he wants. (see bug 1131461) - */ - void visibilityChanged(boolean visible) { - if (mPanelSlightlyVisible != visible) { - mPanelSlightlyVisible = visible; - try { - mBarService.onPanelRevealed(); - } catch (RemoteException ex) { - // Won't fail unless the world has ended. - } - } - } - - void performDisableActions(int net) { - int old = mDisabled; - int diff = net ^ old; - mDisabled = net; - - // act accordingly - if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) { - if ((net & StatusBarManager.DISABLE_EXPAND) != 0) { - Slog.d(TAG, "DISABLE_EXPAND: yes"); - animateCollapse(); - } - } - if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - if ((net & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes"); - if (mTicking) { - mNotificationIcons.setVisibility(View.INVISIBLE); - mTicker.halt(); - } else { - setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out); - } - } else { - Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no"); - if (!mExpandedVisible) { - setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in); - } - } - } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { - if (mTicking && (net & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) { - mTicker.halt(); - } - } - } - - private View.OnClickListener mClearButtonListener = new View.OnClickListener() { - public void onClick(View v) { - try { - mBarService.onClearAllNotifications(); - } catch (RemoteException ex) { - // system process is dead if we're here. - } - animateCollapse(); - } - }; - - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) - || Intent.ACTION_SCREEN_OFF.equals(action)) { - //collapse(); - } - else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { - updateResources(); - } - } - }; - - private void setIntruderAlertVisibility(boolean vis) { - mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE); - } - - /** - * Reload some of our resources when the configuration changes. - * - * We don't reload everything when the configuration changes -- we probably - * should, but getting that smooth is tough. Someday we'll fix that. In the - * meantime, just update the things that we know change. - */ - void updateResources() { - Resources res = getResources(); - - mClearButton.setText(getText(R.string.status_bar_clear_all_button)); - mOngoingTitle.setText(getText(R.string.status_bar_ongoing_events_title)); - mLatestTitle.setText(getText(R.string.status_bar_latest_events_title)); - mNoNotificationsTitle.setText(getText(R.string.status_bar_no_notifications_title)); - - mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); - - if (false) Slog.v(TAG, "updateResources"); - } - - // - // tracing - // - - void postStartTracing() { - mHandler.postDelayed(mStartTracing, 3000); - } - - void vibrate() { - android.os.Vibrator vib = (android.os.Vibrator)getSystemService(Context.VIBRATOR_SERVICE); - vib.vibrate(250); - } - - Runnable mStartTracing = new Runnable() { - public void run() { - vibrate(); - SystemClock.sleep(250); - Slog.d(TAG, "startTracing"); - android.os.Debug.startMethodTracing("/data/statusbar-traces/trace"); - mHandler.postDelayed(mStopTracing, 10000); - } - }; - - Runnable mStopTracing = new Runnable() { - public void run() { - android.os.Debug.stopMethodTracing(); - Slog.d(TAG, "stopTracing"); - vibrate(); - } - }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java index 57452af..20fc41f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarView.java @@ -35,13 +35,12 @@ public class StatusBarView extends FrameLayout { static final int DIM_ANIM_TIME = 400; - StatusBarService mService; + PhoneStatusBarService mService; boolean mTracking; int mStartX, mStartY; ViewGroup mNotificationIcons; ViewGroup mStatusIcons; View mDate; - View mButtonArea; FixedSizeDrawable mBackground; boolean mNightMode = false; @@ -65,8 +64,6 @@ public class StatusBarView extends FrameLayout { mBackground = new FixedSizeDrawable(mDate.getBackground()); mBackground.setFixedBounds(0, 0, 0, 0); mDate.setBackgroundDrawable(mBackground); - - mButtonArea = findViewById(R.id.buttons); } @Override @@ -101,7 +98,7 @@ public class StatusBarView extends FrameLayout { @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); - mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE); + mService.updateExpandedViewPos(PhoneStatusBarService.EXPANDED_LEAVE_ALONE); } @Override @@ -132,10 +129,6 @@ public class StatusBarView extends FrameLayout { mDate.layout(mDate.getLeft(), mDate.getTop(), newDateRight, mDate.getBottom()); mBackground.setFixedBounds(-mDate.getLeft(), -mDate.getTop(), (r-l), (b-t)); - - if (mButtonArea != null) { - mButtonArea.getHitRect(mButtonBounds); - } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java index 9108eee..c59eb6a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/TrackingView.java @@ -26,7 +26,7 @@ import android.widget.LinearLayout; public class TrackingView extends LinearLayout { final Display mDisplay; - StatusBarService mService; + PhoneStatusBarService mService; boolean mTracking; int mStartX, mStartY; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java new file mode 100644 index 0000000..7835d42 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationIconArea.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tablet; + +import android.content.Context; +import android.content.res.Resources; +import android.os.Handler; +import android.util.AttributeSet; +import android.util.Slog; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.ImageView; + +import com.android.systemui.R; + + +public class NotificationIconArea extends LinearLayout { + private static final String TAG = "NotificationIconArea"; + + MoreView mMoreView; + IconLayout mIconLayout; + DraggerView mDraggerView; + + public NotificationIconArea(Context context, AttributeSet attrs) { + super(context, attrs); + + mMoreView = new MoreView(context); + addView(mMoreView, new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + + mIconLayout = new IconLayout(context); + addView(mIconLayout, new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + + mDraggerView = new DraggerView(context); + addView(mDraggerView, new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + } + + class MoreView extends ImageView { + public MoreView(Context context) { + super(context); + setImageResource(R.drawable.stat_notify_more); + } + } + + class IconLayout extends LinearLayout { + public IconLayout(Context context) { + super(context); + } + } + + class DraggerView extends ImageView { + public DraggerView(Context context) { + super(context); + setImageResource(R.drawable.notification_dragger); + } + } +} + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java new file mode 100644 index 0000000..24d3c39 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBarService.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tablet; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.IBinder; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; + +import com.android.internal.statusbar.StatusBarIcon; +import com.android.internal.statusbar.StatusBarIconList; +import com.android.internal.statusbar.StatusBarNotification; + +import com.android.systemui.statusbar.*; +import com.android.systemui.R; + +public class TabletStatusBarService extends StatusBarService { + + View mStatusBarView; + NotificationIconArea mNotificationIconArea; + + int mIconSize; + + + @Override + public void onCreate() { + super.onCreate(); + } + + protected View makeStatusBarView() { + Resources res = getResources(); + + mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); + + final View sb = View.inflate(this, R.layout.status_bar, null); + mStatusBarView = sb; + + // the more notifications icon + mNotificationIconArea = (NotificationIconArea)sb.findViewById(R.id.notificationIcons); + + return sb; + } + + protected int getStatusBarGravity() { + return Gravity.BOTTOM | Gravity.FILL_HORIZONTAL; + } + + public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { + // TODO + } + + public void updateIcon(String slot, int index, int viewIndex, + StatusBarIcon old, StatusBarIcon icon) { + // TODO + } + + public void removeIcon(String slot, int index, int viewIndex) { + // TODO + } + + public void addNotification(IBinder key, StatusBarNotification notification) { + // TODO + } + + public void updateNotification(IBinder key, StatusBarNotification notification) { + // TODO + } + + public void removeNotification(IBinder key) { + // TODO + } + + public void disable(int state) { + // TODO + } + + public void animateExpand() { + // TODO + } + + public void animateCollapse() { + // TODO + } +} diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 8321473..070d1e8 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -284,7 +284,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mTitleView != null) { mTitleView.setText(title); } else if (mActionBar != null) { - mActionBar.setTitle(title); + mActionBar.setWindowTitle(title); } mTitle = title; } @@ -2334,7 +2334,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar); if (mActionBar != null && mActionBar.getTitle() == null) { - mActionBar.setTitle(mTitle); + mActionBar.setWindowTitle(mTitle); } } } diff --git a/libs/audioflinger/A2dpAudioInterface.cpp b/services/audioflinger/A2dpAudioInterface.cpp index 995e31c..995e31c 100644 --- a/libs/audioflinger/A2dpAudioInterface.cpp +++ b/services/audioflinger/A2dpAudioInterface.cpp diff --git a/libs/audioflinger/A2dpAudioInterface.h b/services/audioflinger/A2dpAudioInterface.h index 48154f9..48154f9 100644 --- a/libs/audioflinger/A2dpAudioInterface.h +++ b/services/audioflinger/A2dpAudioInterface.h diff --git a/libs/audioflinger/Android.mk b/services/audioflinger/Android.mk index 22ecc54..22ecc54 100644 --- a/libs/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk diff --git a/libs/audioflinger/AudioBufferProvider.h b/services/audioflinger/AudioBufferProvider.h index 81c5c39..81c5c39 100644 --- a/libs/audioflinger/AudioBufferProvider.h +++ b/services/audioflinger/AudioBufferProvider.h diff --git a/libs/audioflinger/AudioDumpInterface.cpp b/services/audioflinger/AudioDumpInterface.cpp index 6c11114..6c11114 100644 --- a/libs/audioflinger/AudioDumpInterface.cpp +++ b/services/audioflinger/AudioDumpInterface.cpp diff --git a/libs/audioflinger/AudioDumpInterface.h b/services/audioflinger/AudioDumpInterface.h index 814ce5f..814ce5f 100644 --- a/libs/audioflinger/AudioDumpInterface.h +++ b/services/audioflinger/AudioDumpInterface.h diff --git a/libs/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 97eb6c0..771d885 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -6068,11 +6068,4 @@ status_t AudioFlinger::onTransact( return BnAudioFlinger::onTransact(code, data, reply, flags); } -// ---------------------------------------------------------------------------- - -void AudioFlinger::instantiate() { - defaultServiceManager()->addService( - String16("media.audio_flinger"), new AudioFlinger()); -} - }; // namespace android diff --git a/libs/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 507c9ac..7013d76 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -31,10 +31,12 @@ #include <utils/Atomic.h> #include <utils/Errors.h> #include <utils/threads.h> -#include <binder/MemoryDealer.h> #include <utils/SortedVector.h> #include <utils/Vector.h> +#include <binder/BinderService.h> +#include <binder/MemoryDealer.h> + #include <hardware_legacy/AudioHardwareInterface.h> #include "AudioBufferProvider.h" @@ -58,10 +60,13 @@ class AudioResampler; static const nsecs_t kStandbyTimeInNsecs = seconds(3); -class AudioFlinger : public BnAudioFlinger +class AudioFlinger : + public BinderService<AudioFlinger>, + public BnAudioFlinger { + friend class BinderService<AudioFlinger>; public: - static void instantiate(); + static char const* getServiceName() { return "media.audio_flinger"; } virtual status_t dump(int fd, const Vector<String16>& args); diff --git a/libs/audioflinger/AudioHardwareGeneric.cpp b/services/audioflinger/AudioHardwareGeneric.cpp index d63c031..d63c031 100644 --- a/libs/audioflinger/AudioHardwareGeneric.cpp +++ b/services/audioflinger/AudioHardwareGeneric.cpp diff --git a/libs/audioflinger/AudioHardwareGeneric.h b/services/audioflinger/AudioHardwareGeneric.h index aa4e78d..aa4e78d 100644 --- a/libs/audioflinger/AudioHardwareGeneric.h +++ b/services/audioflinger/AudioHardwareGeneric.h diff --git a/libs/audioflinger/AudioHardwareInterface.cpp b/services/audioflinger/AudioHardwareInterface.cpp index 9a4a7f9..9a4a7f9 100644 --- a/libs/audioflinger/AudioHardwareInterface.cpp +++ b/services/audioflinger/AudioHardwareInterface.cpp diff --git a/libs/audioflinger/AudioHardwareStub.cpp b/services/audioflinger/AudioHardwareStub.cpp index d481150..d481150 100644 --- a/libs/audioflinger/AudioHardwareStub.cpp +++ b/services/audioflinger/AudioHardwareStub.cpp diff --git a/libs/audioflinger/AudioHardwareStub.h b/services/audioflinger/AudioHardwareStub.h index 06a29de..06a29de 100644 --- a/libs/audioflinger/AudioHardwareStub.h +++ b/services/audioflinger/AudioHardwareStub.h diff --git a/libs/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 8aaa325..8aaa325 100644 --- a/libs/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp diff --git a/libs/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index aee3e17..aee3e17 100644 --- a/libs/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp index 549d661..549d661 100644 --- a/libs/audioflinger/AudioPolicyManagerBase.cpp +++ b/services/audioflinger/AudioPolicyManagerBase.cpp diff --git a/libs/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index bb3905c..bb3905c 100644 --- a/libs/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp diff --git a/libs/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index a13d0bd..a13d0bd 100644 --- a/libs/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h diff --git a/libs/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp index 5dabacb..5dabacb 100644 --- a/libs/audioflinger/AudioResampler.cpp +++ b/services/audioflinger/AudioResampler.cpp diff --git a/libs/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h index 2dfac76..2dfac76 100644 --- a/libs/audioflinger/AudioResampler.h +++ b/services/audioflinger/AudioResampler.h diff --git a/libs/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp index 1d247bd..1d247bd 100644 --- a/libs/audioflinger/AudioResamplerCubic.cpp +++ b/services/audioflinger/AudioResamplerCubic.cpp diff --git a/libs/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h index b72b62a..b72b62a 100644 --- a/libs/audioflinger/AudioResamplerCubic.h +++ b/services/audioflinger/AudioResamplerCubic.h diff --git a/libs/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp index 9e5e254..9e5e254 100644 --- a/libs/audioflinger/AudioResamplerSinc.cpp +++ b/services/audioflinger/AudioResamplerSinc.cpp diff --git a/libs/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h index e6cb90b..e6cb90b 100644 --- a/libs/audioflinger/AudioResamplerSinc.h +++ b/services/audioflinger/AudioResamplerSinc.h diff --git a/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 87975af..87975af 100644 --- a/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/services/camera/libcameraservice/CameraHardwareStub.cpp index b3e0ee6..b3e0ee6 100644 --- a/camera/libcameraservice/CameraHardwareStub.cpp +++ b/services/camera/libcameraservice/CameraHardwareStub.cpp diff --git a/camera/libcameraservice/CameraHardwareStub.h b/services/camera/libcameraservice/CameraHardwareStub.h index d3427ba..d3427ba 100644 --- a/camera/libcameraservice/CameraHardwareStub.h +++ b/services/camera/libcameraservice/CameraHardwareStub.h diff --git a/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 10668a4..c786f94 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -192,11 +192,6 @@ sp<CameraService::Client> CameraService::getClientById(int cameraId) { return mClient[cameraId].promote(); } -void CameraService::instantiate() { - defaultServiceManager()->addService(String16("media.camera"), - new CameraService()); -} - status_t CameraService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // Permission checks diff --git a/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 8193e77..b0b2d7a 100644 --- a/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -19,6 +19,8 @@ #ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H +#include <binder/BinderService.h> + #include <camera/ICameraService.h> #include <camera/CameraHardwareInterface.h> @@ -30,11 +32,14 @@ namespace android { class MemoryHeapBase; class MediaPlayer; -class CameraService: public BnCameraService +class CameraService : + public BinderService<CameraService>, + public BnCameraService { class Client; + friend class BinderService<CameraService>; public: - static void instantiate(); + static char const* getServiceName() { return "media.camera"; } CameraService(); virtual ~CameraService(); diff --git a/camera/libcameraservice/CannedJpeg.h b/services/camera/libcameraservice/CannedJpeg.h index b6266fb..b6266fb 100644 --- a/camera/libcameraservice/CannedJpeg.h +++ b/services/camera/libcameraservice/CannedJpeg.h diff --git a/camera/libcameraservice/FakeCamera.cpp b/services/camera/libcameraservice/FakeCamera.cpp index f3a6a67..f3a6a67 100644 --- a/camera/libcameraservice/FakeCamera.cpp +++ b/services/camera/libcameraservice/FakeCamera.cpp diff --git a/camera/libcameraservice/FakeCamera.h b/services/camera/libcameraservice/FakeCamera.h index 724de20..724de20 100644 --- a/camera/libcameraservice/FakeCamera.h +++ b/services/camera/libcameraservice/FakeCamera.h diff --git a/camera/tests/CameraServiceTest/Android.mk b/services/camera/tests/CameraServiceTest/Android.mk index cf4e42f..cf4e42f 100644 --- a/camera/tests/CameraServiceTest/Android.mk +++ b/services/camera/tests/CameraServiceTest/Android.mk diff --git a/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp index 3c8d553..3c8d553 100644 --- a/camera/tests/CameraServiceTest/CameraServiceTest.cpp +++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp diff --git a/services/java/com/android/server/ViewServer.java b/services/java/com/android/server/ViewServer.java index 9c7db9b..b369f71 100644 --- a/services/java/com/android/server/ViewServer.java +++ b/services/java/com/android/server/ViewServer.java @@ -216,8 +216,11 @@ class ViewServer implements Runnable { class ViewServerWorker implements Runnable, WindowManagerService.WindowChangeListener { private Socket mClient; private boolean mNeedWindowListUpdate; + private boolean mNeedFocusedWindowUpdate; public ViewServerWorker(Socket client) { mClient = client; + mNeedWindowListUpdate = false; + mNeedFocusedWindowUpdate = false; } public void run() { @@ -285,20 +288,42 @@ class ViewServer implements Runnable { } } + public void focusChanged() { + synchronized(this) { + mNeedFocusedWindowUpdate = true; + notifyAll(); + } + } + private boolean windowManagerAutolistLoop() { mWindowManager.addWindowChangeListener(this); BufferedWriter out = null; try { out = new BufferedWriter(new OutputStreamWriter(mClient.getOutputStream())); while (!Thread.interrupted()) { + boolean needWindowListUpdate = false; + boolean needFocusedWindowUpdate = false; synchronized (this) { - while (!mNeedWindowListUpdate) { + while (!mNeedWindowListUpdate && !mNeedFocusedWindowUpdate) { wait(); } - mNeedWindowListUpdate = false; + if (mNeedWindowListUpdate) { + mNeedWindowListUpdate = false; + needWindowListUpdate = true; + } + if (mNeedFocusedWindowUpdate) { + mNeedFocusedWindowUpdate = false; + needFocusedWindowUpdate = true; + } + } + if(needWindowListUpdate) { + out.write("LIST UPDATE\n"); + out.flush(); + } + if(needFocusedWindowUpdate) { + out.write("FOCUS UPDATE\n"); + out.flush(); } - out.write("UPDATE\n"); - out.flush(); } } catch (Exception e) { Slog.w(LOG_TAG, "Connection error: ", e); diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index c986dcc..3475b2f 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -494,6 +494,7 @@ public class WindowManagerService extends IWindowManager.Stub public interface WindowChangeListener { public void windowsChanged(); + public void focusChanged(); } final Configuration mTempConfiguration = new Configuration(); @@ -4829,6 +4830,21 @@ public class WindowManagerService extends IWindowManager.Stub } } + private void notifyFocusChanged() { + WindowChangeListener[] windowChangeListeners; + synchronized(mWindowMap) { + if(mWindowChangeListeners.isEmpty()) { + return; + } + windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()]; + windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners); + } + int N = windowChangeListeners.length; + for(int i = 0; i < N; i++) { + windowChangeListeners[i].focusChanged(); + } + } + private WindowState findWindow(int hashCode) { if (hashCode == -1) { return getFocusedWindow(); @@ -7716,7 +7732,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int ENABLE_SCREEN = 16; public static final int APP_FREEZE_TIMEOUT = 17; public static final int SEND_NEW_CONFIGURATION = 18; - public static final int WINDOWS_CHANGED = 19; + public static final int REPORT_WINDOWS_CHANGE = 19; private Session mLastReportedHold; @@ -7768,6 +7784,7 @@ public class WindowManagerService extends IWindowManager.Stub // Ignore if process has died. } } + notifyFocusChanged(); } } break; @@ -8048,7 +8065,7 @@ public class WindowManagerService extends IWindowManager.Stub break; } - case WINDOWS_CHANGED: { + case REPORT_WINDOWS_CHANGE: { if (mWindowsChanged) { synchronized (mWindowMap) { mWindowsChanged = false; @@ -8279,8 +8296,8 @@ public class WindowManagerService extends IWindowManager.Stub } } if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) { - mH.removeMessages(H.WINDOWS_CHANGED); - mH.sendMessage(mH.obtainMessage(H.WINDOWS_CHANGED)); + mH.removeMessages(H.REPORT_WINDOWS_CHANGE); + mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE)); } } catch (RuntimeException e) { mInLayout = false; diff --git a/libs/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index a14bfb5..a14bfb5 100644 --- a/libs/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk diff --git a/libs/surfaceflinger/Barrier.h b/services/surfaceflinger/Barrier.h index 6f8507e..6f8507e 100644 --- a/libs/surfaceflinger/Barrier.h +++ b/services/surfaceflinger/Barrier.h diff --git a/libs/surfaceflinger/BlurFilter.cpp b/services/surfaceflinger/BlurFilter.cpp index 1ffbd5b..1ffbd5b 100644 --- a/libs/surfaceflinger/BlurFilter.cpp +++ b/services/surfaceflinger/BlurFilter.cpp diff --git a/libs/surfaceflinger/BlurFilter.h b/services/surfaceflinger/BlurFilter.h index 294db43..294db43 100644 --- a/libs/surfaceflinger/BlurFilter.h +++ b/services/surfaceflinger/BlurFilter.h diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index 2eac0a8..2eac0a8 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h index 66bf521..66bf521 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp index 1d09f84..1d09f84 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h index 8369bb8..8369bb8 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h diff --git a/libs/surfaceflinger/GLExtensions.cpp b/services/surfaceflinger/GLExtensions.cpp index 7f4f9fc..7f4f9fc 100644 --- a/libs/surfaceflinger/GLExtensions.cpp +++ b/services/surfaceflinger/GLExtensions.cpp diff --git a/libs/surfaceflinger/GLExtensions.h b/services/surfaceflinger/GLExtensions.h index bbb284e..bbb284e 100644 --- a/libs/surfaceflinger/GLExtensions.h +++ b/services/surfaceflinger/GLExtensions.h diff --git a/libs/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 758da4e..758da4e 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp diff --git a/libs/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e1d283b..e1d283b 100644 --- a/libs/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h diff --git a/libs/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index d5aa53f..d5aa53f 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp diff --git a/libs/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 4288cf7..4288cf7 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h diff --git a/libs/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp index 64a43c7..64a43c7 100644 --- a/libs/surfaceflinger/LayerBlur.cpp +++ b/services/surfaceflinger/LayerBlur.cpp diff --git a/libs/surfaceflinger/LayerBlur.h b/services/surfaceflinger/LayerBlur.h index 4c9ec64..4c9ec64 100644 --- a/libs/surfaceflinger/LayerBlur.h +++ b/services/surfaceflinger/LayerBlur.h diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp index 5f83636..5f83636 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/services/surfaceflinger/LayerBuffer.cpp diff --git a/libs/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h index 1c0bf83..1c0bf83 100644 --- a/libs/surfaceflinger/LayerBuffer.h +++ b/services/surfaceflinger/LayerBuffer.h diff --git a/libs/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index a1f339e..a1f339e 100644 --- a/libs/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp diff --git a/libs/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index f032314..f032314 100644 --- a/libs/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h diff --git a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 b/services/surfaceflinger/MODULE_LICENSE_APACHE2 index e69de29..e69de29 100644 --- a/libs/surfaceflinger/MODULE_LICENSE_APACHE2 +++ b/services/surfaceflinger/MODULE_LICENSE_APACHE2 diff --git a/libs/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index d668e88..d668e88 100644 --- a/libs/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp diff --git a/libs/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index 890f809..890f809 100644 --- a/libs/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 68e8f19..3167c4c 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -63,20 +63,6 @@ #define DISPLAY_COUNT 1 namespace android { - -// --------------------------------------------------------------------------- - -void SurfaceFlinger::instantiate() { - defaultServiceManager()->addService( - String16("SurfaceFlinger"), new SurfaceFlinger()); -} - -void SurfaceFlinger::shutdown() { - // we should unregister here, but not really because - // when (if) the service manager goes away, all the services - // it has a reference to will leave too. -} - // --------------------------------------------------------------------------- SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs) diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0bfc170..8821e5c 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -29,6 +29,7 @@ #include <binder/IMemory.h> #include <binder/Permission.h> +#include <binder/BinderService.h> #include <ui/PixelFormat.h> #include <surfaceflinger/ISurfaceComposer.h> @@ -167,11 +168,13 @@ enum { eTraversalNeeded = 0x02 }; -class SurfaceFlinger : public BnSurfaceComposer, protected Thread +class SurfaceFlinger : + public BinderService<SurfaceFlinger>, + public BnSurfaceComposer, + protected Thread { public: - static void instantiate(); - static void shutdown(); + static char const* getServiceName() { return "SurfaceFlinger"; } SurfaceFlinger(); virtual ~SurfaceFlinger(); diff --git a/libs/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp index 6526032..3b326df 100644 --- a/libs/surfaceflinger/TextureManager.cpp +++ b/services/surfaceflinger/TextureManager.cpp @@ -107,7 +107,6 @@ bool TextureManager::isSupportedYuvFormat(int format) { switch (format) { case HAL_PIXEL_FORMAT_YV12: - case HAL_PIXEL_FORMAT_YV16: return true; } return false; @@ -118,7 +117,6 @@ bool TextureManager::isYuvFormat(int format) switch (format) { // supported YUV formats case HAL_PIXEL_FORMAT_YV12: - case HAL_PIXEL_FORMAT_YV16: // Legacy/deprecated YUV formats case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: diff --git a/libs/surfaceflinger/TextureManager.h b/services/surfaceflinger/TextureManager.h index c7c14e7..c7c14e7 100644 --- a/libs/surfaceflinger/TextureManager.h +++ b/services/surfaceflinger/TextureManager.h diff --git a/libs/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp index 5e27cc9..5e27cc9 100644 --- a/libs/surfaceflinger/Transform.cpp +++ b/services/surfaceflinger/Transform.cpp diff --git a/libs/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h index 20fa11a..20fa11a 100644 --- a/libs/surfaceflinger/Transform.h +++ b/services/surfaceflinger/Transform.h diff --git a/libs/surfaceflinger/clz.cpp b/services/surfaceflinger/clz.cpp index 2456b86..2456b86 100644 --- a/libs/surfaceflinger/clz.cpp +++ b/services/surfaceflinger/clz.cpp diff --git a/libs/surfaceflinger/clz.h b/services/surfaceflinger/clz.h index 0ddf986..0ddf986 100644 --- a/libs/surfaceflinger/clz.h +++ b/services/surfaceflinger/clz.h diff --git a/libs/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk index 5053e7d..5053e7d 100644 --- a/libs/surfaceflinger/tests/Android.mk +++ b/services/surfaceflinger/tests/Android.mk diff --git a/libs/surfaceflinger/tests/overlays/Android.mk b/services/surfaceflinger/tests/overlays/Android.mk index 592b601..592b601 100644 --- a/libs/surfaceflinger/tests/overlays/Android.mk +++ b/services/surfaceflinger/tests/overlays/Android.mk diff --git a/libs/surfaceflinger/tests/overlays/overlays.cpp b/services/surfaceflinger/tests/overlays/overlays.cpp index c248a61..c248a61 100644 --- a/libs/surfaceflinger/tests/overlays/overlays.cpp +++ b/services/surfaceflinger/tests/overlays/overlays.cpp diff --git a/libs/surfaceflinger/tests/resize/Android.mk b/services/surfaceflinger/tests/resize/Android.mk index 24c2d01..24c2d01 100644 --- a/libs/surfaceflinger/tests/resize/Android.mk +++ b/services/surfaceflinger/tests/resize/Android.mk diff --git a/libs/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp index 127cca3..127cca3 100644 --- a/libs/surfaceflinger/tests/resize/resize.cpp +++ b/services/surfaceflinger/tests/resize/resize.cpp diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java index 68d01d4..3618c7b 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java @@ -336,6 +336,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout); intent.putExtra(TestShellActivity.TOTAL_TEST_COUNT, mTestCount); intent.putExtra(TestShellActivity.CURRENT_TEST_NUMBER, testNumber); + intent.putExtra(TestShellActivity.STOP_ON_REF_ERROR, true); activity.startActivity(intent); // Wait until done. diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 0a04712..bf66fae 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -179,6 +179,7 @@ public class TestShellActivity extends Activity implements LayoutTestController mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0); mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false); mSaveImagePath = intent.getStringExtra(SAVE_IMAGE); + mStopOnRefError = intent.getBooleanExtra(STOP_ON_REF_ERROR, false); setTitle("Test " + mCurrentTestNumber + " of " + mTotalTestCount); float ratio = (float)mCurrentTestNumber / mTotalTestCount; int progress = (int)(ratio * Window.PROGRESS_END); @@ -699,8 +700,8 @@ public class TestShellActivity extends Activity implements LayoutTestController // waiting for "notifyDone" signal to finish, then there's no point in waiting // anymore because the JS execution is already terminated at this point and a // "notifyDone" will never come out so it's just wasting time till timeout kicks in - if (msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:") - && mWaitUntilDone) { + if ((msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:")) + && mWaitUntilDone && mStopOnRefError) { Log.w(LOGTAG, "Terminating test case on uncaught ReferenceError or TypeError."); mHandler.postDelayed(new Runnable() { public void run() { @@ -857,6 +858,7 @@ public class TestShellActivity extends Activity implements LayoutTestController private boolean mGetDrawtime; private int mTotalTestCount; private int mCurrentTestNumber; + private boolean mStopOnRefError; // States private boolean mTimedOut; @@ -897,6 +899,7 @@ public class TestShellActivity extends Activity implements LayoutTestController static final String SAVE_IMAGE = "SaveImage"; static final String TOTAL_TEST_COUNT = "TestCount"; static final String CURRENT_TEST_NUMBER = "TestNumber"; + static final String STOP_ON_REF_ERROR = "StopOnReferenceError"; static final int DRAW_RUNS = 5; static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt"; diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index f13cfaf..cb894f1 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -87,6 +87,15 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + + <activity + android:name="RotationActivity" + android:label="_Rotation"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> </application> </manifest> diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/MultisamplingActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/MultisamplingActivity.java deleted file mode 100644 index 95b14aa..0000000 --- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/MultisamplingActivity.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.test.hwui; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.os.Bundle; -import android.util.Log; -import android.view.Gravity; -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.widget.FrameLayout; - -@SuppressWarnings({"UnusedDeclaration"}) -public class MultisamplingActivity extends Activity { - private static final String LOG_TAG = "HwUi"; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - DirtyBitmapView container = new DirtyBitmapView(this); - - ColorView color = new ColorView(this); - container.addView(color, new DirtyBitmapView.LayoutParams( - dipToPx(this, 100), dipToPx(this, 100), Gravity.CENTER)); - - AlphaAnimation a = new AlphaAnimation(1.0f, 0.0f); - a.setDuration(2000); - a.setRepeatCount(Animation.INFINITE); - a.setRepeatMode(Animation.REVERSE); - color.startAnimation(a); - - setContentView(container); - } - - @SuppressWarnings({"UnusedDeclaration"}) - static int dipToPx(Context c, int dip) { - return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f); - } - - static class ColorView extends View { - ColorView(Context c) { - super(c); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.drawRGB(0, 255, 0); - } - } - - static class DirtyBitmapView extends FrameLayout { - private final Paint mPaint; - - DirtyBitmapView(Context c) { - super(c); - mPaint = new Paint(); - } - - @Override - public void dispatchDraw(Canvas canvas) { - canvas.drawRGB(255, 255, 255); - - mPaint.setColor(0xffff0000); - canvas.drawRect(200.0f, 0.0f, 220.0f, 20.0f, mPaint); - - canvas.save(); - canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); - Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); - Log.d(LOG_TAG, "rejected = " + canvas.quickReject(100.0f, 100.0f, 110.0f, 110.0f, - Canvas.EdgeType.BW)); - Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f, - Canvas.EdgeType.BW)); - canvas.restore(); - - canvas.save(); - canvas.scale(2.0f, 2.0f); - canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); - Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); - Log.d(LOG_TAG, "rejected = " + canvas.quickReject(50.0f, 50.0f, 60.0f, 60.0f, - Canvas.EdgeType.BW)); - Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f, - Canvas.EdgeType.BW)); - canvas.restore(); - - canvas.save(); - canvas.translate(20.0f, 20.0f); - canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); - Log.d(LOG_TAG, "clipRect = " + canvas.getClipBounds()); - Log.d(LOG_TAG, "rejected = " + canvas.quickReject(80.0f, 80.0f, 90.0f, 90.0f, - Canvas.EdgeType.BW)); - Log.d(LOG_TAG, "rejected = " + canvas.quickReject(25.0f, 5.0f, 30.0f, 10.0f, - Canvas.EdgeType.BW)); - canvas.restore(); - - canvas.save(); - canvas.scale(2.0f, 2.0f); - canvas.clipRect(20.0f, 0.0f, 40.0f, 20.0f); - - mPaint.setColor(0xff00ff00); - canvas.drawRect(0.0f, 0.0f, 20.0f, 20.0f, mPaint); - - mPaint.setColor(0xff0000ff); - canvas.drawRect(20.0f, 0.0f, 40.0f, 20.0f, mPaint); - - canvas.restore(); - - final int restoreTo = canvas.save(); - canvas.saveLayerAlpha(0.0f, 100.0f, getWidth(), 150.0f, 127, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); - mPaint.setColor(0xff0000ff); - canvas.drawRect(0.0f, 100.0f, 40.0f, 150.0f, mPaint); - mPaint.setColor(0xff00ffff); - canvas.drawRect(40.0f, 100.0f, 140.0f, 150.0f, mPaint); - mPaint.setColor(0xffff00ff); - canvas.drawRect(140.0f, 100.0f, 240.0f, 150.0f, mPaint); - canvas.restoreToCount(restoreTo); - - super.dispatchDraw(canvas); - } - } -}
\ No newline at end of file diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java new file mode 100644 index 0000000..e629cb8 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/RotationActivity.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class RotationActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + DrawingView container = new DrawingView(this); + + setContentView(container); + } + + @SuppressWarnings({"UnusedDeclaration"}) + static int dipToPx(Context c, int dip) { + return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f); + } + + static class DrawingView extends View { + private final Paint mPaint; + + DrawingView(Context c) { + super(c); + mPaint = new Paint(); + mPaint.setAntiAlias(true); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.save(); + canvas.translate(dipToPx(getContext(), 400), dipToPx(getContext(), 200)); + canvas.rotate(45.0f); + canvas.drawRGB(255, 255, 255); + mPaint.setColor(0xffff0000); + canvas.drawRect(-80.0f, -80.0f, 80.0f, 80.0f, mPaint); + canvas.drawRect(0.0f, 0.0f, 220.0f, 220.0f, mPaint); + canvas.restore(); + } + } +} diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk index 6d606a9..135a633 100644 --- a/tools/layoutlib/Android.mk +++ b/tools/layoutlib/Android.mk @@ -52,13 +52,15 @@ include $(BUILD_SYSTEM)/base_rules.mk $(LOCAL_BUILT_MODULE): $(built_core_dep) \ $(built_framework_dep) \ $(built_layoutlib_create_jar) - @echo "host layoutlib_create: $@" - @mkdir -p $(dir $@) - @rm -f $@ + $(hide) echo "host layoutlib_create: $@" + $(hide) mkdir -p $(dir $@) + $(hide) rm -f $@ + $(hide) ls -l $(built_framework_classes) $(hide) java -jar $(built_layoutlib_create_jar) \ $@ \ $(built_core_classes) \ $(built_framework_classes) + $(hide) ls -l $(built_framework_classes) # |
