summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/ActivityThread.java10
-rw-r--r--core/java/android/app/WallpaperManager.java8
-rw-r--r--core/java/android/hardware/Camera.java77
-rw-r--r--core/java/android/hardware/SensorEvent.java23
-rw-r--r--core/java/android/net/DhcpInfoInternal.java25
-rw-r--r--core/java/android/net/DhcpStateMachine.java353
-rw-r--r--core/java/android/net/LinkProperties.java44
-rw-r--r--core/java/android/net/NetworkConfig.java10
-rw-r--r--core/java/android/net/NetworkStats.aidl19
-rw-r--r--core/java/android/net/NetworkStats.java158
-rw-r--r--core/java/android/net/NetworkUtils.java10
-rw-r--r--core/java/android/net/RouteInfo.aidl19
-rw-r--r--core/java/android/net/RouteInfo.java162
-rw-r--r--core/java/android/os/BatteryStats.java1
-rw-r--r--core/java/android/os/INetworkManagementService.aidl18
-rw-r--r--core/java/android/os/PowerManager.java33
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java4
-rw-r--r--core/java/android/util/NtpTrustedTime.java3
-rw-r--r--core/java/android/view/GLES20Canvas.java10
-rw-r--r--core/java/android/view/GLES20TextureLayer.java4
-rw-r--r--core/java/android/view/HardwareCanvas.java8
-rw-r--r--core/java/android/view/HardwareRenderer.java195
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/android/view/TextureView.java56
-rw-r--r--core/java/android/view/View.java36
-rw-r--r--core/java/android/view/ViewAncestor.java (renamed from core/java/android/view/ViewRoot.java)56
-rw-r--r--core/java/android/view/ViewDebug.java24
-rw-r--r--core/java/android/view/ViewGroup.java18
-rw-r--r--core/java/android/view/WindowManager.java6
-rw-r--r--core/java/android/view/WindowManagerImpl.java30
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java4
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java10
-rw-r--r--core/java/android/webkit/BrowserFrame.java4
-rw-r--r--core/java/android/webkit/WebView.java146
-rw-r--r--core/java/android/widget/AbsListView.java4
-rw-r--r--core/java/android/widget/LinearLayout.java9
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/java/android/widget/ZoomButtonsController.java10
-rw-r--r--core/java/com/android/internal/app/ActionBarImpl.java123
-rw-r--r--core/java/com/android/internal/util/Protocol.java1
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuPresenter.java18
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuView.java122
-rw-r--r--core/java/com/android/internal/view/menu/MenuBuilder.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuDialogHelper.java11
-rw-r--r--core/java/com/android/internal/widget/AbsActionBarView.java211
-rw-r--r--core/java/com/android/internal/widget/ActionBarContainer.java7
-rw-r--r--core/java/com/android/internal/widget/ActionBarContextView.java86
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java206
-rw-r--r--core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java8
-rw-r--r--core/jni/Android.mk3
-rw-r--r--core/jni/AndroidRuntime.cpp6
-rw-r--r--core/jni/android_hardware_Camera.cpp14
-rw-r--r--core/jni/android_net_NetUtils.cpp62
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp4
-rw-r--r--core/jni/android_util_Binder.cpp22
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp22
-rw-r--r--core/jni/android_view_TextureView.cpp50
-rw-r--r--core/jni/android_view_ViewAncestor.cpp (renamed from core/jni/android_view_ViewRoot.cpp)8
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp33
-rw-r--r--core/res/AndroidManifest.xml6
-rwxr-xr-xcore/res/res/drawable-hdpi/stat_sys_adb.pngbin703 -> 1302 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_adb.pngbin604 -> 806 bytes
-rw-r--r--core/res/res/drawable-nodpi/platlogo.pngbin83490 -> 65254 bytes
-rw-r--r--core/res/res/layout/action_bar_title_item.xml3
-rw-r--r--core/res/res/layout/screen_action_bar.xml2
-rw-r--r--core/res/res/layout/screen_action_bar_overlay.xml2
-rw-r--r--core/res/res/layout/status_bar_latest_event_content.xml60
-rw-r--r--core/res/res/layout/status_bar_latest_event_content_large_icon.xml50
-rw-r--r--core/res/res/values-ca/strings.xml2
-rw-r--r--core/res/res/values-de/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-ro/strings.xml4
-rw-r--r--core/res/res/values-sk/strings.xml2
-rw-r--r--core/res/res/values-zh-rTW/strings.xml2
-rwxr-xr-xcore/res/res/values/config.xml23
-rwxr-xr-xcore/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/styles.xml13
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java3
-rw-r--r--core/tests/coretests/src/android/net/LinkPropertiesTest.java33
-rw-r--r--core/tests/coretests/src/android/widget/focus/RequestFocusTest.java2
-rw-r--r--core/tests/coretests/src/android/widget/listview/ListViewHeight.java2
-rw-r--r--data/etc/platform.xml4
-rw-r--r--docs/html/guide/guide_toc.cs12
-rw-r--r--docs/html/guide/topics/admin/device-admin.jd210
-rw-r--r--docs/html/guide/topics/graphics/animation.jd2
-rw-r--r--docs/html/guide/topics/resources/menu-resource.jd8
-rw-r--r--docs/html/guide/topics/usb/accessory.jd461
-rw-r--r--docs/html/guide/topics/usb/host.jd443
-rw-r--r--docs/html/guide/topics/usb/index.jd67
-rw-r--r--[-rwxr-xr-x]docs/html/images/admin/device-admin-activate-prompt.pngbin38584 -> 92531 bytes
-rw-r--r--[-rwxr-xr-x]docs/html/images/admin/device-admin-app.pngbin31310 -> 296628 bytes
-rw-r--r--docs/html/images/usb-host-accessory.pngbin0 -> 47143 bytes
-rw-r--r--docs/html/index.jd18
-rw-r--r--docs/html/resources/dashboard/platform-versions.jd22
-rw-r--r--docs/html/resources/resources-data.js10
-rw-r--r--graphics/java/android/graphics/SurfaceTexture.java19
-rw-r--r--graphics/java/android/renderscript/RenderScript.java3
-rw-r--r--include/camera/Camera.h108
-rw-r--r--include/camera/CameraHardwareInterface.h266
-rw-r--r--include/camera/CameraParameters.h20
-rw-r--r--include/gui/SurfaceTextureClient.h20
-rw-r--r--include/media/mediametadataretriever.h1
-rw-r--r--include/media/mediaplayer.h3
-rw-r--r--include/media/stagefright/AACWriter.h75
-rw-r--r--include/media/stagefright/HardwareAPI.h2
-rw-r--r--include/media/stagefright/MediaDefs.h2
-rw-r--r--include/media/stagefright/MetaData.h3
-rw-r--r--include/private/opengles/gl_context.h16
-rw-r--r--include/surfaceflinger/Surface.h20
-rw-r--r--include/ui/FramebufferNativeWindow.h8
-rw-r--r--include/ui/GraphicBuffer.h12
-rw-r--r--include/ui/android_native_buffer.h49
-rw-r--r--include/ui/egl/android_natives.h402
-rw-r--r--libs/camera/CameraParameters.cpp3
-rw-r--r--libs/gui/Surface.cpp26
-rw-r--r--libs/gui/SurfaceTextureClient.cpp15
-rw-r--r--libs/gui/tests/SurfaceTextureClient_test.cpp18
-rw-r--r--libs/gui/tests/SurfaceTexture_test.cpp6
-rw-r--r--libs/gui/tests/Surface_test.cpp2
-rw-r--r--libs/hwui/Caches.h4
-rw-r--r--libs/hwui/DisplayListRenderer.cpp325
-rw-r--r--libs/hwui/DisplayListRenderer.h2
-rw-r--r--libs/hwui/Layer.h6
-rw-r--r--libs/hwui/LayerRenderer.cpp21
-rw-r--r--libs/hwui/LayerRenderer.h2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp119
-rw-r--r--libs/hwui/OpenGLRenderer.h7
-rw-r--r--libs/hwui/ProgramCache.cpp75
-rw-r--r--libs/hwui/ProgramCache.h12
-rw-r--r--libs/hwui/Vertex.h19
-rw-r--r--libs/rs/Android.mk11
-rw-r--r--libs/rs/driver/rsdCore.cpp21
-rw-r--r--libs/rs/driver/rsdGL.cpp11
-rw-r--r--libs/rs/driver/rsdGL.h5
-rw-r--r--libs/rs/driver/rsdMesh.cpp60
-rw-r--r--libs/rs/driver/rsdMesh.h32
-rw-r--r--libs/rs/driver/rsdMeshObj.cpp178
-rw-r--r--libs/rs/driver/rsdMeshObj.h63
-rw-r--r--libs/rs/driver/rsdProgram.cpp95
-rw-r--r--libs/rs/driver/rsdProgramFragment.h32
-rw-r--r--libs/rs/driver/rsdProgramVertex.h31
-rw-r--r--libs/rs/driver/rsdRuntimeMath.cpp2
-rw-r--r--libs/rs/driver/rsdRuntimeStubs.cpp2
-rw-r--r--libs/rs/driver/rsdShader.cpp468
-rw-r--r--libs/rs/driver/rsdShader.h104
-rw-r--r--libs/rs/driver/rsdShaderCache.cpp (renamed from libs/rs/rsShaderCache.cpp)78
-rw-r--r--libs/rs/driver/rsdShaderCache.h (renamed from libs/rs/rsShaderCache.h)61
-rw-r--r--libs/rs/driver/rsdVertexArray.cpp (renamed from libs/rs/rsVertexArray.cpp)48
-rw-r--r--libs/rs/driver/rsdVertexArray.h (renamed from libs/rs/rsVertexArray.h)39
-rw-r--r--libs/rs/rsContext.cpp23
-rw-r--r--libs/rs/rsContext.h6
-rw-r--r--libs/rs/rsFont.cpp29
-rw-r--r--libs/rs/rsFont.h4
-rw-r--r--libs/rs/rsMesh.cpp316
-rw-r--r--libs/rs/rsMesh.h64
-rw-r--r--libs/rs/rsProgram.cpp420
-rw-r--r--libs/rs/rsProgram.h81
-rw-r--r--libs/rs/rsProgramFragment.cpp106
-rw-r--r--libs/rs/rsProgramFragment.h5
-rw-r--r--libs/rs/rsProgramStore.h4
-rw-r--r--libs/rs/rsProgramVertex.cpp100
-rw-r--r--libs/rs/rsProgramVertex.h6
-rw-r--r--libs/rs/rsScriptC_LibGL.cpp16
-rw-r--r--libs/rs/rsType.h3
-rw-r--r--libs/rs/rs_hal.h22
-rw-r--r--libs/rs/rsg_generator.c11
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp20
-rw-r--r--libs/ui/GraphicBuffer.cpp8
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java7
-rw-r--r--media/java/android/media/MediaPlayer.java39
-rw-r--r--media/java/android/media/MediaScanner.java66
-rw-r--r--media/libmedia/MediaScanner.cpp7
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp27
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h3
-rw-r--r--media/libstagefright/AACWriter.cpp382
-rw-r--r--media/libstagefright/ACodec.cpp4
-rw-r--r--media/libstagefright/Android.mk2
-rw-r--r--media/libstagefright/AwesomePlayer.cpp70
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp38
-rw-r--r--media/libstagefright/MediaDefs.cpp2
-rw-r--r--media/libstagefright/NuCachedSource2.cpp5
-rw-r--r--media/libstagefright/OMXCodec.cpp4
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp14
-rw-r--r--media/libstagefright/TimedTextPlayer.cpp252
-rw-r--r--media/libstagefright/codecs/aacdec/AACDecoder.cpp17
-rw-r--r--media/libstagefright/codecs/aacenc/AACEncoder.cpp2
-rw-r--r--media/libstagefright/colorconversion/SoftwareRenderer.cpp2
-rw-r--r--media/libstagefright/include/AwesomePlayer.h42
-rw-r--r--media/libstagefright/include/TimedTextPlayer.h91
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp8
-rw-r--r--opengl/include/EGL/eglext.h2
-rw-r--r--opengl/java/com/google/android/gles_jni/EGLImpl.java18
-rw-r--r--opengl/libagl/TextureObjectManager.cpp2
-rw-r--r--opengl/libagl/TextureObjectManager.h4
-rw-r--r--opengl/libagl/egl.cpp29
-rw-r--r--opengl/libagl/texture.cpp12
-rw-r--r--opengl/libagl2/src/egl.cpp29
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_background.9.pngbin3233 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.pngbin0 -> 1262 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.pngbin0 -> 1139 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.pngbin0 -> 288 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/statusbar_background.9.pngbin0 -> 2846 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/status_bar_background.9.pngbin204 -> 0 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/statusbar_background.9.pngbin0 -> 2849 bytes
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml124
-rw-r--r--packages/SystemUI/res/layout/status_bar_notification_row.xml51
-rw-r--r--packages/SystemUI/res/layout/status_bar_tracking.xml13
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml21
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java4
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java44
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java174
-rw-r--r--services/camera/libcameraservice/Android.mk46
-rw-r--r--services/camera/libcameraservice/CameraHardwareInterface.h619
-rw-r--r--services/camera/libcameraservice/CameraService.cpp88
-rw-r--r--services/camera/libcameraservice/CameraService.h7
-rw-r--r--services/camera/tests/CameraServiceTest/CameraServiceTest.cpp8
-rw-r--r--services/input/InputWindow.h1
-rw-r--r--services/java/com/android/server/ConnectivityService.java39
-rw-r--r--services/java/com/android/server/NetworkManagementService.java74
-rw-r--r--services/java/com/android/server/ThrottleService.java14
-rw-r--r--services/java/com/android/server/WifiWatchdogService.java55
-rw-r--r--services/java/com/android/server/wm/ViewServer.java2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp37
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h13
-rw-r--r--services/surfaceflinger/TextureManager.cpp2
-rw-r--r--services/surfaceflinger/tests/surface/surface.cpp2
-rw-r--r--services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java28
-rw-r--r--telephony/java/com/android/internal/telephony/ApnContext.java18
-rw-r--r--telephony/java/com/android/internal/telephony/DataCallState.java5
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnection.java330
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionAc.java288
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionTracker.java170
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java1
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java44
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java1
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java394
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java274
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java101
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java5
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs2
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs14
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs2
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs8
-rw-r--r--wifi/java/android/net/wifi/WifiConfigStore.java61
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java278
254 files changed, 9573 insertions, 3633 deletions
diff --git a/Android.mk b/Android.mk
index 898d7e29d3f2..d462a3f4e873 100644
--- a/Android.mk
+++ b/Android.mk
@@ -422,6 +422,8 @@ web_docs_sample_code_flags := \
resources/samples/TicTacToeLib "TicTacToeLib" \
-samplecode $(sample_dir)/TicTacToeMain \
resources/samples/TicTacToeMain "TicTacToeMain" \
+ -samplecode $(sample_dir)/USB \
+ resources/samples/USB "USB" \
-samplecode $(sample_dir)/WeatherListWidget \
resources/samples/WeatherListWidget "Weather List Widget" \
-samplecode $(sample_dir)/Wiktionary \
diff --git a/api/current.txt b/api/current.txt
index a98ffae88899..a7f03683eb15 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21025,6 +21025,7 @@ package android.view {
public static abstract interface TextureView.SurfaceTextureListener {
method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture);
+ method public abstract void onSurfaceTextureSizeChanged(android.graphics.SurfaceTexture, int, int);
}
public class TouchDelegate {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4dfba913c778..79552bfc7c91 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -70,7 +70,7 @@ import android.view.HardwareRenderer;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewManager;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -728,7 +728,7 @@ public final class ActivityThread {
long dalvikFree = runtime.freeMemory() / 1024;
long dalvikAllocated = dalvikMax - dalvikFree;
long viewInstanceCount = ViewDebug.getViewInstanceCount();
- long viewRootInstanceCount = ViewDebug.getViewRootInstanceCount();
+ long viewRootInstanceCount = ViewDebug.getViewAncestorInstanceCount();
long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class);
long activityInstanceCount = Debug.countInstancesOfClass(Activity.class);
int globalAssetCount = AssetManager.getGlobalAssetCount();
@@ -843,7 +843,7 @@ public final class ActivityThread {
pw.println(" ");
pw.println(" Objects");
- printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRoots:",
+ printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewAncestors:",
viewRootInstanceCount);
printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
@@ -3918,7 +3918,7 @@ public final class ActivityThread {
sThreadLocal.set(this);
mSystemThread = system;
if (!system) {
- ViewRoot.addFirstDrawHandler(new Runnable() {
+ ViewAncestor.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();
}
@@ -3948,7 +3948,7 @@ public final class ActivityThread {
}
}
- ViewRoot.addConfigCallback(new ComponentCallbacks() {
+ ViewAncestor.addConfigCallback(new ComponentCallbacks() {
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mPackages) {
// We need to apply this change to the resources
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 13a8b78d4832..113c610d6782 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -38,7 +38,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -632,7 +632,7 @@ public class WallpaperManager {
public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
@@ -670,7 +670,7 @@ public class WallpaperManager {
int x, int y, int z, Bundle extras) {
try {
//Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewRoot.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
+ ViewAncestor.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
windowToken, action, x, y, z, extras, false);
//Log.v(TAG, "...app returning after sending offsets!");
} catch (RemoteException e) {
@@ -690,7 +690,7 @@ public class WallpaperManager {
*/
public void clearWallpaperOffsets(IBinder windowToken) {
try {
- ViewRoot.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ ViewAncestor.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
windowToken, -1, -1, -1, -1);
} catch (RemoteException e) {
// Ignore.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 49db72b40b41..9011f733235b 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1179,6 +1179,8 @@ public class Camera {
private static final String KEY_MAX_EXPOSURE_COMPENSATION = "max-exposure-compensation";
private static final String KEY_MIN_EXPOSURE_COMPENSATION = "min-exposure-compensation";
private static final String KEY_EXPOSURE_COMPENSATION_STEP = "exposure-compensation-step";
+ private static final String KEY_AUTO_EXPOSURE_LOCK = "auto-exposure-lock";
+ private static final String KEY_AUTO_EXPOSURE_LOCK_SUPPORTED = "auto-exposure-lock-supported";
private static final String KEY_METERING_AREAS = "metering-areas";
private static final String KEY_MAX_NUM_METERING_AREAS = "max-num-metering-areas";
private static final String KEY_ZOOM = "zoom";
@@ -1195,6 +1197,7 @@ public class Camera {
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
private static final String TRUE = "true";
+ private static final String FALSE = "false";
// Values for white balance settings.
public static final String WHITE_BALANCE_AUTO = "auto";
@@ -2463,6 +2466,80 @@ public class Camera {
}
/**
+ * Sets the auto-exposure lock state. Applications should check
+ * {@link #isAutoExposureLockSupported} before using this method.
+ *
+ * If set to true, the camera auto-exposure routine will pause until the
+ * lock is set to false. Exposure compensation settings changes will
+ * still take effect while auto-exposure is locked. Stopping preview
+ * with {@link #stopPreview()}, or triggering still image capture with
+ * {@link #takePicture(Camera.ShutterCallback, Camera.PictureCallback,
+ * Camera.PictureCallback)}, will automatically set the lock to
+ * false. However, the lock can be re-enabled before preview is
+ * re-started to keep the same AE parameters. Exposure compensation, in
+ * conjunction with re-enabling the AE lock after each still capture,
+ * can be used to capture an exposure-bracketed burst of images, for
+ * example. Auto-exposure state, including the lock state, will not be
+ * maintained after camera {@link #release()} is called. Locking
+ * auto-exposure after {@link #open()} but before the first call to
+ * {@link #startPreview()} will not allow the auto-exposure routine to
+ * run at all, and may result in severely over- or under-exposed images.
+ *
+ * The driver may also independently lock auto-exposure after auto-focus
+ * completes. If this is undesirable, be sure to always set the
+ * auto-exposure lock to false after the
+ * {@link AutoFocusCallback#onAutoFocus(boolean, Camera)} callback is
+ * received. The {@link #getAutoExposureLock()} method can be used after
+ * the callback to determine if the camera has locked auto-exposure
+ * independently.
+ *
+ * @param toggle new state of the auto-exposure lock. True means that
+ * auto-exposure is locked, false means that the auto-exposure
+ * routine is free to run normally.
+ *
+ * @hide
+ */
+ public void setAutoExposureLock(boolean toggle) {
+ set(KEY_AUTO_EXPOSURE_LOCK, toggle ? TRUE : FALSE);
+ }
+
+ /**
+ * Gets the state of the auto-exposure lock. Applications should check
+ * {@link #isAutoExposureLockSupported} before using this method. See
+ * {@link #setAutoExposureLock} for details about the lock.
+ *
+ * @return State of the auto-exposure lock. Returns true if
+ * auto-exposure is currently locked, and false otherwise. The
+ * auto-exposure lock may be independently enabled by the camera
+ * subsystem when auto-focus has completed. This method can be
+ * used after the {@link AutoFocusCallback#onAutoFocus(boolean,
+ * Camera)} callback to determine if the camera has locked AE.
+ *
+ * @see #setAutoExposureLock(boolean)
+ *
+ * @hide
+ */
+ public boolean getAutoExposureLock() {
+ String str = get(KEY_AUTO_EXPOSURE_LOCK);
+ return TRUE.equals(str);
+ }
+
+ /**
+ * Returns true if auto-exposure locking is supported. Applications
+ * should call this before trying to lock auto-exposure. See
+ * {@link #setAutoExposureLock} for details about the lock.
+ *
+ * @return true if auto-exposure lock is supported.
+ * @see #setAutoExposureLock(boolean)
+ *
+ * @hide
+ */
+ public boolean isAutoExposureLockSupported() {
+ String str = get(KEY_AUTO_EXPOSURE_LOCK_SUPPORTED);
+ return TRUE.equals(str);
+ }
+
+ /**
* Gets current zoom value. This also works when smooth zoom is in
* progress. Applications should check {@link #isZoomSupported} before
* using this method.
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 91f0098c7c10..b111b84ca337 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -204,6 +204,12 @@ public class SensorEvent {
* values[0]: Ambient light level in SI lux units
* </ul>
*
+ * <h4>{@link android.hardware.Sensor#TYPE_PRESSURE Sensor.TYPE_PRESSURE}:</h4>
+ * <ul>
+ * <p>
+ * values[0]: Atmospheric pressure in hPa (millibar)
+ * </ul>
+ *
* <h4>{@link android.hardware.Sensor#TYPE_PROXIMITY Sensor.TYPE_PROXIMITY}:
* </h4>
*
@@ -247,6 +253,23 @@ public class SensorEvent {
* <p>Elements of the rotation vector are unitless.
* The x,y, and z axis are defined in the same way as the acceleration
* sensor.</p>
+ * The reference coordinate system is defined as a direct orthonormal basis,
+ * where:
+ * </p>
+ *
+ * <ul>
+ * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
+ * the ground at the device's current location and roughly points East).</li>
+ * <li>Y is tangential to the ground at the device's current location and
+ * points towards the magnetic North Pole.</li>
+ * <li>Z points towards the sky and is perpendicular to the ground.</li>
+ * </ul>
+ *
+ * <p>
+ * <center><img src="../../../images/axis_globe.png"
+ * alt="World coordinate-system diagram." border="0" /></center>
+ * </p>
+ *
* <ul>
* <p>
* values[0]: x*sin(&#952/2)
diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java
index 73966692d03f..860da0a335a9 100644
--- a/core/java/android/net/DhcpInfoInternal.java
+++ b/core/java/android/net/DhcpInfoInternal.java
@@ -22,6 +22,8 @@ import android.util.Log;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
/**
* A simple object for retrieving the results of a DHCP request.
@@ -31,7 +33,6 @@ import java.net.UnknownHostException;
public class DhcpInfoInternal {
private final static String TAG = "DhcpInfoInternal";
public String ipAddress;
- public String gateway;
public int prefixLength;
public String dns1;
@@ -40,7 +41,14 @@ public class DhcpInfoInternal {
public String serverAddress;
public int leaseDuration;
+ private Collection<RouteInfo> routes;
+
public DhcpInfoInternal() {
+ routes = new ArrayList<RouteInfo>();
+ }
+
+ public void addRoute(RouteInfo routeInfo) {
+ routes.add(routeInfo);
}
private int convertToInt(String addr) {
@@ -58,7 +66,12 @@ public class DhcpInfoInternal {
public DhcpInfo makeDhcpInfo() {
DhcpInfo info = new DhcpInfo();
info.ipAddress = convertToInt(ipAddress);
- info.gateway = convertToInt(gateway);
+ for (RouteInfo route : routes) {
+ if (route.isDefaultRoute()) {
+ info.gateway = convertToInt(route.getGateway().getHostAddress());
+ break;
+ }
+ }
try {
InetAddress inetAddress = NetworkUtils.numericToInetAddress(ipAddress);
info.netmask = NetworkUtils.prefixLengthToNetmaskInt(prefixLength);
@@ -81,8 +94,8 @@ public class DhcpInfoInternal {
public LinkProperties makeLinkProperties() {
LinkProperties p = new LinkProperties();
p.addLinkAddress(makeLinkAddress());
- if (TextUtils.isEmpty(gateway) == false) {
- p.addGateway(NetworkUtils.numericToInetAddress(gateway));
+ for (RouteInfo route : routes) {
+ p.addRoute(route);
}
if (TextUtils.isEmpty(dns1) == false) {
p.addDns(NetworkUtils.numericToInetAddress(dns1));
@@ -98,8 +111,10 @@ public class DhcpInfoInternal {
}
public String toString() {
+ String routeString = "";
+ for (RouteInfo route : routes) routeString += route.toString() + " | ";
return "addr: " + ipAddress + "/" + prefixLength +
- " gateway: " + gateway +
+ " routes: " + routeString +
" dns: " + dns1 + "," + dns2 +
" dhcpServer: " + serverAddress +
" leaseDuration: " + leaseDuration;
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
new file mode 100644
index 000000000000..eaf087f43ab8
--- /dev/null
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.DhcpInfoInternal;
+import android.net.NetworkUtils;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * StateMachine that interacts with the native DHCP client and can talk to
+ * a controller that also needs to be a StateMachine
+ *
+ * The Dhcp state machine provides the following features:
+ * - Wakeup and renewal using the native DHCP client (which will not renew
+ * on its own when the device is in suspend state and this can lead to device
+ * holding IP address beyond expiry)
+ * - A notification right before DHCP request or renewal is started. This
+ * can be used for any additional setup before DHCP. For example, wifi sets
+ * BT-Wifi coex settings right before DHCP is initiated
+ *
+ * @hide
+ */
+public class DhcpStateMachine extends StateMachine {
+
+ private static final String TAG = "DhcpStateMachine";
+ private static final boolean DBG = false;
+
+
+ /* A StateMachine that controls the DhcpStateMachine */
+ private StateMachine mController;
+
+ private Context mContext;
+ private BroadcastReceiver mBroadcastReceiver;
+ private AlarmManager mAlarmManager;
+ private PendingIntent mDhcpRenewalIntent;
+ private PowerManager.WakeLock mDhcpRenewWakeLock;
+ private static final String WAKELOCK_TAG = "DHCP";
+
+ private static final int DHCP_RENEW = 0;
+ private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
+
+ private enum DhcpAction {
+ START,
+ RENEW
+ };
+
+ private String mInterfaceName;
+ private boolean mRegisteredForPreDhcpNotification = false;
+
+ private static final int BASE = Protocol.BASE_DHCP;
+
+ /* Commands from controller to start/stop DHCP */
+ public static final int CMD_START_DHCP = BASE + 1;
+ public static final int CMD_STOP_DHCP = BASE + 2;
+ public static final int CMD_RENEW_DHCP = BASE + 3;
+
+ /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+ public static final int CMD_PRE_DHCP_ACTION = BASE + 4;
+ /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+ * success/failure */
+ public static final int CMD_POST_DHCP_ACTION = BASE + 5;
+
+ /* Command from controller to indicate DHCP discovery/renewal can continue
+ * after pre DHCP action is complete */
+ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 6;
+
+ /* Message.arg1 arguments to CMD_POST_DHCP notification */
+ public static final int DHCP_SUCCESS = 1;
+ public static final int DHCP_FAILURE = 2;
+
+ private State mDefaultState = new DefaultState();
+ private State mStoppedState = new StoppedState();
+ private State mWaitBeforeStartState = new WaitBeforeStartState();
+ private State mRunningState = new RunningState();
+ private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
+
+ private DhcpStateMachine(Context context, StateMachine controller, String intf) {
+ super(TAG);
+
+ mContext = context;
+ mController = controller;
+ mInterfaceName = intf;
+
+ mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
+ mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
+
+ PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
+ mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ //DHCP renew
+ if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
+ //acquire a 40s wakelock to finish DHCP renewal
+ mDhcpRenewWakeLock.acquire(40000);
+ sendMessage(CMD_RENEW_DHCP);
+ }
+ };
+ mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
+
+ addState(mDefaultState);
+ addState(mStoppedState, mDefaultState);
+ addState(mWaitBeforeStartState, mDefaultState);
+ addState(mRunningState, mDefaultState);
+ addState(mWaitBeforeRenewalState, mDefaultState);
+
+ setInitialState(mStoppedState);
+ }
+
+ public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller,
+ String intf) {
+ DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
+ dsm.start();
+ return dsm;
+ }
+
+ /**
+ * This sends a notification right before DHCP request/renewal so that the
+ * controller can do certain actions before DHCP packets are sent out.
+ * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
+ * to indicate DHCP can continue
+ *
+ * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
+ * handling during Dhcp
+ */
+ public void registerForPreDhcpNotification() {
+ mRegisteredForPreDhcpNotification = true;
+ }
+
+ class DefaultState extends State {
+ @Override
+ public boolean processMessage(Message message) {
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_RENEW_DHCP:
+ Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
+ break;
+ case SM_QUIT_CMD:
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ //let parent kill the state machine
+ return NOT_HANDLED;
+ default:
+ Log.e(TAG, "Error! unhandled message " + message);
+ break;
+ }
+ return HANDLED;
+ }
+ }
+
+
+ class StoppedState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_START_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ /* Notify controller before starting DHCP */
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
+ transitionTo(mWaitBeforeStartState);
+ } else {
+ if (runDhcp(DhcpAction.START)) {
+ transitionTo(mRunningState);
+ }
+ }
+ break;
+ case CMD_STOP_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class WaitBeforeStartState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
+ if (runDhcp(DhcpAction.START)) {
+ transitionTo(mRunningState);
+ } else {
+ transitionTo(mStoppedState);
+ }
+ break;
+ case CMD_STOP_DHCP:
+ transitionTo(mStoppedState);
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ class RunningState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_STOP_DHCP:
+ mAlarmManager.cancel(mDhcpRenewalIntent);
+ if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+ Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+ }
+ transitionTo(mStoppedState);
+ break;
+ case CMD_RENEW_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ /* Notify controller before starting DHCP */
+ mController.sendMessage(CMD_PRE_DHCP_ACTION);
+ transitionTo(mWaitBeforeRenewalState);
+ } else {
+ if (!runDhcp(DhcpAction.RENEW)) {
+ transitionTo(mStoppedState);
+ }
+ }
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ }
+ return retValue;
+ }
+ }
+
+ class WaitBeforeRenewalState extends State {
+ @Override
+ public void enter() {
+ if (DBG) Log.d(TAG, getName() + "\n");
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ boolean retValue = HANDLED;
+ if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
+ switch (message.what) {
+ case CMD_STOP_DHCP:
+ mAlarmManager.cancel(mDhcpRenewalIntent);
+ if (!NetworkUtils.stopDhcp(mInterfaceName)) {
+ Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
+ }
+ transitionTo(mStoppedState);
+ break;
+ case CMD_PRE_DHCP_ACTION_COMPLETE:
+ if (runDhcp(DhcpAction.RENEW)) {
+ transitionTo(mRunningState);
+ } else {
+ transitionTo(mStoppedState);
+ }
+ break;
+ case CMD_START_DHCP:
+ //ignore
+ break;
+ default:
+ retValue = NOT_HANDLED;
+ break;
+ }
+ return retValue;
+ }
+ }
+
+ private boolean runDhcp(DhcpAction dhcpAction) {
+ boolean success = false;
+ DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
+
+ if (dhcpAction == DhcpAction.START) {
+ Log.d(TAG, "DHCP request on " + mInterfaceName);
+ success = NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal);
+ } else if (dhcpAction == DhcpAction.RENEW) {
+ Log.d(TAG, "DHCP renewal on " + mInterfaceName);
+ success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpInfoInternal);
+ }
+
+ if (success) {
+ Log.d(TAG, "DHCP succeeded on " + mInterfaceName);
+ //Do it a bit earlier than half the lease duration time
+ //to beat the native DHCP client and avoid extra packets
+ //48% for one hour lease time = 29 minutes
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() +
+ dhcpInfoInternal.leaseDuration * 480, //in milliseconds
+ mDhcpRenewalIntent);
+
+ mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpInfoInternal)
+ .sendToTarget();
+ } else {
+ Log.d(TAG, "DHCP failed on " + mInterfaceName + ": " +
+ NetworkUtils.getDhcpError());
+ NetworkUtils.stopDhcp(mInterfaceName);
+ mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
+ .sendToTarget();
+ }
+ return success;
+ }
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index e88292f50744..61acf2b841dd 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -54,7 +54,7 @@ public class LinkProperties implements Parcelable {
String mIfaceName;
private Collection<LinkAddress> mLinkAddresses;
private Collection<InetAddress> mDnses;
- private Collection<InetAddress> mGateways;
+ private Collection<RouteInfo> mRoutes;
private ProxyProperties mHttpProxy;
public LinkProperties() {
@@ -67,7 +67,7 @@ public class LinkProperties implements Parcelable {
mIfaceName = source.getInterfaceName();
mLinkAddresses = source.getLinkAddresses();
mDnses = source.getDnses();
- mGateways = source.getGateways();
+ mRoutes = source.getRoutes();
mHttpProxy = new ProxyProperties(source.getHttpProxy());
}
}
@@ -104,11 +104,11 @@ public class LinkProperties implements Parcelable {
return Collections.unmodifiableCollection(mDnses);
}
- public void addGateway(InetAddress gateway) {
- if (gateway != null) mGateways.add(gateway);
+ public void addRoute(RouteInfo route) {
+ if (route != null) mRoutes.add(route);
}
- public Collection<InetAddress> getGateways() {
- return Collections.unmodifiableCollection(mGateways);
+ public Collection<RouteInfo> getRoutes() {
+ return Collections.unmodifiableCollection(mRoutes);
}
public void setHttpProxy(ProxyProperties proxy) {
@@ -122,7 +122,7 @@ public class LinkProperties implements Parcelable {
mIfaceName = null;
mLinkAddresses = new ArrayList<LinkAddress>();
mDnses = new ArrayList<InetAddress>();
- mGateways = new ArrayList<InetAddress>();
+ mRoutes = new ArrayList<RouteInfo>();
mHttpProxy = null;
}
@@ -146,12 +146,12 @@ public class LinkProperties implements Parcelable {
for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
dns += "] ";
- String gateways = "Gateways: [";
- for (InetAddress gw : mGateways) gateways += gw.getHostAddress() + ",";
- gateways += "] ";
+ String routes = "Routes: [";
+ for (RouteInfo route : mRoutes) routes += route.toString() + ",";
+ routes += "] ";
String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
- return ifaceName + linkAddresses + gateways + dns + proxy;
+ return ifaceName + linkAddresses + routes + dns + proxy;
}
@@ -177,7 +177,7 @@ public class LinkProperties implements Parcelable {
boolean sameAddresses;
boolean sameDnses;
- boolean sameGateways;
+ boolean sameRoutes;
LinkProperties target = (LinkProperties) obj;
@@ -190,12 +190,12 @@ public class LinkProperties implements Parcelable {
sameDnses = (mDnses.size() == targetDnses.size()) ?
mDnses.containsAll(targetDnses) : false;
- Collection<InetAddress> targetGateways = target.getGateways();
- sameGateways = (mGateways.size() == targetGateways.size()) ?
- mGateways.containsAll(targetGateways) : false;
+ Collection<RouteInfo> targetRoutes = target.getRoutes();
+ sameRoutes = (mRoutes.size() == targetRoutes.size()) ?
+ mRoutes.containsAll(targetRoutes) : false;
return
- sameAddresses && sameDnses && sameGateways
+ sameAddresses && sameDnses && sameRoutes
&& TextUtils.equals(getInterfaceName(), target.getInterfaceName())
&& (getHttpProxy() == null ? target.getHttpProxy() == null :
getHttpProxy().equals(target.getHttpProxy()));
@@ -211,7 +211,7 @@ public class LinkProperties implements Parcelable {
return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
+ mLinkAddresses.size() * 31
+ mDnses.size() * 37
- + mGateways.size() * 41
+ + mRoutes.size() * 41
+ ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
}
@@ -231,9 +231,9 @@ public class LinkProperties implements Parcelable {
dest.writeByteArray(d.getAddress());
}
- dest.writeInt(mGateways.size());
- for(InetAddress gw : mGateways) {
- dest.writeByteArray(gw.getAddress());
+ dest.writeInt(mRoutes.size());
+ for(RouteInfo route : mRoutes) {
+ dest.writeParcelable(route, flags);
}
if (mHttpProxy != null) {
@@ -272,9 +272,7 @@ public class LinkProperties implements Parcelable {
}
addressCount = in.readInt();
for (int i=0; i<addressCount; i++) {
- try {
- netProp.addGateway(InetAddress.getByAddress(in.createByteArray()));
- } catch (UnknownHostException e) { }
+ netProp.addRoute((RouteInfo)in.readParcelable(null));
}
if (in.readByte() == 1) {
netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java
index 6e774a6f8640..3cc0bc5eae61 100644
--- a/core/java/android/net/NetworkConfig.java
+++ b/core/java/android/net/NetworkConfig.java
@@ -50,6 +50,13 @@ public class NetworkConfig {
public boolean dependencyMet;
/**
+ * indicates the default restoral timer in seconds
+ * if the network is used as a special network feature
+ * -1 indicates no restoration of default
+ */
+ public int restoreTime;
+
+ /**
* input string from config.xml resource. Uses the form:
* [Connection name],[ConnectivityManager connection type],
* [associated radio-type],[priority],[dependencyMet]
@@ -60,7 +67,8 @@ public class NetworkConfig {
type = Integer.parseInt(fragments[1]);
radio = Integer.parseInt(fragments[2]);
priority = Integer.parseInt(fragments[3]);
- dependencyMet = Boolean.parseBoolean(fragments[4]);
+ restoreTime = Integer.parseInt(fragments[4]);
+ dependencyMet = Boolean.parseBoolean(fragments[5]);
}
/**
diff --git a/core/java/android/net/NetworkStats.aidl b/core/java/android/net/NetworkStats.aidl
new file mode 100644
index 000000000000..d06ca65a3e0d
--- /dev/null
+++ b/core/java/android/net/NetworkStats.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkStats;
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
new file mode 100644
index 000000000000..4430e0005741
--- /dev/null
+++ b/core/java/android/net/NetworkStats.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+
+import java.io.CharArrayWriter;
+import java.io.PrintWriter;
+
+/**
+ * Collection of network statistics. Can contain summary details across all
+ * interfaces, or details with per-UID granularity. Designed to parcel quickly
+ * across process boundaries.
+ *
+ * @hide
+ */
+public class NetworkStats implements Parcelable {
+ /** {@link #iface} value when entry is summarized over all interfaces. */
+ public static final String IFACE_ALL = null;
+ /** {@link #uid} value when entry is summarized over all UIDs. */
+ public static final int UID_ALL = 0;
+
+ /**
+ * {@link SystemClock#elapsedRealtime()} timestamp when this data was
+ * generated.
+ */
+ public final long elapsedRealtime;
+ public final String[] iface;
+ public final int[] uid;
+ public final long[] rx;
+ public final long[] tx;
+
+ // TODO: add fg/bg stats and tag granularity
+
+ private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) {
+ this.elapsedRealtime = elapsedRealtime;
+ this.iface = iface;
+ this.uid = uid;
+ this.rx = rx;
+ this.tx = tx;
+ }
+
+ public NetworkStats(Parcel parcel) {
+ elapsedRealtime = parcel.readLong();
+ iface = parcel.createStringArray();
+ uid = parcel.createIntArray();
+ rx = parcel.createLongArray();
+ tx = parcel.createLongArray();
+ }
+
+ public static class Builder {
+ private long mElapsedRealtime;
+ private final String[] mIface;
+ private final int[] mUid;
+ private final long[] mRx;
+ private final long[] mTx;
+
+ private int mIndex = 0;
+
+ public Builder(long elapsedRealtime, int size) {
+ mElapsedRealtime = elapsedRealtime;
+ mIface = new String[size];
+ mUid = new int[size];
+ mRx = new long[size];
+ mTx = new long[size];
+ }
+
+ public void addEntry(String iface, int uid, long rx, long tx) {
+ mIface[mIndex] = iface;
+ mUid[mIndex] = uid;
+ mRx[mIndex] = rx;
+ mTx[mIndex] = tx;
+ mIndex++;
+ }
+
+ public NetworkStats build() {
+ if (mIndex != mIface.length) {
+ throw new IllegalArgumentException("unexpected number of entries");
+ }
+ return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx);
+ }
+ }
+
+ /**
+ * Find first stats index that matches the requested parameters.
+ */
+ public int findIndex(String iface, int uid) {
+ for (int i = 0; i < this.iface.length; i++) {
+ if (equal(iface, this.iface[i]) && uid == this.uid[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static boolean equal(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ return 0;
+ }
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix);
+ pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
+ for (int i = 0; i < iface.length; i++) {
+ pw.print(prefix);
+ pw.print(" iface="); pw.print(iface[i]);
+ pw.print(" uid="); pw.print(uid[i]);
+ pw.print(" rx="); pw.print(rx[i]);
+ pw.print(" tx="); pw.println(tx[i]);
+ }
+ }
+
+ @Override
+ public String toString() {
+ final CharArrayWriter writer = new CharArrayWriter();
+ dump("", new PrintWriter(writer));
+ return writer.toString();
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(elapsedRealtime);
+ dest.writeStringArray(iface);
+ dest.writeIntArray(uid);
+ dest.writeLongArray(rx);
+ dest.writeLongArray(tx);
+ }
+
+ public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+ public NetworkStats createFromParcel(Parcel in) {
+ return new NetworkStats(in);
+ }
+
+ public NetworkStats[] newArray(int size) {
+ return new NetworkStats[size];
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b3f39885f943..823d10fa6ba6 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -80,6 +80,16 @@ public class NetworkUtils {
public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
/**
+ * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
+ * a result (either success or failure) from the daemon.
+ * @param interfaceName the name of the interface to configure
+ * @param ipInfo if the request succeeds, this object is filled in with
+ * the IP address information.
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean runDhcpRenew(String interfaceName, DhcpInfoInternal ipInfo);
+
+ /**
* Shut down the DHCP client daemon.
* @param interfaceName the name of the interface for which the daemon
* should be stopped
diff --git a/core/java/android/net/RouteInfo.aidl b/core/java/android/net/RouteInfo.aidl
new file mode 100644
index 000000000000..2296a576873d
--- /dev/null
+++ b/core/java/android/net/RouteInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable RouteInfo;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
new file mode 100644
index 000000000000..5b1053140f06
--- /dev/null
+++ b/core/java/android/net/RouteInfo.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.UnknownHostException;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+/**
+ * A simple container for route information.
+ *
+ * @hide
+ */
+public class RouteInfo implements Parcelable {
+ /**
+ * The IP destination address for this route.
+ */
+ private final LinkAddress mDestination;
+
+ /**
+ * The gateway address for this route.
+ */
+ private final InetAddress mGateway;
+
+ private final boolean mIsDefault;
+
+ public RouteInfo(LinkAddress destination, InetAddress gateway) {
+ if (destination == null) {
+ try {
+ if ((gateway != null) && (gateway instanceof Inet4Address)) {
+ destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32);
+ } else {
+ destination = new LinkAddress(InetAddress.getByName("::0"), 128);
+ }
+ } catch (Exception e) {}
+ }
+ mDestination = destination;
+ mGateway = gateway;
+ mIsDefault = isDefault();
+ }
+
+ public RouteInfo(InetAddress gateway) {
+ LinkAddress destination = null;
+ try {
+ if ((gateway != null) && (gateway instanceof Inet4Address)) {
+ destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32);
+ } else {
+ destination = new LinkAddress(InetAddress.getByName("::0"), 128);
+ }
+ } catch (Exception e) {}
+ mDestination = destination;
+ mGateway = gateway;
+ mIsDefault = isDefault();
+ }
+
+ private boolean isDefault() {
+ boolean val = false;
+ if (mGateway != null) {
+ if (mGateway instanceof Inet4Address) {
+ val = (mDestination == null || mDestination.getNetworkPrefixLength() == 32);
+ } else {
+ val = (mDestination == null || mDestination.getNetworkPrefixLength() == 128);
+ }
+ }
+ return val;
+ }
+
+ public LinkAddress getDestination() {
+ return mDestination;
+ }
+
+ public InetAddress getGateway() {
+ return mGateway;
+ }
+
+ public boolean isDefaultRoute() {
+ return mIsDefault;
+ }
+
+ public String toString() {
+ String val = "";
+ if (mDestination != null) val = mDestination.toString();
+ if (mGateway != null) val += " -> " + mGateway.getHostAddress();
+ return val;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mDestination == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mDestination.getAddress().getAddress());
+ dest.writeInt(mDestination.getNetworkPrefixLength());
+ }
+
+ if (mGateway == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mGateway.getAddress());
+ }
+ }
+
+ public static final Creator<RouteInfo> CREATOR =
+ new Creator<RouteInfo>() {
+ public RouteInfo createFromParcel(Parcel in) {
+ InetAddress destAddr = null;
+ int prefix = 0;
+ InetAddress gateway = null;
+
+ if (in.readByte() == 1) {
+ byte[] addr = in.createByteArray();
+ prefix = in.readInt();
+
+ try {
+ destAddr = InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {}
+ }
+
+ if (in.readByte() == 1) {
+ byte[] addr = in.createByteArray();
+
+ try {
+ gateway = InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {}
+ }
+
+ LinkAddress dest = null;
+
+ if (destAddr != null) {
+ dest = new LinkAddress(destAddr, prefix);
+ }
+
+ return new RouteInfo(dest, gateway);
+ }
+
+ public RouteInfo[] newArray(int size) {
+ return new RouteInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b0f3ac3e23a4..e3441978df04 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2080,7 +2080,6 @@ public abstract class BatteryStats implements Parcelable {
final int NU = uidStats.size();
boolean didPid = false;
long nowRealtime = SystemClock.elapsedRealtime();
- StringBuilder sb = new StringBuilder(64);
for (int i=0; i<NU; i++) {
Uid uid = uidStats.valueAt(i);
SparseArray<? extends Uid.Pid> pids = uid.getPidStats();
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 212c5fb81e53..fe36786a43a8 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -19,6 +19,7 @@ package android.os;
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
import android.net.wifi.WifiConfiguration;
/**
@@ -65,7 +66,6 @@ interface INetworkManagementService
** TETHERING RELATED
**/
-
/**
* Returns true if IP forwarding is enabled
*/
@@ -181,17 +181,23 @@ interface INetworkManagementService
void setAccessPoint(in WifiConfiguration wifiConfig, String wlanIface, String softapIface);
/**
- * Read number of bytes sent over an interface
+ ** DATA USAGE RELATED
+ **/
+
+ /**
+ * Return global network statistics summarized at an interface level,
+ * without any UID-level granularity.
*/
- long getInterfaceTxCounter(String iface);
+ NetworkStats getNetworkStatsSummary();
/**
- * Read number of bytes received over an interface
+ * Return detailed network statistics with UID-level granularity,
+ * including interface and tag details.
*/
- long getInterfaceRxCounter(String iface);
+ NetworkStats getNetworkStatsDetail();
/**
- * Configures bandwidth throttling on an interface
+ * Configures bandwidth throttling on an interface.
*/
void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index c830f7a2d2a3..a17983a0fd37 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -261,16 +261,10 @@ public class PowerManager
public void acquire()
{
synchronized (mToken) {
- if (!mRefCounted || mCount++ == 0) {
- try {
- mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
- } catch (RemoteException e) {
- }
- mHeld = true;
- }
+ acquireLocked();
}
}
-
+
/**
* Makes sure the device is on at the level you asked when you created
* the wake lock. The lock will be released after the given timeout.
@@ -278,10 +272,22 @@ public class PowerManager
* @param timeout Release the lock after the give timeout in milliseconds.
*/
public void acquire(long timeout) {
- acquire();
- mHandler.postDelayed(mReleaser, timeout);
+ synchronized (mToken) {
+ acquireLocked();
+ mHandler.postDelayed(mReleaser, timeout);
+ }
}
+ private void acquireLocked() {
+ if (!mRefCounted || mCount++ == 0) {
+ mHandler.removeCallbacks(mReleaser);
+ try {
+ mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
+ } catch (RemoteException e) {
+ }
+ mHeld = true;
+ }
+ }
/**
* Release your claim to the CPU or screen being on.
@@ -290,8 +296,7 @@ public class PowerManager
* It may turn off shortly after you release it, or it may not if there
* are other wake locks held.
*/
- public void release()
- {
+ public void release() {
release(0);
}
@@ -306,9 +311,9 @@ public class PowerManager
*
* {@hide}
*/
- public void release(int flags)
- {
+ public void release(int flags) {
synchronized (mToken) {
+ mHandler.removeCallbacks(mReleaser);
if (!mRefCounted || --mCount == 0) {
try {
mService.releaseWakeLock(mToken, flags);
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 20661d76f741..eae7574c19c7 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -51,7 +51,7 @@ import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
@@ -650,7 +650,7 @@ public abstract class WallpaperService extends Service {
mWindowToken = wrapper.mWindowToken;
mSurfaceHolder.setSizeFromLayout();
mInitializing = true;
- mSession = ViewRoot.getWindowSession(getMainLooper());
+ mSession = ViewAncestor.getWindowSession(getMainLooper());
mWindow.setSession(mSession);
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 729c5064204e..5b19ecdb8b8a 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -45,7 +45,8 @@ public class NtpTrustedTime implements TrustedTime {
/** {@inheritDoc} */
public boolean forceRefresh() {
if (mNtpServer == null) {
- throw new IllegalStateException("Missing NTP server");
+ // missing server, so no trusted time available
+ return false;
}
final SntpClient client = new SntpClient();
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index cdf8954f5b2f..2b79a76bde45 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -163,8 +163,7 @@ class GLES20Canvas extends HardwareCanvas {
static native int nCreateTextureLayer(int[] layerInfo);
static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
- static native void nUpdateTextureLayer(int layerId, int width, int height,
- float[] textureTransform);
+ static native void nUpdateTextureLayer(int layerId, int width, int height, int surface);
static native void nDestroyLayer(int layerId);
static native void nDestroyLayerDeferred(int layerId);
@@ -262,6 +261,13 @@ class GLES20Canvas extends HardwareCanvas {
private static native boolean nDrawDisplayList(int renderer, int displayList,
int width, int height, Rect dirty);
+ @Override
+ void outputDisplayList(DisplayList displayList) {
+ nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+ }
+
+ private static native void nOutputDisplayList(int renderer, int displayList);
+
///////////////////////////////////////////////////////////////////////////
// Hardware layer
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index 21fbdfcf6af3..fcf421bbc3f2 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -70,7 +70,7 @@ class GLES20TextureLayer extends GLES20Layer {
return mSurface;
}
- void update(int width, int height, float[] textureTransform) {
- GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, textureTransform);
+ void update(int width, int height, int surface) {
+ GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, surface);
}
}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index caa7b743cd7e..23b3abcc3cd6 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -64,6 +64,14 @@ public abstract class HardwareCanvas extends Canvas {
abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
/**
+ * Outputs the specified display list to the log. This method exists for use by
+ * tools to output display lists for selected nodes to the log.
+ *
+ * @param displayList The display list to be logged.
+ */
+ abstract void outputDisplayList(DisplayList displayList);
+
+ /**
* Draws the specified layer onto this canvas.
*
* @param layer The layer to composite on this canvas
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 5b2983d548a1..845fbc3727bc 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -34,7 +34,7 @@ import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
/**
- * Interface for rendering a ViewRoot using hardware acceleration.
+ * Interface for rendering a ViewAncestor using hardware acceleration.
*
* @hide
*/
@@ -202,15 +202,14 @@ public abstract class HardwareRenderer {
* @param layer The hardware layer to update
* @param width The layer's width
* @param height The layer's height
- * @param textureTransform A 4x4 column-first transform matrix to apply to
- * texture coordinates
+ * @param surface The surface to update
*/
abstract void updateTextureLayer(HardwareLayer layer, int width, int height,
- float[] textureTransform);
+ SurfaceTexture surface);
/**
* Initializes the hardware renderer for the specified surface and setup the
- * renderer for drawing, if needed. This is invoked when the ViewRoot has
+ * renderer for drawing, if needed. This is invoked when the ViewAncestor has
* potentially lost the hardware renderer. The hardware renderer should be
* reinitialized and setup when the render {@link #isRequested()} and
* {@link #isEnabled()}.
@@ -289,9 +288,10 @@ public abstract class HardwareRenderer {
@SuppressWarnings({"deprecation"})
static abstract class GlRenderer extends HardwareRenderer {
// These values are not exposed in our EGL APIs
- private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- private static final int EGL_SURFACE_TYPE = 0x3033;
- private static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+ static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ static final int EGL_SURFACE_TYPE = 0x3033;
+ static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+ static final int EGL_OPENGL_ES2_BIT = 4;
private static final int SURFACE_STATE_ERROR = 0;
private static final int SURFACE_STATE_SUCCESS = 1;
@@ -459,13 +459,12 @@ public abstract class HardwareRenderer {
getEGLErrorString(sEgl.eglGetError()));
}
- sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+ sEglConfig = chooseEglConfig();
if (sEglConfig == null) {
// We tried to use EGL_SWAP_BEHAVIOR_PRESERVED_BIT, try again without
if (mDirtyRegions) {
mDirtyRegions = false;
-
- sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
+ sEglConfig = chooseEglConfig();
if (sEglConfig == null) {
throw new RuntimeException("eglConfig not initialized");
}
@@ -481,6 +480,21 @@ public abstract class HardwareRenderer {
sEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
}
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig(mDirtyRegions);
+ if (!sEgl.eglChooseConfig(sEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ getEGLErrorString(sEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ return configs[0];
+ }
+ return null;
+ }
+
+ abstract int[] getConfig(boolean dirtyRegions);
+
GL createEglSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException {
// Check preconditions.
if (sEgl == null) {
@@ -592,15 +606,6 @@ public abstract class HardwareRenderer {
void onPostDraw() {
}
-
- /**
- * Defines the EGL configuration for this renderer.
- *
- * @return An {@link android.view.HardwareRenderer.GlRenderer.EglConfigChooser}.
- */
- EglConfigChooser getConfigChooser(int glVersion) {
- return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0, mDirtyRegions);
- }
@Override
void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
@@ -713,134 +718,6 @@ public abstract class HardwareRenderer {
}
return SURFACE_STATE_SUCCESS;
}
-
- static abstract class EglConfigChooser {
- final int[] mConfigSpec;
- private final int mGlVersion;
-
- EglConfigChooser(int glVersion, int[] configSpec) {
- mGlVersion = glVersion;
- mConfigSpec = filterConfigSpec(configSpec);
- }
-
- EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
- int[] index = new int[1];
- if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, index)) {
- throw new IllegalArgumentException("eglChooseConfig failed "
- + getEGLErrorString(egl.eglGetError()));
- }
-
- int numConfigs = index[0];
- if (numConfigs <= 0) {
- throw new IllegalArgumentException("No configs match configSpec");
- }
-
- EGLConfig[] configs = new EGLConfig[numConfigs];
- if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, index)) {
- throw new IllegalArgumentException("eglChooseConfig failed "
- + getEGLErrorString(egl.eglGetError()));
- }
-
- EGLConfig config = chooseConfig(egl, display, configs);
- if (config == null) {
- throw new IllegalArgumentException("No config chosen");
- }
-
- return config;
- }
-
- abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
-
- private int[] filterConfigSpec(int[] configSpec) {
- if (mGlVersion != 2) {
- return configSpec;
- }
- /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
- * And we know the configSpec is well formed.
- */
- int len = configSpec.length;
- int[] newConfigSpec = new int[len + 2];
- System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
- newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
- newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
- newConfigSpec[len + 1] = EGL10.EGL_NONE;
- return newConfigSpec;
- }
- }
-
- /**
- * Choose a configuration with exactly the specified r,g,b,a sizes,
- * and at least the specified depth and stencil sizes.
- */
- static class ComponentSizeChooser extends EglConfigChooser {
- private int[] mValue;
-
- private final int mRedSize;
- private final int mGreenSize;
- private final int mBlueSize;
- private final int mAlphaSize;
- private final int mDepthSize;
- private final int mStencilSize;
- private final boolean mDirtyRegions;
-
- ComponentSizeChooser(int glVersion, int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize, boolean dirtyRegions) {
- super(glVersion, new int[] {
- EGL10.EGL_RED_SIZE, redSize,
- EGL10.EGL_GREEN_SIZE, greenSize,
- EGL10.EGL_BLUE_SIZE, blueSize,
- EGL10.EGL_ALPHA_SIZE, alphaSize,
- EGL10.EGL_DEPTH_SIZE, depthSize,
- EGL10.EGL_STENCIL_SIZE, stencilSize,
- EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
- (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
- EGL10.EGL_NONE });
- mValue = new int[1];
- mRedSize = redSize;
- mGreenSize = greenSize;
- mBlueSize = blueSize;
- mAlphaSize = alphaSize;
- mDepthSize = depthSize;
- mStencilSize = stencilSize;
- mDirtyRegions = dirtyRegions;
- }
-
- @Override
- EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
- for (EGLConfig config : configs) {
- int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
- int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
- if (d >= mDepthSize && s >= mStencilSize) {
- int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
- boolean backBuffer;
- if (mDirtyRegions) {
- int surfaceType = findConfigAttrib(egl, display, config,
- EGL_SURFACE_TYPE, 0);
- backBuffer = (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) != 0;
- } else {
- backBuffer = true;
- }
- if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize
- && backBuffer) {
- return config;
- }
- }
- }
- return null;
- }
-
- private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config,
- int attribute, int defaultValue) {
- if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
- return mValue[0];
- }
-
- return defaultValue;
- }
- }
}
/**
@@ -857,7 +734,23 @@ public abstract class HardwareRenderer {
GLES20Canvas createCanvas() {
return mGlCanvas = new GLES20Canvas(mTranslucent);
}
-
+
+ @Override
+ int[] getConfig(boolean dirtyRegions) {
+ return new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_STENCIL_SIZE, 0,
+ EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT |
+ (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
+ EGL10.EGL_NONE
+ };
+ }
+
@Override
boolean canDraw() {
return super.canDraw() && mGlCanvas != null;
@@ -906,8 +799,8 @@ public abstract class HardwareRenderer {
@Override
void updateTextureLayer(HardwareLayer layer, int width, int height,
- float[] textureTransform) {
- ((GLES20TextureLayer) layer).update(width, height, textureTransform);
+ SurfaceTexture surface) {
+ ((GLES20TextureLayer) layer).update(width, height, surface.mSurfaceTexture);
}
static HardwareRenderer create(boolean translucent) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 0a7a375de5eb..a98c669ed952 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -427,7 +427,7 @@ public class SurfaceView extends View {
if (!mHaveFrame) {
return;
}
- ViewRoot viewRoot = (ViewRoot) getRootView().getParent();
+ ViewAncestor viewRoot = (ViewAncestor) getRootView().getParent();
if (viewRoot != null) {
mTranslator = viewRoot.mTranslator;
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 6380e1b5c7bd..755ecf5a2c46 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -73,6 +73,10 @@ import android.util.Log;
* // Something bad happened
* }
* }
+ *
+ * public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ * // Ignored, Camera does all the work for us
+ * }
* }
* </pre>
*
@@ -90,8 +94,6 @@ public class TextureView extends View {
private HardwareLayer mLayer;
private SurfaceTexture mSurface;
private SurfaceTextureListener mListener;
-
- private final float[] mTextureTransform = new float[16];
private final Runnable mUpdateLayerAction = new Runnable() {
@Override
@@ -99,6 +101,7 @@ public class TextureView extends View {
updateLayer();
}
};
+ private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
/**
* Creates a new TextureView.
@@ -210,6 +213,14 @@ public class TextureView extends View {
}
@Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ if (mSurface != null) {
+ nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
+ }
+ }
+
+ @Override
HardwareLayer getHardwareLayer() {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
return null;
@@ -218,15 +229,17 @@ public class TextureView extends View {
if (mLayer == null) {
mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer();
mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer);
+ nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
- mSurface.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
+ mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
// Per SurfaceTexture's documentation, the callback may be invoked
// from an arbitrary thread
post(mUpdateLayerAction);
}
- });
+ };
+ mSurface.setOnFrameAvailableListener(mUpdateListener);
if (mListener != null) {
mListener.onSurfaceTextureAvailable(mSurface);
@@ -236,16 +249,29 @@ public class TextureView extends View {
return mLayer;
}
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+
+ if (mSurface != null) {
+ // When the view becomes invisible, stop updating it, it's a waste of CPU
+ // To cancel updates, the easiest thing to do is simply to remove the
+ // updates listener
+ if (visibility == VISIBLE) {
+ mSurface.setOnFrameAvailableListener(mUpdateListener);
+ updateLayer();
+ } else {
+ mSurface.setOnFrameAvailableListener(null);
+ }
+ }
+ }
+
private void updateLayer() {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
return;
}
- mSurface.updateTexImage();
- mSurface.getTransformMatrix(mTextureTransform);
-
- mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(),
- mTextureTransform);
+ mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), mSurface);
invalidate();
}
@@ -292,5 +318,17 @@ public class TextureView extends View {
* {@link android.view.TextureView#getSurfaceTexture()}
*/
public void onSurfaceTextureAvailable(SurfaceTexture surface);
+
+ /**
+ * Invoked when the {@link SurfaceTexture}'s buffers size changed.
+ *
+ * @param surface The surface returned by
+ * {@link android.view.TextureView#getSurfaceTexture()}
+ * @param width The new width of the surface
+ * @param height The new height of the surface
+ */
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
}
+
+ private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5af2e56bede3..e47b499c0fb5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4496,10 +4496,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
return true;
}
- /** Gets the ViewRoot, or null if not attached. */
- /*package*/ ViewRoot getViewRoot() {
+ /** Gets the ViewAncestor, or null if not attached. */
+ /*package*/ ViewAncestor getViewAncestor() {
View root = getRootView();
- return root != null ? (ViewRoot)root.getParent() : null;
+ return root != null ? (ViewAncestor)root.getParent() : null;
}
/**
@@ -4515,7 +4515,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
public final boolean requestFocusFromTouch() {
// Leave touch mode if we need to
if (isInTouchMode()) {
- ViewRoot viewRoot = getViewRoot();
+ ViewAncestor viewRoot = getViewAncestor();
if (viewRoot != null) {
viewRoot.ensureTouchMode(false);
}
@@ -5083,7 +5083,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (mAttachInfo != null) {
return mAttachInfo.mInTouchMode;
} else {
- return ViewRoot.isInTouchMode();
+ return ViewAncestor.isInTouchMode();
}
}
@@ -7311,7 +7311,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
if (p != null && ai != null && ai.mHardwareAccelerated) {
// fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewRoot to redraw everything
+ // with a null dirty rect, which tells the ViewAncestor to redraw everything
p.invalidateChild(this, null);
return;
}
@@ -7354,7 +7354,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
if (p != null && ai != null && ai.mHardwareAccelerated) {
// fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewRoot to redraw everything
+ // with a null dirty rect, which tells the ViewAncestor to redraw everything
p.invalidateChild(this, null);
return;
}
@@ -7409,7 +7409,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
if (p != null && ai != null && ai.mHardwareAccelerated) {
// fast-track for GL-enabled applications; just invalidate the whole hierarchy
- // with a null dirty rect, which tells the ViewRoot to redraw everything
+ // with a null dirty rect, which tells the ViewAncestor to redraw everything
p.invalidateChild(this, null);
return;
}
@@ -7558,7 +7558,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewRoot.getRunQueue().post(action);
+ ViewAncestor.getRunQueue().post(action);
return true;
}
@@ -7588,7 +7588,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewRoot.getRunQueue().postDelayed(action, delayMillis);
+ ViewAncestor.getRunQueue().postDelayed(action, delayMillis);
return true;
}
@@ -7612,7 +7612,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
handler = attachInfo.mHandler;
} else {
// Assume that post will succeed later
- ViewRoot.getRunQueue().removeCallbacks(action);
+ ViewAncestor.getRunQueue().removeCallbacks(action);
return true;
}
@@ -10593,9 +10593,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
viewParent = view.mParent;
}
- if (viewParent instanceof ViewRoot) {
+ if (viewParent instanceof ViewAncestor) {
// *cough*
- final ViewRoot vr = (ViewRoot)viewParent;
+ final ViewAncestor vr = (ViewAncestor)viewParent;
location[1] -= vr.mCurScrollY;
}
}
@@ -11405,7 +11405,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* therefore all View objects remove themselves from the global transparent
* region (passed as a parameter to this function).
*
- * @param region The transparent region for this ViewRoot (window).
+ * @param region The transparent region for this ViewAncestor (window).
*
* @return Returns true if the effective visibility of the view at this
* point is opaque, regardless of the transparent region; returns false
@@ -11711,7 +11711,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
surface.unlockCanvasAndPost(canvas);
}
- final ViewRoot root = getViewRoot();
+ final ViewAncestor root = getViewAncestor();
// Cache the local state object for delivery with DragEvents
root.setLocalDragState(myLocalState);
@@ -12497,7 +12497,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
boolean mScalingRequired;
/**
- * If set, ViewRoot doesn't use its lame animation for when the window resizes.
+ * If set, ViewAncestor doesn't use its lame animation for when the window resizes.
*/
boolean mTurnOffWindowResizeAnim;
@@ -12576,7 +12576,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
boolean mInTouchMode;
/**
- * Indicates that ViewRoot should trigger a global layout change
+ * Indicates that ViewAncestor should trigger a global layout change
* the next time it performs a traversal
*/
boolean mRecomputeGlobalAttributes;
@@ -12638,7 +12638,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
Canvas mCanvas;
/**
- * A Handler supplied by a view's {@link android.view.ViewRoot}. This
+ * A Handler supplied by a view's {@link android.view.ViewAncestor}. This
* handler can be used to pump events in the UI events queue.
*/
final Handler mHandler;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewAncestor.java
index f02dabac340d..8085ea8974e8 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -82,9 +82,9 @@ import java.util.ArrayList;
* {@hide}
*/
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewRoot extends Handler implements ViewParent,
+public final class ViewAncestor extends Handler implements ViewParent,
View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
- private static final String TAG = "ViewRoot";
+ private static final String TAG = "ViewAncestor";
private static final boolean DBG = false;
private static final boolean SHOW_FPS = false;
private static final boolean LOCAL_LOGV = false;
@@ -273,7 +273,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
- public ViewRoot(Context context) {
+ public ViewAncestor(Context context) {
super();
if (MEASURE_LATENCY) {
@@ -515,7 +515,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
// Only enable hardware acceleration if we are not in the system process
- // The window manager creates ViewRoots to display animated preview windows
+ // The window manager creates ViewAncestors to display animated preview windows
// of launching apps and we don't want those to be hardware accelerated
final boolean systemHwAccelerated =
@@ -1507,6 +1507,20 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
+ /**
+ * @hide
+ */
+ void outputDisplayList(View view) {
+ if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
+
+ HardwareCanvas canvas = (HardwareCanvas) mAttachInfo.mHardwareCanvas;
+ DisplayList displayList = view.getDisplayList();
+ if (displayList != null) {
+ canvas.outputDisplayList(displayList);
+ }
+ }
+ }
+
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (surface == null || !surface.isValid()) {
@@ -2038,7 +2052,7 @@ public final class ViewRoot extends Handler implements ViewParent,
break;
case DO_TRAVERSAL:
if (mProfile) {
- Debug.startMethodTracing("ViewRoot");
+ Debug.startMethodTracing("ViewAncestor");
}
final long traversalStartTime;
@@ -3546,7 +3560,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- // ViewRoot never intercepts touch event, so this can be a no-op
+ // ViewAncestor never intercepts touch event, so this can be a no-op
}
public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
@@ -3595,14 +3609,14 @@ public final class ViewRoot extends Handler implements ViewParent,
}
static class InputMethodCallback extends IInputMethodCallback.Stub {
- private WeakReference<ViewRoot> mViewRoot;
+ private WeakReference<ViewAncestor> mViewAncestor;
- public InputMethodCallback(ViewRoot viewRoot) {
- mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+ public InputMethodCallback(ViewAncestor viewRoot) {
+ mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
}
public void finishedEvent(int seq, boolean handled) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchFinishedEvent(seq, handled);
}
@@ -3614,36 +3628,36 @@ public final class ViewRoot extends Handler implements ViewParent,
}
static class W extends IWindow.Stub {
- private final WeakReference<ViewRoot> mViewRoot;
+ private final WeakReference<ViewAncestor> mViewAncestor;
- W(ViewRoot viewRoot) {
- mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+ W(ViewAncestor viewRoot) {
+ mViewAncestor = new WeakReference<ViewAncestor>(viewRoot);
}
public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
boolean reportDraw, Configuration newConfig) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig);
}
}
public void dispatchAppVisibility(boolean visible) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchAppVisibility(visible);
}
}
public void dispatchGetNewSurface() {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchGetNewSurface();
}
}
public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.windowFocusChanged(hasFocus, inTouchMode);
}
@@ -3663,7 +3677,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
final View view = viewRoot.mView;
if (view != null) {
@@ -3694,7 +3708,7 @@ public final class ViewRoot extends Handler implements ViewParent,
}
public void closeSystemDialogs(String reason) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchCloseSystemDialogs(reason);
}
@@ -3722,7 +3736,7 @@ public final class ViewRoot extends Handler implements ViewParent,
/* Drag/drop */
public void dispatchDragEvent(DragEvent event) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchDragEvent(event);
}
@@ -3730,7 +3744,7 @@ public final class ViewRoot extends Handler implements ViewParent,
@Override
public void dispatchSystemUiVisibilityChanged(int visibility) {
- final ViewRoot viewRoot = mViewRoot.get();
+ final ViewAncestor viewRoot = mViewAncestor.get();
if (viewRoot != null) {
viewRoot.dispatchSystemUiVisibilityChanged(visibility);
}
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 881cb7682b92..153409961550 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -375,6 +375,7 @@ public class ViewDebug {
private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
private static final String REMOTE_PROFILE = "PROFILE";
private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
+ private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
private static HashMap<Class<?>, Field[]> sFieldsForClasses;
private static HashMap<Class<?>, Method[]> sMethodsForClasses;
@@ -395,7 +396,7 @@ public class ViewDebug {
}
private static BufferedWriter sHierarchyTraces;
- private static ViewRoot sHierarhcyRoot;
+ private static ViewAncestor sHierarhcyRoot;
private static String sHierarchyTracePrefix;
/**
@@ -434,7 +435,7 @@ public class ViewDebug {
}
private static BufferedWriter sMotionEventTraces;
- private static ViewRoot sMotionEventRoot;
+ private static ViewAncestor sMotionEventRoot;
private static String sMotionEventTracePrefix;
/**
@@ -449,14 +450,14 @@ public class ViewDebug {
}
/**
- * Returns the number of instanciated ViewRoots.
+ * Returns the number of instanciated ViewAncestors.
*
- * @return The number of ViewRoots instanciated in the current process.
+ * @return The number of ViewAncestors instanciated in the current process.
*
* @hide
*/
- public static long getViewRootInstanceCount() {
- return Debug.countInstancesOfClass(ViewRoot.class);
+ public static long getViewAncestorInstanceCount() {
+ return Debug.countInstancesOfClass(ViewAncestor.class);
}
/**
@@ -670,7 +671,7 @@ public class ViewDebug {
return;
}
- sHierarhcyRoot = (ViewRoot) view.getRootView().getParent();
+ sHierarhcyRoot = (ViewAncestor) view.getRootView().getParent();
}
/**
@@ -808,7 +809,7 @@ public class ViewDebug {
return;
}
- sMotionEventRoot = (ViewRoot) view.getRootView().getParent();
+ sMotionEventRoot = (ViewAncestor) view.getRootView().getParent();
}
/**
@@ -885,6 +886,8 @@ public class ViewDebug {
final String[] params = parameters.split(" ");
if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
capture(view, clientStream, params[0]);
+ } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
+ outputDisplayList(view, params[0]);
} else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
invalidate(view, params[0]);
} else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
@@ -1156,6 +1159,11 @@ public class ViewDebug {
}
}
+ private static void outputDisplayList(View root, String parameter) throws IOException {
+ final View view = findView(root, parameter);
+ view.getViewAncestor().outputDisplayList(view);
+ }
+
private static void capture(View root, final OutputStream clientStream, String parameter)
throws IOException {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1a84175a630e..7b8242df0474 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -536,7 +536,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// note: knowing that mFocused is non-null is not a good enough reason
// to break the traversal since in that case we'd actually have to find
// the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
- // an ancestor of v; this will get checked for at ViewRoot
+ // an ancestor of v; this will get checked for at ViewAncestor
&& !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
mParent.focusableViewAvailable(v);
}
@@ -936,7 +936,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final float tx = event.mX;
final float ty = event.mY;
- ViewRoot root = getViewRoot();
+ ViewAncestor root = getViewAncestor();
// Dispatch down the view hierarchy
switch (event.mAction) {
@@ -3828,13 +3828,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRoot) {
- ((ViewRoot) parent).mIsAnimating = true;
+ } else if (parent instanceof ViewAncestor) {
+ ((ViewAncestor) parent).mIsAnimating = true;
}
}
- if (parent instanceof ViewRoot) {
- ((ViewRoot) parent).invalidate();
+ if (parent instanceof ViewAncestor) {
+ ((ViewAncestor) parent).invalidate();
parent = null;
} else if (view != null) {
if ((view.mPrivateFlags & DRAWN) == DRAWN ||
@@ -3889,8 +3889,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= DRAW_ANIMATION;
- } else if (parent instanceof ViewRoot) {
- ((ViewRoot) parent).mIsAnimating = true;
+ } else if (parent instanceof ViewAncestor) {
+ ((ViewAncestor) parent).mIsAnimating = true;
}
}
@@ -4413,7 +4413,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// If this group is dirty, check that the parent is dirty as well
if ((mPrivateFlags & DIRTY_MASK) != 0) {
final ViewParent parent = getParent();
- if (parent != null && !(parent instanceof ViewRoot)) {
+ if (parent != null && !(parent instanceof ViewAncestor)) {
if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
result = false;
android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 8a18aaf7c7ce..9395d5cfef2a 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -388,6 +388,12 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
/**
+ * Window type: Navigation bar (when distinct from status bar)
+ * @hide
+ */
+ public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
+
+ /**
* End of types of system windows.
*/
public static final int LAST_SYSTEM_WINDOW = 2999;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 8336959d5c88..d7a309686d4d 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -111,7 +111,7 @@ public class WindowManagerImpl implements WindowManager {
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
- ViewRoot root;
+ ViewAncestor root;
View panelParentView = null;
synchronized (this) {
@@ -148,7 +148,7 @@ public class WindowManagerImpl implements WindowManager {
}
}
- root = new ViewRoot(view.getContext());
+ root = new ViewAncestor(view.getContext());
root.mAddNesting = 1;
view.setLayoutParams(wparams);
@@ -156,7 +156,7 @@ public class WindowManagerImpl implements WindowManager {
if (mViews == null) {
index = 1;
mViews = new View[1];
- mRoots = new ViewRoot[1];
+ mRoots = new ViewAncestor[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
@@ -164,7 +164,7 @@ public class WindowManagerImpl implements WindowManager {
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
old = mRoots;
- mRoots = new ViewRoot[index];
+ mRoots = new ViewAncestor[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
@@ -192,7 +192,7 @@ public class WindowManagerImpl implements WindowManager {
synchronized (this) {
int index = findViewLocked(view, true);
- ViewRoot root = mRoots[index];
+ ViewAncestor root = mRoots[index];
mParams[index] = wparams;
root.setLayoutParams(wparams, false);
}
@@ -207,14 +207,14 @@ public class WindowManagerImpl implements WindowManager {
}
throw new IllegalStateException("Calling with view " + view
- + " but the ViewRoot is attached to " + curView);
+ + " but the ViewAncestor is attached to " + curView);
}
}
public void removeViewImmediate(View view) {
synchronized (this) {
int index = findViewLocked(view, true);
- ViewRoot root = mRoots[index];
+ ViewAncestor root = mRoots[index];
View curView = root.getView();
root.mAddNesting = 0;
@@ -225,12 +225,12 @@ public class WindowManagerImpl implements WindowManager {
}
throw new IllegalStateException("Calling with view " + view
- + " but the ViewRoot is attached to " + curView);
+ + " but the ViewAncestor is attached to " + curView);
}
}
View removeViewLocked(int index) {
- ViewRoot root = mRoots[index];
+ ViewAncestor root = mRoots[index];
View view = root.getView();
// Don't really remove until we have matched all calls to add().
@@ -256,7 +256,7 @@ public class WindowManagerImpl implements WindowManager {
removeItem(tmpViews, mViews, index);
mViews = tmpViews;
- ViewRoot[] tmpRoots = new ViewRoot[count-1];
+ ViewAncestor[] tmpRoots = new ViewAncestor[count-1];
removeItem(tmpRoots, mRoots, index);
mRoots = tmpRoots;
@@ -281,7 +281,7 @@ public class WindowManagerImpl implements WindowManager {
//Log.i("foo", "@ " + i + " token " + mParams[i].token
// + " view " + mRoots[i].getView());
if (token == null || mParams[i].token == token) {
- ViewRoot root = mRoots[i];
+ ViewAncestor root = mRoots[i];
root.mAddNesting = 1;
//Log.i("foo", "Force closing " + root);
@@ -308,7 +308,7 @@ public class WindowManagerImpl implements WindowManager {
int count = mViews.length;
for (int i=0; i<count; i++) {
if (token == null || mParams[i].token == token) {
- ViewRoot root = mRoots[i];
+ ViewAncestor root = mRoots[i];
root.setStopped(stopped);
}
}
@@ -317,13 +317,13 @@ public class WindowManagerImpl implements WindowManager {
public WindowManager.LayoutParams getRootViewLayoutParameter(View view) {
ViewParent vp = view.getParent();
- while (vp != null && !(vp instanceof ViewRoot)) {
+ while (vp != null && !(vp instanceof ViewAncestor)) {
vp = vp.getParent();
}
if (vp == null) return null;
- ViewRoot vr = (ViewRoot)vp;
+ ViewAncestor vr = (ViewAncestor)vp;
int N = mRoots.length;
for (int i = 0; i < N; ++i) {
@@ -344,7 +344,7 @@ public class WindowManagerImpl implements WindowManager {
}
private View[] mViews;
- private ViewRoot[] mRoots;
+ private ViewAncestor[] mRoots;
private WindowManager.LayoutParams[] mParams;
private static void removeItem(Object[] dst, Object[] src, int index)
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index dd2d00de0ca7..b4303f4bec44 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -34,7 +34,7 @@ import android.util.LogPrinter;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
class ComposingText implements NoCopySpan {
}
@@ -501,7 +501,7 @@ public class BaseInputConnection implements InputConnection {
}
}
if (h != null) {
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
event));
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index eef2a33bb44d..27cbaf702457 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -41,7 +41,7 @@ import android.util.Printer;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -636,7 +636,7 @@ public final class InputMethodManager {
if (vh != null) {
// This will result in a call to reportFinishInputConnection()
// below.
- vh.sendMessage(vh.obtainMessage(ViewRoot.FINISH_INPUT_CONNECTION,
+ vh.sendMessage(vh.obtainMessage(ViewAncestor.FINISH_INPUT_CONNECTION,
mServedInputConnection));
}
}
@@ -1093,9 +1093,9 @@ public final class InputMethodManager {
void scheduleCheckFocusLocked(View view) {
Handler vh = view.getHandler();
- if (vh != null && !vh.hasMessages(ViewRoot.CHECK_FOCUS)) {
+ if (vh != null && !vh.hasMessages(ViewAncestor.CHECK_FOCUS)) {
// This will result in a call to checkFocus() below.
- vh.sendMessage(vh.obtainMessage(ViewRoot.CHECK_FOCUS));
+ vh.sendMessage(vh.obtainMessage(ViewAncestor.CHECK_FOCUS));
}
}
@@ -1150,7 +1150,7 @@ public final class InputMethodManager {
}
/**
- * Called by ViewRoot when its window gets input focus.
+ * Called by ViewAncestor when its window gets input focus.
* @hide
*/
public void onWindowFocus(View rootView, View focusedView, int softInputMode,
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 6306274e34c6..9f2fd12c99ca 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -35,7 +35,7 @@ import android.os.Message;
import android.util.Log;
import android.util.TypedValue;
import android.view.Surface;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.WindowManager;
import junit.framework.Assert;
@@ -222,7 +222,7 @@ class BrowserFrame extends Handler {
sConfigCallback = new ConfigCallback(
(WindowManager) appContext.getSystemService(
Context.WINDOW_SERVICE));
- ViewRoot.addConfigCallback(sConfigCallback);
+ ViewAncestor.addConfigCallback(sConfigCallback);
}
sConfigCallback.addHandler(this);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index b5d049219e82..f99d89587d56 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -986,6 +986,7 @@ public class WebView extends AbsoluteLayout
protected WebView(Context context, AttributeSet attrs, int defStyle,
Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
super(context, attrs, defStyle);
+ checkThread();
// Used by the chrome stack to find application paths
JniUtil.setContext(context);
@@ -1138,7 +1139,7 @@ public class WebView extends AbsoluteLayout
PackageInfo pInfo = pm.getPackageInfo(name,
PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
installedPackages.add(name);
- } catch(PackageManager.NameNotFoundException e) {
+ } catch (PackageManager.NameNotFoundException e) {
// package not found
}
}
@@ -1309,6 +1310,7 @@ public class WebView extends AbsoluteLayout
* @param overlay TRUE if horizontal scrollbar should have overlay style.
*/
public void setHorizontalScrollbarOverlay(boolean overlay) {
+ checkThread();
mOverlayHorizontalScrollbar = overlay;
}
@@ -1317,6 +1319,7 @@ public class WebView extends AbsoluteLayout
* @param overlay TRUE if vertical scrollbar should have overlay style.
*/
public void setVerticalScrollbarOverlay(boolean overlay) {
+ checkThread();
mOverlayVerticalScrollbar = overlay;
}
@@ -1325,6 +1328,7 @@ public class WebView extends AbsoluteLayout
* @return TRUE if horizontal scrollbar has overlay style.
*/
public boolean overlayHorizontalScrollbar() {
+ checkThread();
return mOverlayHorizontalScrollbar;
}
@@ -1333,6 +1337,7 @@ public class WebView extends AbsoluteLayout
* @return TRUE if vertical scrollbar has overlay style.
*/
public boolean overlayVerticalScrollbar() {
+ checkThread();
return mOverlayVerticalScrollbar;
}
@@ -1364,6 +1369,7 @@ public class WebView extends AbsoluteLayout
* @deprecated This method is now obsolete.
*/
public int getVisibleTitleHeight() {
+ checkThread();
// need to restrict mScrollY due to over scroll
return Math.max(getTitleHeight() - Math.max(0, mScrollY), 0);
}
@@ -1390,6 +1396,7 @@ public class WebView extends AbsoluteLayout
* there is no certificate (the site is not secure).
*/
public SslCertificate getCertificate() {
+ checkThread();
return mCertificate;
}
@@ -1397,6 +1404,7 @@ public class WebView extends AbsoluteLayout
* Sets the SSL certificate for the main top-level page.
*/
public void setCertificate(SslCertificate certificate) {
+ checkThread();
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "setCertificate=" + certificate);
}
@@ -1416,6 +1424,7 @@ public class WebView extends AbsoluteLayout
* @param password The password for the given host.
*/
public void savePassword(String host, String username, String password) {
+ checkThread();
mDatabase.setUsernamePassword(host, username, password);
}
@@ -1430,6 +1439,7 @@ public class WebView extends AbsoluteLayout
*/
public void setHttpAuthUsernamePassword(String host, String realm,
String username, String password) {
+ checkThread();
mDatabase.setHttpAuthUsernamePassword(host, realm, username, password);
}
@@ -1443,6 +1453,7 @@ public class WebView extends AbsoluteLayout
* String[1] is password. Return null if it can't find anything.
*/
public String[] getHttpAuthUsernamePassword(String host, String realm) {
+ checkThread();
return mDatabase.getHttpAuthUsernamePassword(host, realm);
}
@@ -1475,6 +1486,11 @@ public class WebView extends AbsoluteLayout
* methods may be called on a WebView after destroy.
*/
public void destroy() {
+ checkThread();
+ destroyImpl();
+ }
+
+ private void destroyImpl() {
clearHelpers();
if (mListBoxDialog != null) {
mListBoxDialog.dismiss();
@@ -1511,6 +1527,7 @@ public class WebView extends AbsoluteLayout
* Enables platform notifications of data state and proxy changes.
*/
public static void enablePlatformNotifications() {
+ checkThread();
Network.enablePlatformNotifications();
}
@@ -1519,6 +1536,7 @@ public class WebView extends AbsoluteLayout
* from the Activity's onPause() or onStop().
*/
public static void disablePlatformNotifications() {
+ checkThread();
Network.disablePlatformNotifications();
}
@@ -1530,6 +1548,7 @@ public class WebView extends AbsoluteLayout
* @hide pending API solidification
*/
public void setJsFlags(String flags) {
+ checkThread();
mWebViewCore.sendMessage(EventHub.SET_JS_FLAGS, flags);
}
@@ -1540,6 +1559,7 @@ public class WebView extends AbsoluteLayout
* @param networkUp boolean indicating if network is available
*/
public void setNetworkAvailable(boolean networkUp) {
+ checkThread();
mWebViewCore.sendMessage(EventHub.SET_NETWORK_STATE,
networkUp ? 1 : 0, 0);
}
@@ -1549,6 +1569,7 @@ public class WebView extends AbsoluteLayout
* {@hide}
*/
public void setNetworkType(String type, String subtype) {
+ checkThread();
Map<String, String> map = new HashMap<String, String>();
map.put("type", type);
map.put("subtype", subtype);
@@ -1568,6 +1589,7 @@ public class WebView extends AbsoluteLayout
* @see #restorePicture
*/
public WebBackForwardList saveState(Bundle outState) {
+ checkThread();
if (outState == null) {
return null;
}
@@ -1622,6 +1644,7 @@ public class WebView extends AbsoluteLayout
* @return True if the picture was successfully saved.
*/
public boolean savePicture(Bundle b, final File dest) {
+ checkThread();
if (dest == null || b == null) {
return false;
}
@@ -1684,6 +1707,7 @@ public class WebView extends AbsoluteLayout
* @return True if the picture was successfully restored.
*/
public boolean restorePicture(Bundle b, File src) {
+ checkThread();
if (src == null || b == null) {
return false;
}
@@ -1736,6 +1760,7 @@ public class WebView extends AbsoluteLayout
* @see #restorePicture
*/
public WebBackForwardList restoreState(Bundle inState) {
+ checkThread();
WebBackForwardList returnList = null;
if (inState == null) {
return returnList;
@@ -1795,6 +1820,11 @@ public class WebView extends AbsoluteLayout
* will be replaced by the intrinsic value of the WebView.
*/
public void loadUrl(String url, Map<String, String> extraHeaders) {
+ checkThread();
+ loadUrlImpl(url, extraHeaders);
+ }
+
+ private void loadUrlImpl(String url, Map<String, String> extraHeaders) {
switchOutDrawHistory();
WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
arg.mUrl = url;
@@ -1808,10 +1838,15 @@ public class WebView extends AbsoluteLayout
* @param url The url of the resource to load.
*/
public void loadUrl(String url) {
+ checkThread();
+ loadUrlImpl(url);
+ }
+
+ private void loadUrlImpl(String url) {
if (url == null) {
return;
}
- loadUrl(url, null);
+ loadUrlImpl(url, null);
}
/**
@@ -1823,6 +1858,7 @@ public class WebView extends AbsoluteLayout
* @param postData The data will be passed to "POST" request.
*/
public void postUrl(String url, byte[] postData) {
+ checkThread();
if (URLUtil.isNetworkUrl(url)) {
switchOutDrawHistory();
WebViewCore.PostUrlData arg = new WebViewCore.PostUrlData();
@@ -1831,7 +1867,7 @@ public class WebView extends AbsoluteLayout
mWebViewCore.sendMessage(EventHub.POST_URL, arg);
clearHelpers();
} else {
- loadUrl(url);
+ loadUrlImpl(url);
}
}
@@ -1846,7 +1882,12 @@ public class WebView extends AbsoluteLayout
* @param encoding The encoding of the data. i.e. utf-8, base64
*/
public void loadData(String data, String mimeType, String encoding) {
- loadUrl("data:" + mimeType + ";" + encoding + "," + data);
+ checkThread();
+ loadDataImpl(data, mimeType, encoding);
+ }
+
+ private void loadDataImpl(String data, String mimeType, String encoding) {
+ loadUrlImpl("data:" + mimeType + ";" + encoding + "," + data);
}
/**
@@ -1872,9 +1913,10 @@ public class WebView extends AbsoluteLayout
*/
public void loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding, String historyUrl) {
+ checkThread();
if (baseUrl != null && baseUrl.toLowerCase().startsWith("data:")) {
- loadData(data, mimeType, encoding);
+ loadDataImpl(data, mimeType, encoding);
return;
}
switchOutDrawHistory();
@@ -1894,7 +1936,8 @@ public class WebView extends AbsoluteLayout
* @param filename The filename where the archive should be placed.
*/
public void saveWebArchive(String filename) {
- saveWebArchive(filename, false, null);
+ checkThread();
+ saveWebArchiveImpl(filename, false, null);
}
/* package */ static class SaveWebArchiveMessage {
@@ -1923,6 +1966,12 @@ public class WebView extends AbsoluteLayout
* file failed.
*/
public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
+ checkThread();
+ saveWebArchiveImpl(basename, autoname, callback);
+ }
+
+ private void saveWebArchiveImpl(String basename, boolean autoname,
+ ValueCallback<String> callback) {
mWebViewCore.sendMessage(EventHub.SAVE_WEBARCHIVE,
new SaveWebArchiveMessage(basename, autoname, callback));
}
@@ -1931,6 +1980,7 @@ public class WebView extends AbsoluteLayout
* Stop the current load.
*/
public void stopLoading() {
+ checkThread();
// TODO: should we clear all the messages in the queue before sending
// STOP_LOADING?
switchOutDrawHistory();
@@ -1941,6 +1991,7 @@ public class WebView extends AbsoluteLayout
* Reload the current url.
*/
public void reload() {
+ checkThread();
clearHelpers();
switchOutDrawHistory();
mWebViewCore.sendMessage(EventHub.RELOAD);
@@ -1951,6 +2002,7 @@ public class WebView extends AbsoluteLayout
* @return True iff this WebView has a back history item.
*/
public boolean canGoBack() {
+ checkThread();
WebBackForwardList l = mCallbackProxy.getBackForwardList();
synchronized (l) {
if (l.getClearPending()) {
@@ -1965,7 +2017,8 @@ public class WebView extends AbsoluteLayout
* Go back in the history of this WebView.
*/
public void goBack() {
- goBackOrForward(-1);
+ checkThread();
+ goBackOrForwardImpl(-1);
}
/**
@@ -1973,6 +2026,7 @@ public class WebView extends AbsoluteLayout
* @return True iff this Webview has a forward history item.
*/
public boolean canGoForward() {
+ checkThread();
WebBackForwardList l = mCallbackProxy.getBackForwardList();
synchronized (l) {
if (l.getClearPending()) {
@@ -1987,7 +2041,8 @@ public class WebView extends AbsoluteLayout
* Go forward in the history of this WebView.
*/
public void goForward() {
- goBackOrForward(1);
+ checkThread();
+ goBackOrForwardImpl(1);
}
/**
@@ -1997,6 +2052,7 @@ public class WebView extends AbsoluteLayout
* history.
*/
public boolean canGoBackOrForward(int steps) {
+ checkThread();
WebBackForwardList l = mCallbackProxy.getBackForwardList();
synchronized (l) {
if (l.getClearPending()) {
@@ -2016,6 +2072,11 @@ public class WebView extends AbsoluteLayout
* forward list.
*/
public void goBackOrForward(int steps) {
+ checkThread();
+ goBackOrForwardImpl(steps);
+ }
+
+ private void goBackOrForwardImpl(int steps) {
goBackOrForward(steps, false);
}
@@ -2031,6 +2092,7 @@ public class WebView extends AbsoluteLayout
* Returns true if private browsing is enabled in this WebView.
*/
public boolean isPrivateBrowsingEnabled() {
+ checkThread();
return getSettings().isPrivateBrowsingEnabled();
}
@@ -2053,6 +2115,7 @@ public class WebView extends AbsoluteLayout
* @return true if the page was scrolled
*/
public boolean pageUp(boolean top) {
+ checkThread();
if (mNativeClass == 0) {
return false;
}
@@ -2079,6 +2142,7 @@ public class WebView extends AbsoluteLayout
* @return true if the page was scrolled
*/
public boolean pageDown(boolean bottom) {
+ checkThread();
if (mNativeClass == 0) {
return false;
}
@@ -2103,6 +2167,7 @@ public class WebView extends AbsoluteLayout
* and onMeasure() will return 0 if MeasureSpec is not MeasureSpec.EXACTLY
*/
public void clearView() {
+ checkThread();
mContentWidth = 0;
mContentHeight = 0;
setBaseLayer(0, null, false, false);
@@ -2119,6 +2184,7 @@ public class WebView extends AbsoluteLayout
* bounds of the view.
*/
public Picture capturePicture() {
+ checkThread();
if (mNativeClass == 0) return null;
Picture result = new Picture();
nativeCopyBaseContentToPicture(result);
@@ -2149,6 +2215,7 @@ public class WebView extends AbsoluteLayout
* @return The current scale.
*/
public float getScale() {
+ checkThread();
return mZoomManager.getScale();
}
@@ -2161,6 +2228,7 @@ public class WebView extends AbsoluteLayout
* @param scaleInPercent The initial scale in percent.
*/
public void setInitialScale(int scaleInPercent) {
+ checkThread();
mZoomManager.setInitialScaleInPercent(scaleInPercent);
}
@@ -2170,6 +2238,7 @@ public class WebView extends AbsoluteLayout
* level of this WebView.
*/
public void invokeZoomPicker() {
+ checkThread();
if (!getSettings().supportZoom()) {
Log.w(LOGTAG, "This WebView doesn't support zoom.");
return;
@@ -2197,6 +2266,7 @@ public class WebView extends AbsoluteLayout
* HitTestResult type is set to UNKNOWN_TYPE.
*/
public HitTestResult getHitTestResult() {
+ checkThread();
return hitTestResult(mInitialHitTestResult);
}
@@ -2278,6 +2348,7 @@ public class WebView extends AbsoluteLayout
* - "src" returns the image's src attribute.
*/
public void requestFocusNodeHref(Message hrefMsg) {
+ checkThread();
if (hrefMsg == null) {
return;
}
@@ -2306,6 +2377,7 @@ public class WebView extends AbsoluteLayout
* as the data member with "url" as key. The result can be null.
*/
public void requestImageRef(Message msg) {
+ checkThread();
if (0 == mNativeClass) return; // client isn't initialized
int contentX = viewToContentX(mLastTouchX + mScrollX);
int contentY = viewToContentY(mLastTouchY + mScrollY);
@@ -2802,6 +2874,7 @@ public class WebView extends AbsoluteLayout
* @return The url for the current page.
*/
public String getUrl() {
+ checkThread();
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getUrl() : null;
}
@@ -2815,6 +2888,7 @@ public class WebView extends AbsoluteLayout
* @return The url that was originally requested for the current page.
*/
public String getOriginalUrl() {
+ checkThread();
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getOriginalUrl() : null;
}
@@ -2825,6 +2899,7 @@ public class WebView extends AbsoluteLayout
* @return The title for the current page.
*/
public String getTitle() {
+ checkThread();
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getTitle() : null;
}
@@ -2835,6 +2910,7 @@ public class WebView extends AbsoluteLayout
* @return The favicon for the current page.
*/
public Bitmap getFavicon() {
+ checkThread();
WebHistoryItem h = mCallbackProxy.getBackForwardList().getCurrentItem();
return h != null ? h.getFavicon() : null;
}
@@ -2855,6 +2931,7 @@ public class WebView extends AbsoluteLayout
* @return The progress for the current page between 0 and 100.
*/
public int getProgress() {
+ checkThread();
return mCallbackProxy.getProgress();
}
@@ -2862,6 +2939,7 @@ public class WebView extends AbsoluteLayout
* @return the height of the HTML content.
*/
public int getContentHeight() {
+ checkThread();
return mContentHeight;
}
@@ -2879,6 +2957,7 @@ public class WebView extends AbsoluteLayout
* useful if the application has been paused.
*/
public void pauseTimers() {
+ checkThread();
mWebViewCore.sendMessage(EventHub.PAUSE_TIMERS);
}
@@ -2887,6 +2966,7 @@ public class WebView extends AbsoluteLayout
* This will resume dispatching all timers.
*/
public void resumeTimers() {
+ checkThread();
mWebViewCore.sendMessage(EventHub.RESUME_TIMERS);
}
@@ -2899,6 +2979,7 @@ public class WebView extends AbsoluteLayout
* Note that this differs from pauseTimers(), which affects all WebViews.
*/
public void onPause() {
+ checkThread();
if (!mIsPaused) {
mIsPaused = true;
mWebViewCore.sendMessage(EventHub.ON_PAUSE);
@@ -2914,6 +2995,7 @@ public class WebView extends AbsoluteLayout
* Call this to resume a WebView after a previous call to onPause().
*/
public void onResume() {
+ checkThread();
if (mIsPaused) {
mIsPaused = false;
mWebViewCore.sendMessage(EventHub.ON_RESUME);
@@ -2934,6 +3016,7 @@ public class WebView extends AbsoluteLayout
* free any available memory.
*/
public void freeMemory() {
+ checkThread();
mWebViewCore.sendMessage(EventHub.FREE_MEMORY);
}
@@ -2944,6 +3027,7 @@ public class WebView extends AbsoluteLayout
* @param includeDiskFiles If false, only the RAM cache is cleared.
*/
public void clearCache(boolean includeDiskFiles) {
+ checkThread();
// Note: this really needs to be a static method as it clears cache for all
// WebView. But we need mWebViewCore to send message to WebCore thread, so
// we can't make this static.
@@ -2956,6 +3040,7 @@ public class WebView extends AbsoluteLayout
* currently focused textfield if there is one.
*/
public void clearFormData() {
+ checkThread();
if (inEditingMode()) {
AutoCompleteAdapter adapter = null;
mWebTextView.setAdapterCustom(adapter);
@@ -2966,6 +3051,7 @@ public class WebView extends AbsoluteLayout
* Tell the WebView to clear its internal back/forward list.
*/
public void clearHistory() {
+ checkThread();
mCallbackProxy.getBackForwardList().setClearPending();
mWebViewCore.sendMessage(EventHub.CLEAR_HISTORY);
}
@@ -2975,6 +3061,7 @@ public class WebView extends AbsoluteLayout
* certificate errors.
*/
public void clearSslPreferences() {
+ checkThread();
mWebViewCore.sendMessage(EventHub.CLEAR_SSL_PREF_TABLE);
}
@@ -2987,6 +3074,7 @@ public class WebView extends AbsoluteLayout
* updated to reflect any new state.
*/
public WebBackForwardList copyBackForwardList() {
+ checkThread();
return mCallbackProxy.getBackForwardList().clone();
}
@@ -2998,6 +3086,7 @@ public class WebView extends AbsoluteLayout
* @param forward Direction to search.
*/
public void findNext(boolean forward) {
+ checkThread();
if (0 == mNativeClass) return; // client isn't initialized
nativeFindNext(forward);
}
@@ -3009,6 +3098,7 @@ public class WebView extends AbsoluteLayout
* that were found.
*/
public int findAll(String find) {
+ checkThread();
if (0 == mNativeClass) return 0; // client isn't initialized
int result = find != null ? nativeFindAll(find.toLowerCase(),
find.toUpperCase(), find.equalsIgnoreCase(mLastFind)) : 0;
@@ -3028,6 +3118,7 @@ public class WebView extends AbsoluteLayout
* @return boolean True if the find dialog is shown, false otherwise.
*/
public boolean showFindDialog(String text, boolean showIme) {
+ checkThread();
FindActionModeCallback callback = new FindActionModeCallback(mContext);
if (getParent() == null || startActionMode(callback) == null) {
// Could not start the action mode, so end Find on page
@@ -3104,6 +3195,7 @@ public class WebView extends AbsoluteLayout
* @return the address, or if no address is found, return null.
*/
public static String findAddress(String addr) {
+ checkThread();
return findAddress(addr, false);
}
@@ -3137,6 +3229,7 @@ public class WebView extends AbsoluteLayout
* Clear the highlighting surrounding text matches created by findAll.
*/
public void clearMatches() {
+ checkThread();
if (mNativeClass == 0)
return;
nativeSetFindIsEmpty();
@@ -3166,6 +3259,7 @@ public class WebView extends AbsoluteLayout
* @param response The message that will be dispatched with the result.
*/
public void documentHasImages(Message response) {
+ checkThread();
if (response == null) {
return;
}
@@ -3561,6 +3655,7 @@ public class WebView extends AbsoluteLayout
* @param client An implementation of WebViewClient.
*/
public void setWebViewClient(WebViewClient client) {
+ checkThread();
mCallbackProxy.setWebViewClient(client);
}
@@ -3581,6 +3676,7 @@ public class WebView extends AbsoluteLayout
* @param listener An implementation of DownloadListener.
*/
public void setDownloadListener(DownloadListener listener) {
+ checkThread();
mCallbackProxy.setDownloadListener(listener);
}
@@ -3591,6 +3687,7 @@ public class WebView extends AbsoluteLayout
* @param client An implementation of WebChromeClient.
*/
public void setWebChromeClient(WebChromeClient client) {
+ checkThread();
mCallbackProxy.setWebChromeClient(client);
}
@@ -3629,6 +3726,7 @@ public class WebView extends AbsoluteLayout
* @param listener An implementation of WebView.PictureListener.
*/
public void setPictureListener(PictureListener listener) {
+ checkThread();
mPictureListener = listener;
}
@@ -3670,6 +3768,7 @@ public class WebView extends AbsoluteLayout
* JavaScript.
*/
public void addJavascriptInterface(Object obj, String interfaceName) {
+ checkThread();
if (obj == null) {
return;
}
@@ -3684,6 +3783,7 @@ public class WebView extends AbsoluteLayout
* @param interfaceName The name of the interface to remove.
*/
public void removeJavascriptInterface(String interfaceName) {
+ checkThread();
if (mWebViewCore != null) {
WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
arg.mInterfaceName = interfaceName;
@@ -3698,6 +3798,7 @@ public class WebView extends AbsoluteLayout
* settings.
*/
public WebSettings getSettings() {
+ checkThread();
return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
}
@@ -3710,6 +3811,7 @@ public class WebView extends AbsoluteLayout
*/
@Deprecated
public static synchronized PluginList getPluginList() {
+ checkThread();
return new PluginList();
}
@@ -3718,7 +3820,9 @@ public class WebView extends AbsoluteLayout
* @deprecated This was used for Gears, which has been deprecated.
*/
@Deprecated
- public void refreshPlugins(boolean reloadOpenPages) { }
+ public void refreshPlugins(boolean reloadOpenPages) {
+ checkThread();
+ }
//-------------------------------------------------------------------------
// Override View methods
@@ -3727,7 +3831,7 @@ public class WebView extends AbsoluteLayout
@Override
protected void finalize() throws Throwable {
try {
- destroy();
+ destroyImpl();
} finally {
super.finalize();
}
@@ -4988,6 +5092,7 @@ public class WebView extends AbsoluteLayout
* Do not rely on this functionality; it will be deprecated in the future.
*/
public void emulateShiftHeld() {
+ checkThread();
setUpSelect(false, 0, 0);
}
@@ -6257,6 +6362,7 @@ public class WebView extends AbsoluteLayout
private boolean mMapTrackballToArrowKeys = true;
public void setMapTrackballToArrowKeys(boolean setMap) {
+ checkThread();
mMapTrackballToArrowKeys = setMap;
}
@@ -6549,6 +6655,7 @@ public class WebView extends AbsoluteLayout
}
public void flingScroll(int vx, int vy) {
+ checkThread();
mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
invalidate();
@@ -6684,6 +6791,7 @@ public class WebView extends AbsoluteLayout
*/
@Deprecated
public View getZoomControls() {
+ checkThread();
if (!getSettings().supportZoom()) {
Log.w(LOGTAG, "This WebView doesn't support zoom.");
return null;
@@ -6703,6 +6811,7 @@ public class WebView extends AbsoluteLayout
* @return TRUE if the WebView can be zoomed in.
*/
public boolean canZoomIn() {
+ checkThread();
return mZoomManager.canZoomIn();
}
@@ -6710,6 +6819,7 @@ public class WebView extends AbsoluteLayout
* @return TRUE if the WebView can be zoomed out.
*/
public boolean canZoomOut() {
+ checkThread();
return mZoomManager.canZoomOut();
}
@@ -6718,6 +6828,7 @@ public class WebView extends AbsoluteLayout
* @return TRUE if zoom in succeeds. FALSE if no zoom changes.
*/
public boolean zoomIn() {
+ checkThread();
return mZoomManager.zoomIn();
}
@@ -6726,6 +6837,7 @@ public class WebView extends AbsoluteLayout
* @return TRUE if zoom out succeeds. FALSE if no zoom changes.
*/
public boolean zoomOut() {
+ checkThread();
return mZoomManager.zoomOut();
}
@@ -8682,6 +8794,7 @@ public class WebView extends AbsoluteLayout
}
public void debugDump() {
+ checkThread();
nativeDebugDump();
mWebViewCore.sendMessage(EventHub.DUMP_NAVTREE);
}
@@ -8743,6 +8856,19 @@ public class WebView extends AbsoluteLayout
return mViewManager;
}
+ private static void checkThread() {
+ if (!"main".equals(Thread.currentThread().getName())) {
+ try {
+ throw new RuntimeException("A WebView method was called on thread '" +
+ Thread.currentThread().getName() + "'. " +
+ "All WebView methods must be called on the UI thread. " +
+ "Future versions of WebView may not support use on other threads.");
+ } catch (RuntimeException e) {
+ Log.e(LOGTAG, Log.getStackTraceString(e));
+ }
+ }
+ }
+
private native int nativeCacheHitFramePointer();
private native boolean nativeCacheHitIsPlugin();
private native Rect nativeCacheHitNodeBounds();
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d63d421fb3b5..df4c4ed74b49 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2818,7 +2818,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
// If we couldn't find a view to click on, but the down event
// was touching the edge, we will bail out and try again.
- // This allows the edge correcting code in ViewRoot to try to
+ // This allows the edge correcting code in ViewAncestor to try to
// find a nearby view to select
return false;
}
@@ -5021,7 +5021,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
public boolean sendKeyEvent(KeyEvent event) {
// Use our own input connection, since the filter
// text view may not be shown in a window so has
- // no ViewRoot to dispatch events with.
+ // no ViewAncestor to dispatch events with.
return mDefInputConnection.sendKeyEvent(event);
}
};
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index dbe9288afa79..7838ec093f31 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -254,6 +254,15 @@ public class LinearLayout extends ViewGroup {
return mDividerPadding;
}
+ /**
+ * Get the width of the current divider drawable.
+ *
+ * @hide Used internally by framework.
+ */
+ public int getDividerWidth() {
+ return mDividerWidth;
+ }
+
@Override
protected void onDraw(Canvas canvas) {
if (mDivider == null) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index d115364bff41..e11f5bbbc81b 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1568,7 +1568,7 @@ public class ListView extends AbsListView {
// take focus back to us temporarily to avoid the eventual
// call to clear focus when removing the focused child below
- // from messing things up when ViewRoot assigns focus back
+ // from messing things up when ViewAncestor assigns focus back
// to someone else
final View focusedChild = getFocusedChild();
if (focusedChild != null) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 24b176d13e4e..c38624fe0619 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -113,7 +113,7 @@ import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -3373,13 +3373,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Handler h = getHandler();
if (h != null) {
long eventTime = SystemClock.uptimeMillis();
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
| KeyEvent.FLAG_EDITOR_ACTION)));
- h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ h.sendMessage(h.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(SystemClock.uptimeMillis(), eventTime,
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
@@ -7152,7 +7152,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
// The DecorView does not have focus when the 'Done' ExtractEditText button is
- // pressed. Since it is the ViewRoot's mView, it requests focus before
+ // pressed. Since it is the ViewAncestor's mView, it requests focus before
// ExtractEditText clears focus, which gives focus to the ExtractEditText.
// This special case ensure that we keep current selection in that case.
// It would be better to know why the DecorView does not have focus at that time.
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 450c966bdbeb..9e37c7bb1873 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -33,7 +33,7 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
@@ -501,7 +501,7 @@ public class ZoomButtonsController implements View.OnTouchListener {
} else {
- ViewRoot viewRoot = getOwnerViewRoot();
+ ViewAncestor viewRoot = getOwnerViewAncestor();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
}
@@ -526,15 +526,15 @@ public class ZoomButtonsController implements View.OnTouchListener {
}
}
- private ViewRoot getOwnerViewRoot() {
+ private ViewAncestor getOwnerViewAncestor() {
View rootViewOfOwner = mOwnerView.getRootView();
if (rootViewOfOwner == null) {
return null;
}
ViewParent parentOfRootView = rootViewOfOwner.getParent();
- if (parentOfRootView instanceof ViewRoot) {
- return (ViewRoot) parentOfRootView;
+ if (parentOfRootView instanceof ViewAncestor) {
+ return (ViewAncestor) parentOfRootView;
} else {
return null;
}
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 57df259acca9..1e576ceb044f 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -19,6 +19,7 @@ package com.android.internal.app;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.AbsActionBarView;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
@@ -46,7 +47,6 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.DecelerateInterpolator;
import android.widget.HorizontalScrollView;
-import android.widget.LinearLayout;
import android.widget.SpinnerAdapter;
import java.lang.ref.WeakReference;
@@ -61,8 +61,6 @@ import java.util.ArrayList;
*/
public class ActionBarImpl extends ActionBar {
private static final String TAG = "ActionBarImpl";
- private static final int NORMAL_VIEW = 0;
- private static final int CONTEXT_VIEW = 1;
private Context mContext;
private Activity mActivity;
@@ -70,8 +68,8 @@ public class ActionBarImpl extends ActionBar {
private ActionBarContainer mContainerView;
private ActionBarView mActionView;
- private ActionBarContextView mUpperContextView;
- private LinearLayout mLowerView;
+ private ActionBarContextView mContextView;
+ private ActionBarContainer mSplitView;
private View mContentView;
private ViewGroup mExternalTabView;
@@ -102,26 +100,6 @@ public class ActionBarImpl extends ActionBar {
private static final TimeInterpolator sFadeOutInterpolator = new DecelerateInterpolator();
- final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
- new AnimatorListenerAdapter() { // NORMAL_VIEW
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mLowerView != null) {
- mLowerView.removeAllViews();
- }
- mCurrentModeAnim = null;
- hideAllExcept(NORMAL_VIEW);
- }
- },
- new AnimatorListenerAdapter() { // CONTEXT_VIEW
- @Override
- public void onAnimationEnd(Animator animation) {
- mCurrentModeAnim = null;
- hideAllExcept(CONTEXT_VIEW);
- }
- }
- };
-
final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -160,19 +138,19 @@ public class ActionBarImpl extends ActionBar {
private void init(View decor) {
mContext = decor.getContext();
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
- mUpperContextView = (ActionBarContextView) decor.findViewById(
+ mContextView = (ActionBarContextView) decor.findViewById(
com.android.internal.R.id.action_context_bar);
- mLowerView = (LinearLayout) decor.findViewById(
- com.android.internal.R.id.lower_action_context_bar);
mContainerView = (ActionBarContainer) decor.findViewById(
com.android.internal.R.id.action_bar_container);
+ mSplitView = (ActionBarContainer) decor.findViewById(
+ com.android.internal.R.id.split_action_bar);
- if (mActionView == null || mUpperContextView == null || mContainerView == null) {
+ if (mActionView == null || mContextView == null || mContainerView == null) {
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
"with a compatible window decor layout");
}
- mActionView.setContextView(mUpperContextView);
+ mActionView.setContextView(mContextView);
mContextDisplayMode = mActionView.isSplitActionBar() ?
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
@@ -341,16 +319,16 @@ public class ActionBarImpl extends ActionBar {
mActionMode.finish();
}
- mUpperContextView.killMode();
+ mContextView.killMode();
ActionMode mode = new ActionModeImpl(callback);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
mWasHiddenBeforeMode = !isShowing();
mode.invalidate();
- mUpperContextView.initForMode(mode);
- animateTo(CONTEXT_VIEW);
- if (mLowerView != null) {
+ mContextView.initForMode(mode);
+ animateToMode(true);
+ if (mSplitView != null) {
// TODO animate this
- mLowerView.setVisibility(View.VISIBLE);
+ mSplitView.setVisibility(View.VISIBLE);
}
mActionMode = mode;
return mode;
@@ -418,7 +396,10 @@ public class ActionBarImpl extends ActionBar {
int selectedTabPosition = mSelectedTab != null
? mSelectedTab.getPosition() : mSavedTabPosition;
mActionView.removeTabAt(position);
- mTabs.remove(position);
+ TabImpl removedTab = mTabs.remove(position);
+ if (removedTab != null) {
+ removedTab.setPosition(-1);
+ }
final int newTabCount = mTabs.size();
for (int i = position; i < newTabCount; i++) {
@@ -495,6 +476,10 @@ public class ActionBarImpl extends ActionBar {
mContainerView.setTranslationY(-mContainerView.getHeight());
b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
}
+ if (mSplitView != null) {
+ mSplitView.setAlpha(0);
+ b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
+ }
anim.addListener(mShowListener);
mCurrentShowAnim = anim;
anim.start();
@@ -525,6 +510,10 @@ public class ActionBarImpl extends ActionBar {
b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
-mContainerView.getHeight()));
}
+ if (mSplitView != null) {
+ mSplitView.setAlpha(1);
+ b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
+ }
anim.addListener(mHideListener);
mCurrentShowAnim = anim;
anim.start();
@@ -537,45 +526,14 @@ public class ActionBarImpl extends ActionBar {
return mContainerView.getVisibility() == View.VISIBLE;
}
- long animateTo(int viewIndex) {
+ void animateToMode(boolean toActionMode) {
show(false);
if (mCurrentModeAnim != null) {
mCurrentModeAnim.end();
}
- AnimatorSet set = new AnimatorSet();
-
- final View targetChild = mContainerView.getChildAt(viewIndex);
- targetChild.setVisibility(View.VISIBLE);
- targetChild.setAlpha(0);
- AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
-
- final int count = mContainerView.getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = mContainerView.getChildAt(i);
- if (i == viewIndex || child == mContainerView.getTabContainer()) {
- continue;
- }
-
- if (child.getVisibility() != View.GONE) {
- Animator a = ObjectAnimator.ofFloat(child, "alpha", 0);
- a.setInterpolator(sFadeOutInterpolator);
- b.with(a);
- }
- }
-
- set.addListener(mAfterAnimation[viewIndex]);
-
- mCurrentModeAnim = set;
- set.start();
- return set.getDuration();
- }
-
- private void hideAllExcept(int viewIndex) {
- final int count = mContainerView.getChildCount();
- for (int i = 0; i < count; i++) {
- mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
- }
+ mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+ mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
}
/**
@@ -612,14 +570,10 @@ public class ActionBarImpl extends ActionBar {
mCallback.onDestroyActionMode(this);
mCallback = null;
- animateTo(NORMAL_VIEW);
+ animateToMode(false);
// Clear out the context mode views after the animation finishes
- mUpperContextView.closeMode();
- if (mLowerView != null && mLowerView.getVisibility() != View.GONE) {
- // TODO Animate this
- mLowerView.setVisibility(View.GONE);
- }
+ mContextView.closeMode();
mActionMode = null;
if (mWasHiddenBeforeMode) {
@@ -636,18 +590,18 @@ public class ActionBarImpl extends ActionBar {
@Override
public void setCustomView(View view) {
- mUpperContextView.setCustomView(view);
+ mContextView.setCustomView(view);
mCustomView = new WeakReference<View>(view);
}
@Override
public void setSubtitle(CharSequence subtitle) {
- mUpperContextView.setSubtitle(subtitle);
+ mContextView.setSubtitle(subtitle);
}
@Override
public void setTitle(CharSequence title) {
- mUpperContextView.setTitle(title);
+ mContextView.setTitle(title);
}
@Override
@@ -662,12 +616,12 @@ public class ActionBarImpl extends ActionBar {
@Override
public CharSequence getTitle() {
- return mUpperContextView.getTitle();
+ return mContextView.getTitle();
}
@Override
public CharSequence getSubtitle() {
- return mUpperContextView.getSubtitle();
+ return mContextView.getSubtitle();
}
@Override
@@ -707,7 +661,7 @@ public class ActionBarImpl extends ActionBar {
return;
}
invalidate();
- mUpperContextView.showOverflowMenu();
+ mContextView.showOverflowMenu();
}
}
@@ -719,7 +673,7 @@ public class ActionBarImpl extends ActionBar {
private Object mTag;
private Drawable mIcon;
private CharSequence mText;
- private int mPosition;
+ private int mPosition = -1;
private View mCustomView;
@Override
@@ -751,6 +705,7 @@ public class ActionBarImpl extends ActionBar {
@Override
public Tab setCustomView(View view) {
mCustomView = view;
+ if (mPosition >= 0) mActionView.updateTab(mPosition);
return this;
}
@@ -781,6 +736,7 @@ public class ActionBarImpl extends ActionBar {
@Override
public Tab setIcon(Drawable icon) {
mIcon = icon;
+ if (mPosition >= 0) mActionView.updateTab(mPosition);
return this;
}
@@ -792,6 +748,7 @@ public class ActionBarImpl extends ActionBar {
@Override
public Tab setText(CharSequence text) {
mText = text;
+ if (mPosition >= 0) mActionView.updateTab(mPosition);
return this;
}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index b35f615b240d..2e7ec58de536 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -39,6 +39,7 @@ public class Protocol {
public static final int BASE_WIFI = 0x00020000;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
+ public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
public static final int BASE_DATA_CONNECTION_TRACKER = 0x00050000;
//TODO: define all used protocols
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index e210b78c268f..0051ec3a1b44 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -21,7 +21,6 @@ import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
@@ -36,11 +35,14 @@ import java.util.ArrayList;
* MenuPresenter for building action menus as seen in the action bar and action modes.
*/
public class ActionMenuPresenter extends BaseMenuPresenter {
+ private static final String TAG = "ActionMenuPresenter";
+
private View mOverflowButton;
private boolean mReserveOverflow;
private int mWidthLimit;
private int mActionItemWidthLimit;
private int mMaxItems;
+ private boolean mStrictWidthLimit;
// Group IDs that have been added as actions - used temporarily, allocated here for reuse.
private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
@@ -89,11 +91,12 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
mScrapActionButtonView = null;
}
- public void setWidthLimit(int width) {
+ public void setWidthLimit(int width, boolean strict) {
if (mReserveOverflow) {
width -= mOverflowButton.getMeasuredWidth();
}
mActionItemWidthLimit = width;
+ mStrictWidthLimit = strict;
}
public void setItemLimit(int itemCount) {
@@ -131,6 +134,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
if (mReserveOverflow && mMenu.getNonActionItems().size() > 0) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mContext);
+ mOverflowButton.setLayoutParams(
+ ((ActionMenuView) mMenuView).generateOverflowButtonLayoutParams());
}
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
if (parent != mMenuView) {
@@ -189,7 +194,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
public boolean showOverflowMenu() {
if (mReserveOverflow && !isOverflowMenuShowing() && mMenuView != null &&
mPostedOpenRunnable == null) {
- Log.d("ActionMenuPresenter", "showOverflowMenu");
OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
mPostedOpenRunnable = new OpenOverflowRunnable(popup);
// Post this for later; we might still need a layout for the anchor to be right.
@@ -338,9 +342,11 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
firstActionWidth = measuredWidth;
}
- // Did this push the entire first item past halfway?
- if (widthLimit + firstActionWidth <= 0) {
- isAction = false;
+ if (mStrictWidthLimit) {
+ isAction = widthLimit >= 0;
+ } else {
+ // Did this push the entire first item past the limit?
+ isAction = widthLimit + firstActionWidth > 0;
}
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 0ea9c893dcdf..290bf08e0718 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -20,6 +20,7 @@ import android.content.res.Configuration;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.LinearLayout;
@@ -33,6 +34,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
private boolean mReserveOverflow;
private ActionMenuPresenter mPresenter;
+ private boolean mUpdateContentsBeforeMeasure;
+ private boolean mFormatItems;
public ActionMenuView(Context context) {
this(context, null);
@@ -59,6 +62,95 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
@Override
+ public void requestLayout() {
+ // Layout can influence how many action items fit.
+ mUpdateContentsBeforeMeasure = true;
+ super.requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mUpdateContentsBeforeMeasure && mMenu != null) {
+ mMenu.onItemsChanged(true);
+ mUpdateContentsBeforeMeasure = false;
+ }
+ // If we've been given an exact size to match, apply special formatting during layout.
+ mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (!mFormatItems) {
+ super.onLayout(changed, left, top, right, bottom);
+ return;
+ }
+
+ final int childCount = getChildCount();
+ final int midVertical = (top + bottom) / 2;
+ final int dividerWidth = getDividerWidth();
+ boolean hasOverflow = false;
+ int overflowWidth = 0;
+ int nonOverflowWidth = 0;
+ int nonOverflowCount = 0;
+ int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
+ for (int i = 0; i < childCount; i++) {
+ final View v = getChildAt(i);
+ if (v.getVisibility() == GONE) {
+ continue;
+ }
+
+ LayoutParams p = (LayoutParams) v.getLayoutParams();
+ if (p.isOverflowButton) {
+ hasOverflow = true;
+ overflowWidth = v.getMeasuredWidth();
+ if (hasDividerBeforeChildAt(i)) {
+ overflowWidth += dividerWidth;
+ }
+
+ int height = v.getMeasuredHeight();
+ int r = getPaddingRight();
+ int l = r - overflowWidth;
+ int t = midVertical - (height / 2);
+ int b = t + height;
+ v.layout(l, t, r, b);
+
+ widthRemaining -= overflowWidth;
+ } else {
+ nonOverflowWidth += v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
+ if (hasDividerBeforeChildAt(i)) {
+ nonOverflowWidth += dividerWidth;
+ }
+ nonOverflowCount++;
+ }
+ }
+
+ // Try to center non-overflow items with uniformly spaced padding, including on the edges.
+ // Overflow will always pin to the right edge. If there isn't enough room for that,
+ // center in the remaining space.
+ if (nonOverflowWidth <= widthRemaining - overflowWidth) {
+ widthRemaining -= overflowWidth;
+ }
+
+ final int spacing = (widthRemaining - nonOverflowWidth) / (nonOverflowCount + 1);
+ int startLeft = getPaddingLeft() + overflowWidth + spacing;
+ for (int i = 0; i < childCount; i++) {
+ final View v = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+ if (v.getVisibility() == GONE || lp.isOverflowButton) {
+ continue;
+ }
+
+ startLeft += lp.leftMargin;
+ int width = v.getMeasuredWidth();
+ int height = v.getMeasuredHeight();
+ int t = midVertical - (height / 2);
+ v.layout(startLeft, t, startLeft + width, t + height);
+ startLeft += width + lp.rightMargin + spacing;
+ }
+ }
+
+ @Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
mPresenter.dismissPopupMenus();
@@ -97,6 +189,12 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
return p instanceof LayoutParams;
}
+ public LayoutParams generateOverflowButtonLayoutParams() {
+ LayoutParams result = generateDefaultLayoutParams();
+ result.isOverflowButton = true;
+ return result;
+ }
+
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
}
@@ -127,4 +225,28 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
public boolean needsDividerBefore();
public boolean needsDividerAfter();
}
+
+ public static class LayoutParams extends LinearLayout.LayoutParams {
+ @ViewDebug.ExportedProperty(category = "layout")
+ public boolean isOverflowButton;
+
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ }
+
+ public LayoutParams(LayoutParams other) {
+ super((LinearLayout.LayoutParams) other);
+ isOverflowButton = other.isOverflowButton;
+ }
+
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ isOverflowButton = false;
+ }
+
+ public LayoutParams(int width, int height, boolean isOverflowButton) {
+ super(width, height);
+ this.isOverflowButton = isOverflowButton;
+ }
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 7fba5cac2aee..e9fcb23113c6 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -226,6 +226,7 @@ public class MenuBuilder implements Menu {
private void dispatchPresenterUpdate(boolean cleared) {
if (mPresenters.isEmpty()) return;
+ stopDispatchingItemsChanged();
for (WeakReference<MenuPresenter> ref : mPresenters) {
final MenuPresenter presenter = ref.get();
if (presenter == null) {
@@ -234,6 +235,7 @@ public class MenuBuilder implements Menu {
presenter.updateMenuView(cleared);
}
}
+ startDispatchingItemsChanged();
}
private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) {
diff --git a/core/java/com/android/internal/view/menu/MenuDialogHelper.java b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
index 6387c9b9747a..5c8e057a9705 100644
--- a/core/java/com/android/internal/view/menu/MenuDialogHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuDialogHelper.java
@@ -37,6 +37,7 @@ public class MenuDialogHelper implements DialogInterface.OnKeyListener,
private MenuBuilder mMenu;
private AlertDialog mDialog;
ListMenuPresenter mPresenter;
+ private MenuPresenter.Callback mPresenterCallback;
public MenuDialogHelper(MenuBuilder menu) {
mMenu = menu;
@@ -124,6 +125,10 @@ public class MenuDialogHelper implements DialogInterface.OnKeyListener,
}
+ public void setPresenterCallback(MenuPresenter.Callback cb) {
+ mPresenterCallback = cb;
+ }
+
/**
* Dismisses the menu's dialog.
*
@@ -145,10 +150,16 @@ public class MenuDialogHelper implements DialogInterface.OnKeyListener,
if (allMenusAreClosing || menu == mMenu) {
dismiss();
}
+ if (mPresenterCallback != null) {
+ mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
+ }
}
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ if (mPresenterCallback != null) {
+ return mPresenterCallback.onOpenSubMenu(subMenu);
+ }
return false;
}
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
new file mode 100644
index 000000000000..3979eabcf156
--- /dev/null
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget;
+
+import com.android.internal.view.menu.ActionMenuPresenter;
+import com.android.internal.view.menu.ActionMenuView;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+
+public abstract class AbsActionBarView extends ViewGroup {
+ protected ActionMenuView mMenuView;
+ protected ActionMenuPresenter mMenuPresenter;
+ protected ActionBarContainer mSplitView;
+
+ protected Animator mVisibilityAnim;
+ protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
+
+ private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator();
+
+ private static final int FADE_DURATION = 200;
+
+ public AbsActionBarView(Context context) {
+ super(context);
+ }
+
+ public AbsActionBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setSplitView(ActionBarContainer splitView) {
+ mSplitView = splitView;
+ }
+
+ public void animateToVisibility(int visibility) {
+ if (mVisibilityAnim != null) {
+ mVisibilityAnim.cancel();
+ }
+ if (visibility == VISIBLE) {
+ if (getVisibility() != VISIBLE) {
+ setAlpha(0);
+ if (mSplitView != null && mMenuView != null) {
+ mMenuView.setAlpha(0);
+ }
+ }
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
+ anim.setDuration(FADE_DURATION);
+ anim.setInterpolator(sAlphaInterpolator);
+ if (mSplitView != null && mMenuView != null) {
+ AnimatorSet set = new AnimatorSet();
+ ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
+ splitAnim.setDuration(FADE_DURATION);
+ set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ set.play(anim).with(splitAnim);
+ } else {
+ anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ anim.start();
+ }
+ } else {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
+ anim.setDuration(FADE_DURATION);
+ anim.setInterpolator(sAlphaInterpolator);
+ if (mSplitView != null && mMenuView != null) {
+ AnimatorSet set = new AnimatorSet();
+ ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
+ splitAnim.setDuration(FADE_DURATION);
+ set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ set.play(anim).with(splitAnim);
+ } else {
+ anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ anim.start();
+ }
+ }
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ if (mVisibilityAnim != null) {
+ mVisibilityAnim.end();
+ }
+ super.setVisibility(visibility);
+ }
+
+ public boolean showOverflowMenu() {
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.showOverflowMenu();
+ }
+ return false;
+ }
+
+ public void postShowOverflowMenu() {
+ post(new Runnable() {
+ public void run() {
+ showOverflowMenu();
+ }
+ });
+ }
+
+ public boolean hideOverflowMenu() {
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.hideOverflowMenu();
+ }
+ return false;
+ }
+
+ public boolean isOverflowMenuShowing() {
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.isOverflowMenuShowing();
+ }
+ return false;
+ }
+
+ public boolean isOverflowReserved() {
+ return mMenuPresenter != null && mMenuPresenter.isOverflowReserved();
+ }
+
+ public void dismissPopupMenus() {
+ if (mMenuPresenter != null) {
+ mMenuPresenter.dismissPopupMenus();
+ }
+ }
+
+ protected int measureChildView(View child, int availableWidth, int childSpecHeight,
+ int spacing) {
+ child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+ childSpecHeight);
+
+ availableWidth -= child.getMeasuredWidth();
+ availableWidth -= spacing;
+
+ return availableWidth;
+ }
+
+ protected int positionChild(View child, int x, int y, int contentHeight) {
+ int childWidth = child.getMeasuredWidth();
+ int childHeight = child.getMeasuredHeight();
+ int childTop = y + (contentHeight - childHeight) / 2;
+
+ child.layout(x, childTop, x + childWidth, childTop + childHeight);
+
+ return childWidth;
+ }
+
+ protected int positionChildInverse(View child, int x, int y, int contentHeight) {
+ int childWidth = child.getMeasuredWidth();
+ int childHeight = child.getMeasuredHeight();
+ int childTop = y + (contentHeight - childHeight) / 2;
+
+ child.layout(x - childWidth, childTop, x, childTop + childHeight);
+
+ return childWidth;
+ }
+
+ protected class VisibilityAnimListener implements Animator.AnimatorListener {
+ private boolean mCanceled = false;
+ private int mFinalVisibility;
+
+ public VisibilityAnimListener withFinalVisibility(int visibility) {
+ mFinalVisibility = visibility;
+ return this;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ setVisibility(VISIBLE);
+ mVisibilityAnim = animation;
+ mCanceled = false;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mCanceled) return;
+
+ mVisibilityAnim = null;
+ setVisibility(mFinalVisibility);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCanceled = true;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 3deb036ea89a..c18565df9cdd 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -19,6 +19,7 @@ package com.android.internal.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.view.ActionMode;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -85,6 +86,12 @@ public class ActionBarContainer extends FrameLayout {
}
@Override
+ public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
+ // No starting an action mode for an action bar child! (Where would it go?)
+ return null;
+ }
+
+ @Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 70fb3b2093b3..f45a3bb63a6d 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -30,7 +30,7 @@ import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -38,7 +38,7 @@ import android.widget.TextView;
/**
* @hide
*/
-public class ActionBarContextView extends ViewGroup implements AnimatorListener {
+public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
private static final String TAG = "ActionBarContextView";
private int mContentHeight;
@@ -53,8 +53,6 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
private TextView mSubtitleView;
private int mTitleStyleRes;
private int mSubtitleStyleRes;
- private ActionMenuView mMenuView;
- private ActionMenuPresenter mPresenter;
private Animator mCurrentAnimation;
private boolean mAnimateInOnLayout;
@@ -87,12 +85,6 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
com.android.internal.R.styleable.ActionMode_height, 0);
a.recycle();
}
-
- @Override
- public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
- // No starting an action mode for an existing action mode UI child! (Where would it go?)
- return null;
- }
public void setHeight(int height) {
mContentHeight = height;
@@ -178,10 +170,25 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
});
final MenuBuilder menu = (MenuBuilder) mode.getMenu();
- mPresenter = new ActionMenuPresenter();
- menu.addMenuPresenter(mPresenter);
- mMenuView = (ActionMenuView) mPresenter.getMenuView(this);
- addView(mMenuView);
+ mMenuPresenter = new ActionMenuPresenter();
+ menu.addMenuPresenter(mMenuPresenter);
+ mMenuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
+
+ final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT);
+ mMenuView.setLayoutParams(layoutParams);
+ if (mSplitView == null) {
+ addView(mMenuView);
+ } else {
+ // Allow full screen width in split mode.
+ mMenuPresenter.setWidthLimit(
+ getContext().getResources().getDisplayMetrics().widthPixels, true);
+ // No limit to the item count; use whatever will fit.
+ mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+ // Span the whole width
+ layoutParams.width = LayoutParams.MATCH_PARENT;
+ mSplitView.addView(mMenuView);
+ }
mAnimateInOnLayout = true;
}
@@ -213,28 +220,31 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
public void killMode() {
finishAnimation();
removeAllViews();
+ if (mSplitView != null) {
+ mSplitView.removeView(mMenuView);
+ }
mCustomView = null;
mMenuView = null;
mAnimateInOnLayout = false;
}
public boolean showOverflowMenu() {
- if (mPresenter != null) {
- return mPresenter.showOverflowMenu();
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.showOverflowMenu();
}
return false;
}
public boolean hideOverflowMenu() {
- if (mPresenter != null) {
- return mPresenter.hideOverflowMenu();
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.hideOverflowMenu();
}
return false;
}
public boolean isOverflowMenuShowing() {
- if (mPresenter != null) {
- return mPresenter.isOverflowMenuShowing();
+ if (mMenuPresenter != null) {
+ return mMenuPresenter.isOverflowMenuShowing();
}
return false;
}
@@ -342,7 +352,7 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
private Animator makeOutAnimation() {
ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
- 0, -mClose.getWidth());
+ -mClose.getWidth());
buttonAnimator.setDuration(200);
buttonAnimator.addListener(this);
buttonAnimator.setInterpolator(new DecelerateInterpolator());
@@ -356,7 +366,7 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
for (int i = 0; i < 0; i++) {
View child = mMenuView.getChildAt(i);
child.setScaleY(0);
- ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 1, 0);
+ ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
a.setDuration(100);
a.setStartDelay(i * 70);
b.with(a);
@@ -383,7 +393,7 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
mAnimateInOnLayout = false;
}
}
-
+
if (mTitleLayout != null && mCustomView == null) {
x += positionChild(mTitleLayout, x, y, contentHeight);
}
@@ -399,36 +409,6 @@ public class ActionBarContextView extends ViewGroup implements AnimatorListener
}
}
- private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
- child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
- childSpecHeight);
-
- availableWidth -= child.getMeasuredWidth();
- availableWidth -= spacing;
-
- return availableWidth;
- }
-
- private int positionChild(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x, childTop, x + childWidth, childTop + childHeight);
-
- return childWidth;
- }
-
- private int positionChildInverse(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x - childWidth, childTop, x, childTop + childHeight);
-
- return childWidth;
- }
-
@Override
public void onAnimationStart(Animator animation) {
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 0c13f7bfbe60..d6f439aa7938 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -38,7 +38,6 @@ import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.ActionMode;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -59,7 +58,7 @@ import android.widget.TextView;
/**
* @hide
*/
-public class ActionBarView extends ViewGroup {
+public class ActionBarView extends AbsActionBarView {
private static final String TAG = "ActionBarView";
/**
@@ -115,11 +114,8 @@ public class ActionBarView extends ViewGroup {
private boolean mIncludeTabs;
private MenuBuilder mOptionsMenu;
- private ActionMenuView mMenuView;
- private ActionMenuPresenter mActionMenuPresenter;
private ActionBarContextView mContextView;
- private ViewGroup mSplitView;
private ActionMenuItem mLogoNavItem;
@@ -274,12 +270,6 @@ public class ActionBarView extends ViewGroup {
mTabLayout = tabLayout;
}
- @Override
- public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
- // No starting an action mode for an action bar child! (Where would it go?)
- return null;
- }
-
public void setCallback(OnNavigationListener callback) {
mCallback = callback;
}
@@ -288,7 +278,7 @@ public class ActionBarView extends ViewGroup {
if (menu == mOptionsMenu) return;
if (mOptionsMenu != null) {
- mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);
+ mOptionsMenu.removeMenuPresenter(mMenuPresenter);
}
MenuBuilder builder = (MenuBuilder) menu;
@@ -296,12 +286,12 @@ public class ActionBarView extends ViewGroup {
if (mMenuView != null) {
removeView(mMenuView);
}
- if (mActionMenuPresenter == null) {
- mActionMenuPresenter = new ActionMenuPresenter();
- mActionMenuPresenter.setCallback(cb);
- builder.addMenuPresenter(mActionMenuPresenter);
+ if (mMenuPresenter == null) {
+ mMenuPresenter = new ActionMenuPresenter();
+ mMenuPresenter.setCallback(cb);
+ builder.addMenuPresenter(mMenuPresenter);
}
- final ActionMenuView menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+ final ActionMenuView menuView = (ActionMenuView) mMenuPresenter.getMenuView(this);
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
menuView.setLayoutParams(layoutParams);
@@ -309,10 +299,12 @@ public class ActionBarView extends ViewGroup {
addView(menuView);
} else {
// Allow full screen width in split mode.
- mActionMenuPresenter.setWidthLimit(
- getContext().getResources().getDisplayMetrics().widthPixels);
+ mMenuPresenter.setWidthLimit(
+ getContext().getResources().getDisplayMetrics().widthPixels, true);
// No limit to the item count; use whatever will fit.
- mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+ mMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+ // Span the whole width
+ layoutParams.width = LayoutParams.MATCH_PARENT;
if (mSplitView != null) {
mSplitView.addView(menuView);
} // We'll add this later if we missed it this time.
@@ -320,59 +312,6 @@ public class ActionBarView extends ViewGroup {
mMenuView = menuView;
}
- public void setSplitView(ViewGroup splitView) {
- mSplitView = splitView;
- splitView.setVisibility(VISIBLE);
- if (mMenuView != null) {
- splitView.addView(mMenuView);
- }
- }
-
- public boolean showOverflowMenu() {
- if (mActionMenuPresenter != null) {
- return mActionMenuPresenter.showOverflowMenu();
- }
- return false;
- }
-
- public void openOverflowMenu() {
- if (mActionMenuPresenter != null) {
- showOverflowMenu();
- }
- }
-
- public void postShowOverflowMenu() {
- post(new Runnable() {
- public void run() {
- showOverflowMenu();
- }
- });
- }
-
- public boolean hideOverflowMenu() {
- if (mActionMenuPresenter != null) {
- return mActionMenuPresenter.hideOverflowMenu();
- }
- return false;
- }
-
- public boolean isOverflowMenuShowing() {
- if (mActionMenuPresenter != null) {
- return mActionMenuPresenter.isOverflowMenuShowing();
- }
- return false;
- }
-
- public boolean isOverflowReserved() {
- return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
- }
-
- public void dismissPopupMenus() {
- if (mActionMenuPresenter != null) {
- mActionMenuPresenter.dismissPopupMenus();
- }
- }
-
public void setCustomNavigationView(View view) {
final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
if (mCustomNavView != null && showCustom) {
@@ -451,8 +390,8 @@ public class ActionBarView extends ViewGroup {
mHomeLayout.setVisibility(vis);
if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
- mHomeAsUpView.setVisibility((options & ActionBar.DISPLAY_HOME_AS_UP) != 0
- ? VISIBLE : GONE);
+ final boolean isUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+ mHomeAsUpView.setVisibility(isUp ? VISIBLE : GONE);
}
if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -480,6 +419,17 @@ public class ActionBarView extends ViewGroup {
} else {
invalidate();
}
+
+ // Make sure the home button has an accurate content description for accessibility.
+ if ((options & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
+ mHomeLayout.setContentDescription(null);
+ } else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_up_description));
+ } else {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_home_description));
+ }
}
public void setIcon(Drawable icon) {
@@ -648,6 +598,10 @@ public class ActionBarView extends ViewGroup {
}
}
+ public void updateTab(int position) {
+ ((TabView) mTabLayout.getChildAt(position)).update();
+ }
+
public void removeTabAt(int position) {
if (mTabLayout != null) {
mTabLayout.removeViewAt(position);
@@ -876,16 +830,6 @@ public class ActionBarView extends ViewGroup {
}
}
- private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
- child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
- childSpecHeight);
-
- availableWidth -= child.getMeasuredWidth();
- availableWidth -= spacing;
-
- return availableWidth;
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int x = getPaddingLeft();
@@ -998,68 +942,78 @@ public class ActionBarView extends ViewGroup {
}
}
- private int positionChild(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x, childTop, x + childWidth, childTop + childHeight);
-
- return childWidth;
- }
-
- private int positionChildInverse(View child, int x, int y, int contentHeight) {
- int childWidth = child.getMeasuredWidth();
- int childHeight = child.getMeasuredHeight();
- int childTop = y + (contentHeight - childHeight) / 2;
-
- child.layout(x - childWidth, childTop, x, childTop + childHeight);
-
- return childWidth;
- }
-
private static class TabView extends LinearLayout {
private ActionBar.Tab mTab;
+ private TextView mTextView;
+ private ImageView mIconView;
+ private View mCustomView;
public TabView(Context context, ActionBar.Tab tab) {
super(context, null, com.android.internal.R.attr.actionBarTabStyle);
mTab = tab;
+ update();
+
+ setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT, 1));
+ }
+
+ public void update() {
+ final ActionBar.Tab tab = mTab;
final View custom = tab.getCustomView();
if (custom != null) {
addView(custom);
+ mCustomView = custom;
+ if (mTextView != null) mTextView.setVisibility(GONE);
+ if (mIconView != null) {
+ mIconView.setVisibility(GONE);
+ mIconView.setImageDrawable(null);
+ }
} else {
- // TODO Style tabs based on the theme
+ if (mCustomView != null) {
+ removeView(mCustomView);
+ mCustomView = null;
+ }
final Drawable icon = tab.getIcon();
final CharSequence text = tab.getText();
if (icon != null) {
- ImageView iconView = new ImageView(context);
- iconView.setImageDrawable(icon);
- LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.CENTER_VERTICAL;
- iconView.setLayoutParams(lp);
- addView(iconView);
+ if (mIconView == null) {
+ ImageView iconView = new ImageView(getContext());
+ LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ lp.gravity = Gravity.CENTER_VERTICAL;
+ iconView.setLayoutParams(lp);
+ addView(iconView, 0);
+ mIconView = iconView;
+ }
+ mIconView.setImageDrawable(icon);
+ mIconView.setVisibility(VISIBLE);
+ } else if (mIconView != null) {
+ mIconView.setVisibility(GONE);
+ mIconView.setImageDrawable(null);
}
if (text != null) {
- TextView textView = new TextView(context, null,
- com.android.internal.R.attr.actionBarTabTextStyle);
- textView.setText(text);
- textView.setSingleLine();
- textView.setEllipsize(TruncateAt.END);
- LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.CENTER_VERTICAL;
- textView.setLayoutParams(lp);
- addView(textView);
+ if (mTextView == null) {
+ TextView textView = new TextView(getContext(), null,
+ com.android.internal.R.attr.actionBarTabTextStyle);
+ textView.setSingleLine();
+ textView.setEllipsize(TruncateAt.END);
+ LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.WRAP_CONTENT);
+ lp.gravity = Gravity.CENTER_VERTICAL;
+ textView.setLayoutParams(lp);
+ addView(textView);
+ mTextView = textView;
+ }
+ mTextView.setText(text);
+ mTextView.setVisibility(VISIBLE);
+ } else {
+ mTextView.setVisibility(GONE);
}
}
-
- setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT, 1));
}
public ActionBar.Tab getTab() {
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index 65973b6869c0..3070e3ebf194 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -29,7 +29,7 @@ import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewRoot;
+import android.view.ViewAncestor;
import com.android.internal.R;
public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
@@ -150,7 +150,7 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
KeyEvent event = events[i];
event = KeyEvent.changeFlags(event, event.getFlags()
| KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
- handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY, event));
+ handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY, event));
}
}
}
@@ -158,11 +158,11 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener {
public void sendDownUpKeyEvents(int keyEventCode) {
long eventTime = SystemClock.uptimeMillis();
Handler handler = mTargetView.getHandler();
- handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
- handler.sendMessage(handler.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME,
+ handler.sendMessage(handler.obtainMessage(ViewAncestor.DISPATCH_KEY_FROM_IME,
new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 290f5283a7a4..8beb94b71664 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -47,7 +47,8 @@ LOCAL_SRC_FILES:= \
android_emoji_EmojiFactory.cpp \
android_view_Display.cpp \
android_view_Surface.cpp \
- android_view_ViewRoot.cpp \
+ android_view_TextureView.cpp \
+ android_view_ViewAncestor.cpp \
android_view_InputChannel.cpp \
android_view_InputQueue.cpp \
android_view_KeyEvent.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a4a229a84359..17f9246ee70c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -118,7 +118,8 @@ extern int register_com_android_internal_graphics_NativeUtils(JNIEnv *env);
extern int register_android_view_Display(JNIEnv* env);
extern int register_android_view_GLES20Canvas(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
-extern int register_android_view_ViewRoot(JNIEnv* env);
+extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_ViewAncestor(JNIEnv* env);
extern int register_android_database_CursorWindow(JNIEnv* env);
extern int register_android_database_SQLiteCompiledSql(JNIEnv* env);
extern int register_android_database_SQLiteDatabase(JNIEnv* env);
@@ -1122,7 +1123,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Graphics),
REG_JNI(register_android_view_GLES20Canvas),
REG_JNI(register_android_view_Surface),
- REG_JNI(register_android_view_ViewRoot),
+ REG_JNI(register_android_view_TextureView),
+ REG_JNI(register_android_view_ViewAncestor),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
REG_JNI(register_android_opengl_jni_GLES10),
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 97580f54cde3..4687ee07f6fd 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -218,7 +218,7 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int
if (mCallbackBuffers.isEmpty()) {
LOGV("Out of buffers, clearing callback!");
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
mManualCameraCallbackSet = false;
if (obj == NULL) {
@@ -305,22 +305,22 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM
mManualCameraCallbackSet = false;
// In order to limit the over usage of binder threads, all non-manual buffer
- // callbacks use FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
+ // callbacks use CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER mode now.
//
// Continuous callbacks will have the callback re-registered from handleMessage.
// Manual buffer mode will operate as fast as possible, relying on the finite supply
// of buffers for throttling.
if (!installed) {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
clearCallbackBuffers_l(env, &mCallbackBuffers);
} else if (mManualBufferMode) {
if (!mCallbackBuffers.isEmpty()) {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
mManualCameraCallbackSet = true;
}
} else {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_BARCODE_SCANNER);
clearCallbackBuffers_l(env, &mCallbackBuffers);
}
}
@@ -343,7 +343,7 @@ void JNICameraContext::addCallbackBuffer(
// next frame. This may have come unset had we not had a
// callbackbuffer ready for it last time.
if (mManualBufferMode && !mManualCameraCallbackSet) {
- mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA);
+ mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_CAMERA);
mManualCameraCallbackSet = true;
}
break;
@@ -456,7 +456,7 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
// clear callbacks
if (camera != NULL) {
- camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
+ camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
camera->disconnect();
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 4a0e68e01a9b..548376df5296 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -40,6 +40,16 @@ int dhcp_do_request(const char *ifname,
const char *dns2,
const char *server,
uint32_t *lease);
+
+int dhcp_do_request_renew(const char *ifname,
+ const char *ipaddr,
+ const char *gateway,
+ uint32_t *prefixLength,
+ const char *dns1,
+ const char *dns2,
+ const char *server,
+ uint32_t *lease);
+
int dhcp_stop(const char *ifname);
int dhcp_release_lease(const char *ifname);
char *dhcp_get_errmsg();
@@ -57,7 +67,6 @@ namespace android {
static struct fieldIds {
jmethodID constructorId;
jfieldID ipaddress;
- jfieldID gateway;
jfieldID prefixLength;
jfieldID dns1;
jfieldID dns2;
@@ -145,7 +154,8 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstri
return (jint)result;
}
-static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
+ jobject info, bool renew)
{
int result;
char ipaddr[PROPERTY_VALUE_MAX];
@@ -159,12 +169,41 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
if (nameStr == NULL) return (jboolean)false;
- result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
- dns1, dns2, server, &lease);
+ if (renew) {
+ result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
+ } else {
+ result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
+ }
+
env->ReleaseStringUTFChars(ifname, nameStr);
if (result == 0) {
env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
- env->SetObjectField(info, dhcpInfoInternalFieldIds.gateway, env->NewStringUTF(gateway));
+
+ // set the gateway
+ jclass cls = env->FindClass("java/net/InetAddress");
+ jmethodID method = env->GetStaticMethodID(cls, "getByName",
+ "(Ljava/lang/String;)Ljava/net/InetAddress;");
+ jvalue args[1];
+ args[0].l = env->NewStringUTF(gateway);
+ jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args);
+
+ if (!env->ExceptionOccurred()) {
+ cls = env->FindClass("android/net/RouteInfo");
+ method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V");
+ args[0].l = inetAddressObject;
+ jobject routeInfoObject = env->NewObjectA(cls, method, args);
+
+ cls = env->FindClass("android/net/DhcpInfoInternal");
+ method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V");
+ args[0].l = routeInfoObject;
+ env->CallVoidMethodA(info, method, args);
+ } else {
+ // if we have an exception (host not found perhaps), just don't add the route
+ env->ExceptionClear();
+ }
+
env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength);
env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1));
env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2));
@@ -175,6 +214,17 @@ static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring if
return (jboolean)(result == 0);
}
+static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
+}
+
+static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
+}
+
+
static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -218,6 +268,7 @@ static JNINativeMethod gNetworkUtilMethods[] = {
{ "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute },
{ "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections },
{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp },
+ { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
@@ -229,7 +280,6 @@ int register_android_net_NetworkUtils(JNIEnv* env)
LOG_FATAL_IF(dhcpInfoInternalClass == NULL, "Unable to find class android/net/DhcpInfoInternal");
dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalClass, "<init>", "()V");
dhcpInfoInternalFieldIds.ipaddress = env->GetFieldID(dhcpInfoInternalClass, "ipAddress", "Ljava/lang/String;");
- dhcpInfoInternalFieldIds.gateway = env->GetFieldID(dhcpInfoInternalClass, "gateway", "Ljava/lang/String;");
dhcpInfoInternalFieldIds.prefixLength = env->GetFieldID(dhcpInfoInternalClass, "prefixLength", "I");
dhcpInfoInternalFieldIds.dns1 = env->GetFieldID(dhcpInfoInternalClass, "dns1", "Ljava/lang/String;");
dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalClass, "dns2", "Ljava/lang/String;");
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 9d17fe9a200e..e930c5c37638 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -419,7 +419,9 @@ static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject)
}
// reply comes back in the form "powermode = XX" where XX is the
// number we're interested in.
- sscanf(reply, "%*s = %u", &power);
+ if (sscanf(reply, "%*s = %u", &power) != 1) {
+ return (jint)-1;
+ }
return (jint)power;
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 06811953d999..b432d658adc4 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -282,6 +282,16 @@ protected:
code, (int32_t)&data, (int32_t)reply, flags);
jthrowable excep = env->ExceptionOccurred();
+ if (excep) {
+ report_exception(env, excep,
+ "*** Uncaught remote exception! "
+ "(Exceptions are not yet supported across processes.)");
+ res = JNI_FALSE;
+
+ /* clean up JNI local ref -- we don't return to Java code */
+ env->DeleteLocalRef(excep);
+ }
+
// Restore the Java binder thread's state if it changed while
// processing a call (as it would if the Parcel's header had a
// new policy mask and Parcel.enforceInterface() changed
@@ -294,14 +304,12 @@ protected:
set_dalvik_blockguard_policy(env, strict_policy_before);
}
- if (excep) {
- report_exception(env, excep,
- "*** Uncaught remote exception! "
- "(Exceptions are not yet supported across processes.)");
- res = JNI_FALSE;
-
+ jthrowable excep2 = env->ExceptionOccurred();
+ if (excep2) {
+ report_exception(env, excep2,
+ "*** Uncaught exception in onBinderStrictModePolicyChange");
/* clean up JNI local ref -- we don't return to Java code */
- env->DeleteLocalRef(excep);
+ env->DeleteLocalRef(excep2);
}
//aout << "onTransact to Java code; result=" << res << endl
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index af7639a541d8..d43a27f9feaa 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -24,6 +24,8 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/ResourceTypes.h>
+#include <gui/SurfaceTexture.h>
+
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkMatrix.h>
@@ -517,6 +519,11 @@ static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
return redraw;
}
+static void android_view_GLES20Canvas_outputDisplayList(JNIEnv* env,
+ jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
+ renderer->outputDisplayList(displayList);
+}
+
// ----------------------------------------------------------------------------
// Layers
// ----------------------------------------------------------------------------
@@ -577,10 +584,13 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
}
static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
- Layer* layer, jint width, jint height, jfloatArray texTransform) {
- jfloat* transform = env->GetFloatArrayElements(texTransform, NULL);
- LayerRenderer::updateTextureLayer(layer, width, height, transform);
- env->ReleaseFloatArrayElements(texTransform, transform, 0);
+ Layer* layer, jint width, jint height, SurfaceTexture* surface) {
+ float transform[16];
+ surface->updateTexImage();
+ surface->getTransformMatrix(transform);
+ GLenum renderTarget = surface->getCurrentTextureTarget();
+
+ LayerRenderer::updateTextureLayer(layer, width, height, renderTarget, transform);
}
static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, Layer* layer) {
@@ -709,7 +719,7 @@ static JNINativeMethod gMethods[] = {
{ "nGetDisplayListRenderer", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListRenderer },
{ "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_drawDisplayList },
-
+ { "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
{ "nInterrupt", "(I)V", (void*) android_view_GLES20Canvas_interrupt },
{ "nResume", "(I)V", (void*) android_view_GLES20Canvas_resume },
@@ -717,7 +727,7 @@ static JNINativeMethod gMethods[] = {
{ "nCreateLayer", "(IIZ[I)I", (void*) android_view_GLES20Canvas_createLayer },
{ "nResizeLayer", "(III[I)V" , (void*) android_view_GLES20Canvas_resizeLayer },
{ "nCreateTextureLayer", "([I)I", (void*) android_view_GLES20Canvas_createTextureLayer },
- { "nUpdateTextureLayer", "(III[F)V" , (void*) android_view_GLES20Canvas_updateTextureLayer },
+ { "nUpdateTextureLayer", "(IIII)V", (void*) android_view_GLES20Canvas_updateTextureLayer },
{ "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer },
{ "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
{ "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer },
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
new file mode 100644
index 000000000000..c5d86c87e588
--- /dev/null
+++ b/core/jni/android_view_TextureView.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 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 <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Native layer
+// ----------------------------------------------------------------------------
+
+static void android_view_TextureView_setDefaultBufferSize(JNIEnv* env, jobject,
+ jint surfaceTexture, jint width, jint height) {
+
+ sp<SurfaceTexture> surface = reinterpret_cast<SurfaceTexture*>(surfaceTexture);
+ surface->setDefaultBufferSize(width, height);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/TextureView";
+
+static JNINativeMethod gMethods[] = {
+ { "nSetDefaultBufferSize", "(III)V", (void*) android_view_TextureView_setDefaultBufferSize }
+};
+
+int register_android_view_TextureView(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/android_view_ViewRoot.cpp b/core/jni/android_view_ViewAncestor.cpp
index 2988ae8bd5aa..d8e1124a44dd 100644
--- a/core/jni/android_view_ViewRoot.cpp
+++ b/core/jni/android_view_ViewAncestor.cpp
@@ -35,7 +35,7 @@ namespace android {
static int gPrevDur;
-static void android_view_ViewRoot_showFPS(JNIEnv* env, jobject, jobject jcanvas,
+static void android_view_ViewAncestor_showFPS(JNIEnv* env, jobject, jobject jcanvas,
jint dur) {
NPE_CHECK_RETURN_VOID(env, jcanvas);
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
@@ -79,14 +79,14 @@ static void android_view_ViewRoot_showFPS(JNIEnv* env, jobject, jobject jcanvas,
// ----------------------------------------------------------------------------
-const char* const kClassPathName = "android/view/ViewRoot";
+const char* const kClassPathName = "android/view/ViewAncestor";
static JNINativeMethod gMethods[] = {
{ "nativeShowFPS", "(Landroid/graphics/Canvas;I)V",
- (void*)android_view_ViewRoot_showFPS }
+ (void*)android_view_ViewAncestor_showFPS }
};
-int register_android_view_ViewRoot(JNIEnv* env) {
+int register_android_view_ViewAncestor(JNIEnv* env) {
return AndroidRuntime::registerNativeMethods(env,
kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 5f2065a05cdb..f77752759dc3 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -27,6 +27,9 @@
#include <SkBitmap.h>
#include <SkPixelRef.h>
+#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
namespace android {
static jclass gConfig_class;
@@ -319,6 +322,35 @@ not_valid_surface:
return (jint)sur;
}
+static jint jni_eglCreateWindowSurfaceTexture(JNIEnv *_env, jobject _this, jobject display,
+ jobject config, jint native_window, jintArray attrib_list) {
+ if (display == NULL || config == NULL
+ || !validAttribList(_env, attrib_list)) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
+ return JNI_FALSE;
+ }
+ EGLDisplay dpy = getDisplay(_env, display);
+ EGLContext cnf = getConfig(_env, config);
+ sp<ANativeWindow> window;
+ if (native_window == 0) {
+not_valid_surface:
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Make sure the SurfaceTexture is valid");
+ return 0;
+ }
+
+ sp<SurfaceTexture> surfaceTexture = reinterpret_cast<SurfaceTexture*>(native_window);
+
+ window = new SurfaceTextureClient(surfaceTexture);
+ if (window == NULL)
+ goto not_valid_surface;
+
+ jint* base = beginNativeAttribList(_env, attrib_list);
+ EGLSurface sur = eglCreateWindowSurface(dpy, cnf, window.get(), base);
+ endNativeAttributeList(_env, attrib_list, base);
+ return (jint)sur;
+}
+
static jboolean jni_eglGetConfigAttrib(JNIEnv *_env, jobject _this, jobject display,
jobject config, jint attribute, jintArray value) {
if (display == NULL || config == NULL
@@ -508,6 +540,7 @@ static JNINativeMethod methods[] = {
{"_eglCreatePbufferSurface","(" DISPLAY CONFIG "[I)I", (void*)jni_eglCreatePbufferSurface },
{"_eglCreatePixmapSurface", "(" SURFACE DISPLAY CONFIG OBJECT "[I)V", (void*)jni_eglCreatePixmapSurface },
{"_eglCreateWindowSurface", "(" DISPLAY CONFIG OBJECT "[I)I", (void*)jni_eglCreateWindowSurface },
+{"_eglCreateWindowSurfaceTexture", "(" DISPLAY CONFIG "I[I)I", (void*)jni_eglCreateWindowSurfaceTexture },
{"eglDestroyContext", "(" DISPLAY CONTEXT ")Z", (void*)jni_eglDestroyContext },
{"eglDestroySurface", "(" DISPLAY SURFACE ")Z", (void*)jni_eglDestroySurface },
{"eglMakeCurrent", "(" DISPLAY SURFACE SURFACE CONTEXT")Z", (void*)jni_eglMakeCurrent },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2ed39e47082e..1c4bffdc1c43 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -496,6 +496,12 @@
android:label="@string/permlab_hardware_test"
android:description="@string/permdesc_hardware_test" />
+ <!-- Allows access to configure network interfaces, configure/use IPSec, etc.
+ @hide -->
+ <permission android:name="android.permission.NET_ADMIN"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature" />
+
<!-- =========================================== -->
<!-- Permissions associated with telephony state -->
<!-- =========================================== -->
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png
index 9c56e24688d5..615e8b3e7fe7 100755
--- a/core/res/res/drawable-hdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-hdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png
index 1400bb3df31b..6ba480d93aae 100644
--- a/core/res/res/drawable-mdpi/stat_sys_adb.png
+++ b/core/res/res/drawable-mdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index 67e6ac318008..c235005f2326 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
index 0cf422212758..d8b729debed2 100644
--- a/core/res/res/layout/action_bar_title_item.xml
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -28,5 +28,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
- android:ellipsize="end" />
+ android:ellipsize="end"
+ android:visibility="gone" />
</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index 14af446abf20..9742b9476e2e 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -43,7 +43,7 @@ This is an optimized layout for a screen with the Action Bar enabled.
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
- <LinearLayout android:id="@+id/lower_action_context_bar"
+ <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarStyle"
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
index aebbe411566f..086acdd132ff 100644
--- a/core/res/res/layout/screen_action_bar_overlay.xml
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -46,7 +46,7 @@ the Action Bar enabled overlaying application content.
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/action_bar_container" />
- <LinearLayout android:id="@+id/lower_action_context_bar"
+ <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index c64b90ea1daa..676c38b78830 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -1,56 +1,48 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingTop="7dp"
- android:paddingLeft="5dp"
- >
-
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:background="@drawable/notify_panel_notification_icon_bg"
+ android:scaleType="center"
+ />
<LinearLayout
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingTop="3dp"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
>
- <!--com.android.server.status.AnimatedImageView android:id="@+id/icon" -->
- <ImageView android:id="@+id/icon"
- android:layout_width="25dp"
- android:layout_height="25dp"
- android:scaleType="fitCenter"
- android:src="@drawable/arrow_down_float"/>
<TextView android:id="@+id/title"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
- android:paddingLeft="4dp"
+ android:layout_marginBottom="-3dp"
/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- >
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_marginTop="-2dp"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
- android:paddingLeft="4dp"
- />
- <android.widget.DateTimeView android:id="@+id/time"
- android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
- android:layout_marginLeft="4dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:paddingRight="5dp"
/>
</LinearLayout>
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:gravity="center_vertical"
+ android:paddingLeft="8dp"
+ />
</LinearLayout>
+
diff --git a/core/res/res/layout/status_bar_latest_event_content_large_icon.xml b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
new file mode 100644
index 000000000000..ebdaaa384994
--- /dev/null
+++ b/core/res/res/layout/status_bar_latest_event_content_large_icon.xml
@@ -0,0 +1,50 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ >
+ <TextView android:id="@+id/title"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:layout_marginBottom="-3dp"
+ />
+ <TextView android:id="@+id/text"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginTop="-2dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ />
+ </LinearLayout>
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:singleLine="true"
+ android:gravity="center_vertical"
+ android:paddingLeft="4dp"
+ android:paddingRight="4dp"
+ />
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_marginBottom="13dip"
+ android:scaleType="center"
+ />
+</LinearLayout>
+
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index fbf4161a814a..62e79f8bae9d 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -50,7 +50,7 @@
<string name="needPuk2" msgid="4526033371987193070">"Escriviu el PUK2 per desbloquejar la targeta SIM."</string>
<string name="ClipMmi" msgid="6952821216480289285">"Identificació de trucada entrant"</string>
<string name="ClirMmi" msgid="7784673673446833091">"Identificació de trucada de sortida"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Desviament de trucades"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"Desviació de trucades"</string>
<string name="CwMmi" msgid="9129678056795016867">"Trucada en espera"</string>
<string name="BaMmi" msgid="455193067926770581">"Restricció de trucades"</string>
<string name="PwdMmi" msgid="7043715687905254199">"Canvi de contrasenya"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 64da78f4b01e..acb9821f601e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -204,8 +204,8 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"Laufende Anwendungen neu ordnen"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
- <string name="permlab_removeTasks" msgid="4802740047161700683">"Aktive Anwendungen beenden"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"Ermöglicht einer Anwendung das Entfernen von Aufgaben und Beenden der entsprechenden Anwendungen. Schädliche Anwendungen können das Verhalten anderer Anwendungen stören."</string>
+ <string name="permlab_removeTasks" msgid="4802740047161700683">"Aktive Apps beenden"</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"Ermöglicht einer App das Entfernen von Aufgaben und Beenden der entsprechenden Apps. Schädliche Apps können das Verhalten anderer Apps stören."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 373f76c59868..2f1a1adae4aa 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -466,7 +466,7 @@
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modificar/eliminar contenido de la tarjeta SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Permite escribir en USB"</string>
<string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Permite que una aplicación escriba en la tarjeta SD."</string>
- <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Cambiar/borrar almac interno"</string>
+ <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar o eliminar el contenido del almacenamiento de medios interno"</string>
<string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Permite que una aplicación modifique el contenido del almacenamiento interno de medios."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"acceder al sistema de archivos almacenado en caché"</string>
<string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Permite que una aplicación lea y escriba el sistema de archivos almacenado en caché."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 1f0a94c33155..f112c33e6c7d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -204,7 +204,7 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Mengizinkan aplikasi mengambil informasi tentang tugas yang sedang dan baru saja dijalankan. Aplikasi hasad dapat menemukan informasi bajakan tentang aplikasi lain."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"atur urutan aplikasi yang berjalan"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Mengizinkan aplikasi memindah tugas ke latar depan dan latar belakang. Aplikasi hasad dapat memaksa dirinya ke latar depan tanpa sepengetahuan Anda."</string>
- <string name="permlab_removeTasks" msgid="4802740047161700683">"berhenti menjalankan aplikasi"</string>
+ <string name="permlab_removeTasks" msgid="4802740047161700683">"menghentikan aplikasi yang berjalan"</string>
<string name="permdesc_removeTasks" msgid="2000332928514575461">"Memungkinkan aplikasi menghapus tugas dan menghentikan aplikasinya. Aplikasi jahat dapat mengganggu perilaku aplikasi lain."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"aktifkan debugging aplikasi"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Mengizinkan aplikasi menghidupkan debug untuk aplikasi lain. Aplikasi hasad dapat menggunakan ini untuk menghentikan aplikasi penting lainnya."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 4d2b6c350a74..4d36eb3941cd 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -204,8 +204,8 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permite aplicaţiei să regăsească informaţii despre activităţile rulate curent şi recent. Poate permite aplicaţiilor rău-intenţionate să descopere informaţii confidenţiale despre alte aplicaţii."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reordonare aplicaţii aflate în derulare"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite unei aplicaţii să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău-intenţionate ar putea să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
- <string name="permlab_removeTasks" msgid="4802740047161700683">"opriţi aplicaţiile care rulează"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"Permite unei aplicaţii să elimine sarcinile şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
+ <string name="permlab_removeTasks" msgid="4802740047161700683">"oprirea aplicaţiilor care rulează"</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"Permite unei aplicaţii să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"activare depanare aplicaţie"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite unei aplicaţii să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău-intenţionate ar putea să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 6155536ecfbd..a81b2ee0059e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -205,7 +205,7 @@
<string name="permlab_reorderTasks" msgid="5669588525059921549">"zmena usporiadania spustených aplikácií"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Umožňuje aplikácii presúvať úlohy do popredia alebo pozadia. Škodlivé aplikácie môžu vynútiť svoje presunutia do popredia bez vášho pričinenia."</string>
<string name="permlab_removeTasks" msgid="4802740047161700683">"zastavenie činnosti aplikácií"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"Umožňuje aplikácii odstraňovať úlohy a ukončiť čínnosť súvisiacich aplikácií. Škodlivé aplikácie môžu narušovať správanie iných aplikácií."</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"Umožňuje aplikácii odstraňovať úlohy a ukončiť činnosť súvisiacich aplikácií. Škodlivé aplikácie môžu narušovať správanie iných aplikácií."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"povoliť ladenie aplikácií"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Umožňuje aplikácii povoliť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9c234a7711e5..545be3109433 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -205,7 +205,7 @@
<string name="permlab_reorderTasks" msgid="5669588525059921549">"重新安排執行中的應用程式"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"允許應用程式將工作移至前端或背景作業。請注意:惡意程式可能使用此功能自行把自己拉到前端。"</string>
<string name="permlab_removeTasks" msgid="4802740047161700683">"停止執行中的應用程式"</string>
- <string name="permdesc_removeTasks" msgid="2000332928514575461">"允許應用程式移除工作並且關閉應用程式。惡意應用程式會干擾其他應用程式的行為。"</string>
+ <string name="permdesc_removeTasks" msgid="2000332928514575461">"允許應用程式移除工作並且關閉應用程式。惡意應用程式會干擾其他應用程式的運行。"</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"啟用應用程式偵錯"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可利用此功能終止其他應用程式。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 348060439574..620d293e2c12 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -144,17 +144,20 @@
attributes. This is used by the connectivity manager to decide which networks can coexist
based on the hardware -->
<!-- An Array of "[Connection name],[ConnectivityManager connection type],
- [associated radio-type],[priority],[dependencyMet] -->
- <!-- the 5th element indicates boot-time dependency-met value. -->
+ [associated radio-type],[priority],[restoral-timer(ms)],[dependencyMet] -->
+ <!-- the 5th element "resore-time" indicates the number of milliseconds to delay
+ before automatically restore the default connection. Set -1 if the connection
+ does not require auto-restore. -->
+ <!-- the 6th element indicates boot-time dependency-met value. -->
<string-array translatable="false" name="networkAttributes">
- <item>"wifi,1,1,1,true"</item>
- <item>"mobile,0,0,0,true"</item>
- <item>"mobile_mms,2,0,2,true"</item>
- <item>"mobile_supl,3,0,2,true"</item>
- <item>"mobile_hipri,5,0,3,true"</item>
- <item>"mobile_fota,10,0,2,true"</item>
- <item>"mobile_ims,11,0,2,true"</item>
- <item>"mobile_cbs,12,0,2,true"</item>
+ <item>"wifi,1,1,1,-1,true"</item>
+ <item>"mobile,0,0,0,-1,true"</item>
+ <item>"mobile_mms,2,0,2,60000,true"</item>
+ <item>"mobile_supl,3,0,2,60000,true"</item>
+ <item>"mobile_hipri,5,0,3,60000,true"</item>
+ <item>"mobile_fota,10,0,2,60000,true"</item>
+ <item>"mobile_ims,11,0,2,60000,true"</item>
+ <item>"mobile_cbs,12,0,2,60000,true"</item>
</string-array>
<!-- This string array should be overridden by the device to present a list of radio
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bc419ec419ee..fa662ed19295 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2815,4 +2815,10 @@
<!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
<string name="number_picker_decrement_button">Decrement</string>
+ <!-- Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] -->
+ <string name="action_bar_home_description">Navigate home</string>
+ <!-- Content description for the action bar "up" affordance. [CHAR LIMIT=NONE] -->
+ <string name="action_bar_up_description">Navigate up</string>
+ <!-- Content description for the action menu overflow button. [CHAR LIMIT=NONE] -->
+ <string name="action_menu_overflow_description">More options</string>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index e66669877c71..2d44f62ba08f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -217,7 +217,6 @@
<style name="TextAppearance.StatusBar">
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="TextAppearance.StatusBar.Ticker">
</style>
@@ -226,15 +225,13 @@
</style>
<style name="TextAppearance.StatusBar.Icon">
- <item name="android:textStyle">bold</item>
</style>
<style name="TextAppearance.StatusBar.EventContent">
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="android:textColor">#ff999999</item>
+ <item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Title">
- <item name="android:textSize">18sp</item>
- <item name="android:textStyle">bold</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="TextAppearance.StatusBar.EventContent.Info">
<item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
@@ -1117,7 +1114,7 @@
<style name="Widget.ActionButton.Overflow">
<item name="android:src">@drawable/ic_menu_more</item>
- <item name="android:contentDescription">@string/more_item_label</item>
+ <item name="android:contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.ActionButton.CloseMode">
@@ -1778,6 +1775,7 @@
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
+ <item name="android:contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button">
@@ -2112,6 +2110,7 @@
<item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
+ <item name="android:contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Holo.Light.ActionBarView_TabView" parent="Widget.Holo.ActionBarView_TabView">
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index d22356dfe230..27363e828e1f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -30,6 +30,7 @@ import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.ProxySettings;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.util.Log;
import java.io.InputStream;
@@ -301,7 +302,7 @@ public class AccessPointParserHelper {
if (!InetAddress.isNumeric(gwAddr)) {
throw new SAXException();
}
- mLinkProperties.addGateway(InetAddress.getByName(gwAddr));
+ mLinkProperties.addRoute(new RouteInfo(InetAddress.getByName(gwAddr)));
} catch (UnknownHostException e) {
throw new SAXException();
}
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index 50666b4d0dad..e3b6b5f95050 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -17,6 +17,7 @@
package android.net;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
@@ -55,8 +56,8 @@ public class LinkPropertiesTest extends TestCase {
source.addDns(NetworkUtils.numericToInetAddress(DNS1));
source.addDns(NetworkUtils.numericToInetAddress(DNS2));
// set 2 gateways
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
LinkProperties target = new LinkProperties();
@@ -68,8 +69,8 @@ public class LinkPropertiesTest extends TestCase {
NetworkUtils.numericToInetAddress(ADDRV6), 128));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertTrue(source.equals(target));
assertTrue(source.hashCode() == target.hashCode());
@@ -83,8 +84,8 @@ public class LinkPropertiesTest extends TestCase {
NetworkUtils.numericToInetAddress(ADDRV6), 128));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
target.clear();
@@ -96,8 +97,8 @@ public class LinkPropertiesTest extends TestCase {
NetworkUtils.numericToInetAddress(ADDRV6), 128));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
target.clear();
@@ -109,8 +110,8 @@ public class LinkPropertiesTest extends TestCase {
// change dnses
target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
target.clear();
@@ -122,8 +123,8 @@ public class LinkPropertiesTest extends TestCase {
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
// change gateway
- target.addGateway(NetworkUtils.numericToInetAddress("75.208.8.2"));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
assertFalse(source.equals(target));
} catch (Exception e) {
@@ -146,8 +147,8 @@ public class LinkPropertiesTest extends TestCase {
source.addDns(NetworkUtils.numericToInetAddress(DNS1));
source.addDns(NetworkUtils.numericToInetAddress(DNS2));
// set 2 gateways
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
- source.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
LinkProperties target = new LinkProperties();
// Exchange order
@@ -158,8 +159,8 @@ public class LinkPropertiesTest extends TestCase {
NetworkUtils.numericToInetAddress(ADDRV4), 32));
target.addDns(NetworkUtils.numericToInetAddress(DNS2));
target.addDns(NetworkUtils.numericToInetAddress(DNS1));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY2));
- target.addGateway(NetworkUtils.numericToInetAddress(GATEWAY1));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
assertTrue(source.equals(target));
assertTrue(source.hashCode() == target.hashCode());
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index 477831e95fd5..909a8c9a845d 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -90,7 +90,7 @@ public class RequestFocusTest extends ActivityInstrumentationTestCase<RequestFoc
fail("requestFocus from wrong thread should raise exception.");
} catch (AndroidRuntimeException e) {
// Expected. The actual exception is not public, so we can't catch it.
- assertEquals("android.view.ViewRoot$CalledFromWrongThreadException",
+ assertEquals("android.view.ViewAncestor$CalledFromWrongThreadException",
e.getClass().getName());
}
}
diff --git a/core/tests/coretests/src/android/widget/listview/ListViewHeight.java b/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
index 64f280aa79c2..5cf3ff672e84 100644
--- a/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
+++ b/core/tests/coretests/src/android/widget/listview/ListViewHeight.java
@@ -88,7 +88,7 @@ public class ListViewHeight extends Activity {
// Clicking this button will remove the list adapter and hide the outer enclosing view.
// We have to climb all the way to the top because the bug (not checking visibility)
- // only occurs at the very outer loop of ViewRoot.performTraversals and in the case of
+ // only occurs at the very outer loop of ViewAncestor.performTraversals and in the case of
// an Activity, this means you have to crawl all the way out to the root view.
// In the search manager, it's sufficient to simply show/hide the outer search manager
// view to trigger the same bug.
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 1870a4a46055..5ed7966c92c7 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -66,6 +66,10 @@
<group gid="mtp" />
</permission>
+ <permission name="android.permission.NET_ADMIN" >
+ <group gid="net_admin" />
+ </permission>
+
<!-- The group that /cache belongs to, linked to the permission
set on the applications that can access /cache -->
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 46763c23f39d..5b8aa7af5d21 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -301,6 +301,17 @@
<li><a href="<?cs var:toroot?>guide/topics/nfc/index.html">
<span class="en">Near Field Communication</span></a>
<span class="new">new!</span></li>
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot?>guide/topics/usb/index.html">
+ <span class="en">USB</span></a>
+ <span class="new">new!</span>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/topics/usb/accessory.html">Accessory</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/usb/host.html">Host</a></li>
+ </ul>
+ </li>
+
<li><a href="<?cs var:toroot?>guide/topics/network/sip.html">
<span class="en">Session Initiation Protocol</span></a>
<span class="new">new!</span>
@@ -347,7 +358,6 @@
<a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html">
<span class="en">What To Test</span></a>
</li>
-
</ul>
</li>
</ul>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index b86a5f0836ab..7dddd9acc7ef 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -128,6 +128,60 @@ can require PIN or passwords to have at least six characters. </td> </tr>
combination of letters and numbers. They may include symbolic characters.
</td>
</tr>
+
+ <tr>
+ <td>Complex password required</td>
+ <td>Requires that passwords must contain at least a letter, a numerical digit, and a special symbol. Introduced in Android 3.0.
+ </td>
+ </tr>
+
+<tr>
+ <td>Minimum letters required in password</td> <td>The minimum number of
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+
+ <tr>
+ <td>Minimum lowercase letters required in password</td>
+ <td>The minimum number of lowercase
+letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+ <tr>
+ <td>Minimum non-letter characters required in password</td>
+ <td>The minimum number of
+non-letter characters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Minimum numerical digits required in password</td>
+ <td>The minimum number of numerical digits required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Minimum symbols required in password</td>
+ <td>The minimum number of symbols required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Minimum uppercase letters required in password</td>
+ <td>The minimum number of uppercase letters required in the password for all admins or a particular one. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Password expiration timeout</td>
+ <td>When the password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. Introduced in Android 3.0.</td>
+</tr>
+
+<tr>
+ <td>Password history restriction</td>
+ <td>This policy prevents users from reusing the last <em>n</em> unique passwords.
+ This policy is typically used in conjunction with
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()}, which forces
+users to update their passwords after a specified amount of time has elapsed.
+Introduced in Android 3.0.</td>
+</tr>
+
<tr>
<td>Maximum failed password attempts </td>
<td>Specifies how many times a user can enter the wrong password before the
@@ -141,6 +195,12 @@ device is lost or stolen.</td>
pressed a button before the device locks the screen. When this happens, users
need to enter their PIN or passwords again before they can use their devices and
access data. The value can be between 1 and 60 minutes.</td> </tr>
+
+<tr>
+<td>Require storage encryption</td>
+<td>Specifies that the storage area should be encrypted, if the device supports it.
+Introduced in Android 3.0.</td> </tr>
+
</table>
<h4>Other features</h4>
@@ -172,18 +232,28 @@ they've enabled the application, they can use the buttons in the user interface
to do the following:</p>
<ul>
<li>Set password quality.</li>
- <li>Specify the minimum length for the user's password.</li>
+ <li>Specify requirements for the user's password, such as minimum length, the minimum number of
+ numeric characters it must contain, and so on.</li>
<li>Set the password. If the password does not conform to the specified
policies, the system returns an error.</li>
<li>Set how many failed password attempts can occur before the device is wiped
(that is, restored to factory settings).</li>
+<li>Set how long from now the password will expire.</li>
+<li>Set the password history length (<em>length</em> refers to number of old passwords stored in the history).
+This prevents users from reusing
+one of the last <em>n</em> passwords they previously used.</li>
+<li>Specify that the storage area should be encrypted, if the device supports it.</li>
<li>Set the maximum amount of inactive time that can elapse before the device
locks.</li>
<li>Make the device lock immediately.</li>
<li>Wipe the device's data (that is, restore factory settings).</li>
+
</ul>
+
+
<img src="{@docRoot}images/admin/device-admin-app.png"/>
+
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Sample Application</p>
@@ -469,7 +539,13 @@ password containing at least <em>both</em> numeric <em>and</em> alphabetic (or
other symbol) characters.</dd>
<dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_NUMERIC}</dt><dd>The user must enter a password
containing at least numeric characters.</dd>
- <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_COMPLEX}</dt><dd>The user
+must have entered a password containing at least a letter, a numerical digit and
+a special symbol.</dd>
+<dt>{@link
+android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The
+policy requires some kind
of password, but doesn't care what it is.</dd>
<dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}</dt><dd>
The policy has no requirements for the password. </dd>
@@ -482,6 +558,36 @@ ComponentName mDeviceAdminSample;
mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
</pre>
+<h5>Set password content requirements</h5>
+
+<p>Beginning with Android 3.0, the {@link android.app.admin.DevicePolicyManager} class
+includes methods that let you fine-tune the contents of the password. For
+example, you could set a policy that states that passwords must contain at least
+<em>n</em> uppercase letters. Here are the methods for fine-tuning a password's
+contents:</p>
+<ul>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLetters(android.content.ComponentName,int) setPasswordMinimumLetters()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumLowerCase(android.content.ComponentName,int) setPasswordMinimumLowerCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumUpperCase(android.content.ComponentName,int) setPasswordMinimumUpperCase()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNonLetter(android.content.ComponentName,int) setPasswordMinimumNonLetter()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumNumeric(android.content.ComponentName,int) setPasswordMinimumNumeric()}</li>
+
+<li>{@link android.app.admin.DevicePolicyManager#setPasswordMinimumSymbols(android.content.ComponentName,int) setPasswordMinimumSymbols()}</li>
+</ul>
+<p>For example, this snippet states that the password must have at least 2 uppercase letters:</p>
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwMinUppercase = 2;
+...
+mDPM.setPasswordMinimumUpperCase(mDeviceAdminSample, pwMinUppercase);</pre>
+
+
<h5>Set the minimum password length</h5>
<p>You can specify that a password must be at least the specified minimum
length. For example:</p>
@@ -501,7 +607,86 @@ int maxFailedPw;
...
mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);</pre>
-<h4 id="lock">Set device lock</h4>
+<h5 id="expiration">Set password expiration timeout</h5>
+<p>Beginning with Android 3.0, you can use the
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()}
+method to set when a password will expire, expressed as a delta in milliseconds from when a device admin sets the expiration timeout. For example:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+long pwExpiration;
+...
+mDPM.setPasswordExpirationTimeout(mDeviceAdminSample, pwExpiration);
+</pre>
+
+<p>From the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/
+DeviceAdminSample.html"> Device Administration API sample</a>, here is the code
+that updates the password expiration status:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+private TextView mPasswordExpirationStatus;
+...
+void updatePasswordExpirationStatus() {
+ boolean active = mDPM.isAdminActive(mDeviceAdminSample);
+ String statusText;
+ if (active) {
+ long now = System.currentTimeMillis();
+ // Query the DevicePolicyManager twice - first for the expiration values
+ // set by the sample app, and later, for the system values (which may be different
+ // if there is another administrator active.)
+ long expirationDate = mDPM.getPasswordExpiration(mDeviceAdminSample);
+ long mSecUntilExpiration = expirationDate - now;
+ if (mSecUntilExpiration &gt;= 0) {
+ statusText = &quot;Expiration in &quot; + countdownString(mSecUntilExpiration);
+ } else {
+ statusText = &quot;Expired &quot; + countdownString(-mSecUntilExpiration) + &quot; ago&quot;;
+ }
+
+ // expirationTimeout is the cycle time between required password refresh
+ long expirationTimeout = mDPM.getPasswordExpirationTimeout(mDeviceAdminSample);
+ statusText += &quot; / timeout period &quot; + countdownString(expirationTimeout);
+
+ // Now report the aggregate (global) expiration time
+ statusText += &quot; / Aggregate &quot;;
+ expirationDate = mDPM.getPasswordExpiration(null);
+ mSecUntilExpiration = expirationDate - now;
+ if (mSecUntilExpiration &gt;= 0) {
+ statusText += &quot;expiration in &quot; + countdownString(mSecUntilExpiration);
+ } else {
+ statusText += &quot;expired &quot; + countdownString(-mSecUntilExpiration) + &quot; ago&quot;;
+ }
+ } else {
+ statusText = &quot;&lt;inactive&gt;&quot;;
+ }
+ mPasswordExpirationStatus.setText(statusText);</pre>
+
+<h5 id="history">Restrict password based on history</h5>
+
+<p>Beginning with Android 3.0, you can use the
+{@link android.app.admin.DevicePolicyManager#setPasswordHistoryLength(android.content.ComponentName,int) setPasswordHistoryLength()}
+method to limit users'
+ability to reuse old passwords. This method takes a <em>length</em>
+parameter, which specifies how many old
+passwords are stored. When this policy is active, users cannot enter a new
+password that matches the last <em>n</em> passwords. This prevents
+users from using the same password over and over. This policy is typically used
+in conjunction with
+{@link android.app.admin.DevicePolicyManager#setPasswordExpirationTimeout(android.content.ComponentName,long) setPasswordExpirationTimeout()},
+which forces users
+to update their passwords after a specified amount of time has elapsed. </p>
+
+<p>For example, this snippet prohibits users from reusing any of their last 5 passwords:</p>
+
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+int pwHistoryLength = 5;
+...
+mDPM.setPasswordHistoryLength(mDeviceAdminSample, pwHistoryLength);
+</pre>
+
+<h4 id="lock">Set device lock</h4>
<p>You can set the maximum period of user inactivity that can occur before the
device locks. For example:</p>
<pre>
@@ -516,6 +701,8 @@ mDPM.setMaximumTimeToLock(mDeviceAdminSample, timeMs);
DevicePolicyManager mDPM;
mDPM.lockNow();</pre>
+
+
<h4 id="wipe">Perform data wipe</h4>
<p>You can use the {@link android.app.admin.DevicePolicyManager} method
@@ -530,3 +717,20 @@ DevicePolicyManager mDPM;
mDPM.wipeData(0);</pre>
<p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
additional options. Currently the value must be 0. </p>
+
+<h4 id=storage">Storage encryption</h4>
+<p>Beginning with Android 3.0, you can use the
+{@link android.app.admin.DevicePolicyManager#setStorageEncryption(android.content.ComponentName,boolean) setStorageEncryption()}
+method to set a policy requiring encryption of the storage area, where supported.</p>
+
+<p>For example:</p>
+
+<pre>
+DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
+...
+mDPM.setStorageEncryption(mDeviceAdminSample, true);
+</pre>
+<p>
+See the <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.html"> Device Administration API sample</a> for a complete
+example of how to enable storage encryption.</p>
diff --git a/docs/html/guide/topics/graphics/animation.jd b/docs/html/guide/topics/graphics/animation.jd
index 3b1716cfd6ed..e10ab3ee34be 100644
--- a/docs/html/guide/topics/graphics/animation.jd
+++ b/docs/html/guide/topics/graphics/animation.jd
@@ -903,7 +903,7 @@ For more information on creating animators, see the sections on animating with
<code>"floatType"</code> unless you specify something else or if the <code>valuesFrom</code>
and <code>valuesTo</code> values are colors.</dd>
- <dt><code>android:startDelay</code></dt>
+ <dt><code>android:startOffset</code></dt>
<dd>The delay, in milliseconds, before the animation begins playing (after calling {@link
android.animation.ValueAnimator#start start()}).</dd>
diff --git a/docs/html/guide/topics/resources/menu-resource.jd b/docs/html/guide/topics/resources/menu-resource.jd
index 5c1eed03fb0a..5b90ce2fd181 100644
--- a/docs/html/guide/topics/resources/menu-resource.jd
+++ b/docs/html/guide/topics/resources/menu-resource.jd
@@ -49,14 +49,14 @@ In XML: <code>@[<em>package</em>:]menu.<em>filename</em></code>
android:alphabeticShortcut="<em>string</em>"
android:numericShortcut="<em>string</em>"
android:checkable=["true" | "false"]
- android:visible=["visible" | "invisible" | "gone"]
- android:enabled=["enabled" | "disabled"]
+ android:visible=["true" | "false"]
+ android:enabled=["true" | "false"]
android:menuCategory=["container" | "system" | "secondary" | "alternative"]
android:orderInCategory="<em>integer</em>" /&gt;
&lt;<a href="#group-element">group</a> android:id="@[+][<em>package</em>:]id/<em>resource name</em>"
android:checkableBehavior=["none" | "all" | "single"]
- android:visible=["visible" | "invisible" | "gone"]
- android:enabled=["enabled" | "disabled"]
+ android:visible=["true" | "false"]
+ android:enabled=["true" | "false"]
android:menuCategory=["container" | "system" | "secondary" | "alternative"]
android:orderInCategory="<em>integer</em>" &gt;
&lt;<a href="#item-element">item</a> /&gt;
diff --git a/docs/html/guide/topics/usb/accessory.jd b/docs/html/guide/topics/usb/accessory.jd
new file mode 100644
index 000000000000..b0f488170c06
--- /dev/null
+++ b/docs/html/guide/topics/usb/accessory.jd
@@ -0,0 +1,461 @@
+page.title=USB Accessory
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+
+ <ol>
+ <li>
+ <a href="#choosing">Choosing the Right USB Accessory APIs</a>
+
+ <ol>
+ <li><a href="#installing">Installing the Google APIs add-on library</a></li>
+ </ol>
+ </li>
+
+ <li>
+ <a href="#api">API Overview</a>
+
+ <ol>
+ <li><a href="#usage">Usage differences between the add-on library and the platform
+ APIs</a></li>
+ </ol>
+ </li>
+
+ <li><a href="#manifest">Android Manifest Requirements</a></li>
+
+ <li>
+ <a href="#working-a">Working with accessories</a>
+
+ <ol>
+ <li><a href="#discovering-a">Discovering an accessory</a></li>
+
+ <li><a href="#permission-a">Obtaining permission to communicate with an
+ accessory</a></li>
+
+ <li><a href="#communicating-a">Communicating with an accessory</a></li>
+
+ <li><a href="#terminating-a">Terminating communication with an accessory</a></li>
+ </ol>
+ </li>
+ </ol>
+
+ <h2>See also</h2>
+
+ <ol>
+ <li><a href="http://accessories.android.com/demokit">Android USB Accessory Development
+ Kit</a></li>
+ </ol>
+ </div>
+ </div>
+
+ <p>USB accessory mode allows users to connect
+ USB host hardware specifically designed for Android-powered devices. The accessories must adhere
+ to the Android accessory protocol outlined in the <a href=
+ "http://accessories.android.com/demokit">Android Accessory Development Kit</a> documentation.
+ This allows Android-powered devices that cannot act as a USB host to still interact with USB
+ hardware. When an Android-powered device is in USB accessory mode, the attached Android USB
+ accessory acts as the host, provides power to the USB bus, and enumerates connected devices.
+ Android 3.1 (API level 12) supports USB accessory mode and the feature is also backported to
+ Android 2.3.4 (API level 10) to enable support for a broader range of devices.</p>
+
+ <h2 id="choosing">Choosing the Right USB Accessory APIs</h2>
+
+ <p>Although the USB accessory APIs were introduced to the platform in Android 3.1, they are also
+ available in Android 2.3.4 using the Google APIs add-on library. Because these APIs were
+ backported using an external library, there are two packages that you can import to support USB
+ accessory mode. Depending on what Android-powered devices you want to support, you might have to
+ use one over the other:</p>
+
+ <ul>
+ <li><code>com.android.future.usb</code>: To support USB accessory mode in Android 2.3.4, the
+ <a href="http://code.google.com/android/add-ons/google-apis/index.html">Google APIs add-on
+ library</a> includes the backported USB accessory APIs and they are contained in this
+ namespace. Android 3.1 also supports importing and calling the classes within this namespace to
+ support applications written with the add-on library. This add-on library is a thin wrapper
+ around the {@link android.hardware.usb} accessory APIs and does not support USB host mode. If
+ you want to support the widest range of devices that support USB accessory mode, use the add-on
+ library and import this package. It is important to note that not all Android 2.3.4 devices are
+ required to support the USB accessory feature. Each individual device manufacturer decides
+ whether or not to support this capability, which is why you must declare it in your manifest
+ file.</li>
+
+ <li>{@link android.hardware.usb}: This namespace contains the classes that support USB
+ accessory mode in Android 3.1. This package is included as part of the framework APIs, so
+ Android 3.1 supports USB accessory mode without the use of an add-on library. Use this package
+ if you only care about Android 3.1 or newer devices that have hardware support for USB
+ accessory mode, which you can declare in your manifest file.</li>
+ </ul>
+
+ <h3 id="installing">Installing the Google APIs add-on library</h3>
+
+ <p>If you want to install the add-on, you can do so by installing the Google APIs Android API 10
+ package with the SDK Manager. See <a href=
+ "http://code.google.com/android/add-ons/google-apis/installing.html">Installing the Google APIs
+ Add-on</a> for more information on installing the add-on library.</p>
+
+ <h2 id="api">API Overview</h2>
+
+ <p>Because the add-on library is a wrapper for the framework APIs, the classes that support the
+ USB accessory feature are similar. You can use the reference documentation for the {@link
+ android.hardware.usb} even if you are using the add-on library.</p>
+
+ <p class="note"><strong>Note:</strong> There is, however, a minor <a href="#usage">usage
+ difference</a> between the add-on library and framework APIs that you should be aware of.</p>
+
+ <p>The following table describes the classes that support the USB accessory APIs:</p>
+
+ <table>
+ <tr>
+ <th>Class</th>
+
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbManager}</td>
+
+ <td>Allows you to enumerate and communicate with connected USB accessories.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbAccessory}</td>
+
+ <td>Represents a USB accessory and contains methods to access its identifying
+ information.</td>
+ </tr>
+ </table>
+
+ <h3 id="usage">Usage differences between the add-on library and platform APIs</h3>
+
+ <p>There are two usage differences between using the Google APIs add-on library and the platform
+ APIs.</p>
+
+ <p>If you are using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbManager} object in the following manner:</p>
+ <pre>
+UsbManager manager = UsbManager.getInstance(this);
+</pre>
+
+ <p>If you are not using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbManager} object in the following manner:</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+</pre>
+
+ <p>When you filter for a connected accessory with an intent filter, the {@link
+ android.hardware.usb.UsbAccessory} object is contained inside the intent that is passed to your
+ application. If you are using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbAccessory} object in the following manner:</p>
+ <pre>
+UsbAccessory accessory = UsbManager.getAccessory(intent);
+</pre>
+
+ <p>If you are not using the add-on library, you must obtain the {@link
+ android.hardware.usb.UsbAccessory} object in the following manner:</p>
+ <pre>
+UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+</pre>
+
+ <h2 id="manifest">Android Manifest requirements</h2>
+
+ <p>The following list describes what you need to add to your application's manifest file before
+ working with the USB accesory APIs. The <a href="#manifest-example">manifest and resource file
+ examples</a> show how to declare these items:</p>
+
+ <ul>
+ <li>Because not all Android-powered devices are guaranteed to support the USB accessory APIs,
+ include a <code>&lt;uses-feature&gt;</code> element that declares that your application uses
+ the <code>android.hardware.usb.accessory</code> feature.</li>
+
+ <li>If you are using the <a href="addon">add-on library</a>, add the
+ <code>&lt;uses-library&gt;</code> element specifying
+ <code>com.android.future.usb.accessory</code> for the library.</li>
+
+ <li>Set the minimum SDK of the application to API Level 10 if you are using the add-on library
+ or 12 if you are using the {@link android.hardware.usb} package.</li>
+
+ <li>
+ <p>If you want your application to be notified of an attached USB accessory, specify an
+ <code>&lt;intent-filter&gt;</code> and <code>&lt;meta-data&gt;</code> element pair for the
+ <code>android.hardware.usb.action.USB_ACCESSORY_ATTACHED</code> intent in your main activity.
+ The <code>&lt;meta-data&gt;</code> element points to an external XML resource file that
+ declares identifying information about the accessory that you want to detect.</p>
+
+ <p>In the XML resource file, declare <code>&lt;usb-accessory&gt;</code> elements for the
+ accessories that you want to filter. Each <code>&lt;usb-accessory&gt;</code> can have the
+ following attributes:</p>
+
+ <ul>
+ <li><code>manufacturer</code></li>
+
+ <li><code>model</code></li>
+
+ <li><code>version</code></li>
+ </ul>
+
+ <p>Save the resource file in the <code>res/xml/</code> directory. The resource file name
+ (without the .xml extension) must be the same as the one you specified in the
+ <code>&lt;meta-data&gt;</code> element. The format for the XML resource file is also shown in
+ the <a href="#example">example</a> below.</p>
+ </li>
+ </ul>
+
+ <h3 id="manifest-example">Manifest and resource file examples</h3>
+
+ <p>The following example shows a sample manifest and its corresponding resource file:</p>
+ <pre>
+&lt;manifest ...&gt;
+ &lt;uses-feature android:name="android.hardware.usb.accessory" /&gt;
+ <!-- version must be either 10 or 12 -->
+ &lt;uses-sdk android:minSdkVersion="&lt;<em>version</em>&gt;" /&gt;
+ ...
+ &lt;application&gt;
+ &lt;uses-library android:name="com.android.future.usb.accessory" /&gt;
+ &lt;activity ...&gt;
+ ...
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /&gt;
+ &lt;/intent-filter&gt;
+
+ &lt;meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" /&gt;
+ &lt;/activity&gt;
+ &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+ <p>In this case, the following resource file should be saved in
+ <code>res/xml/accessory_filter.xml</code> and specifies that any accessory that has the
+ corresponding model, manufacturer, and version should be filtered. The accessory sends these
+ attributes the Android-powered device:</p>
+ <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+ &lt;usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/&gt;
+&lt;/resources&gt;
+</pre>
+
+ <h2 id="working-a">Working with Accessories</h2>
+
+ <p>When users connect USB accessories to an Android-powered device, the Android system can
+ determine whether your application is interested in the connected accessory. If so, you can set
+ up communication with the accessory if desired. To do this, your application has to:</p>
+
+ <ol>
+ <li>Discover connected accessories by using an intent filter that filters for accessory
+ attached events or by enumerating connected accessories and finding the appropriate one.</li>
+
+ <li>Ask the user for permission to communicate with the accessory, if not already
+ obtained.</li>
+
+ <li>Communicate with the accessory by reading and writing data on the appropriate interface
+ endpoints.</li>
+ </ol>
+
+ <h3 id="discovering-a">Discovering an accessory</h3>
+
+ <p>Your application can discover accessories by either using an intent filter to be notified when
+ the user connects an accessory or by enumerating accessories that are already connected. Using an
+ intent filter is useful if you want to be able to have your application automatically detect a
+ desired accessory. Enumerating connected accessories is useful if you want to get a list of all
+ connected accessories or if your application did not filter for an intent.</p>
+
+ <h4 id="discover-a-intent">Using an intent filter</h4>
+
+ <p>To have your application discover a particular USB accessory, you can specify an intent filter
+ to filter for the <code>android.hardware.usb.action.USB_ACCESSORY_ATTACHED</code> intent. Along
+ with this intent filter, you need to specify a resource file that specifies properties of the USB
+ accessory, such as manufacturer, model, and version. When users connect an accessory that matches
+ your accessory filter,</p>
+
+ <p>The following example shows how to declare the intent filter:</p>
+ <pre>
+&lt;activity ...&gt;
+ ...
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" /&gt;
+ &lt;/intent-filter&gt;
+
+ &lt;meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" /&gt;
+&lt;/activity&gt;
+</pre>
+
+ <p>The following example shows how to declare the corresponding resource file that specifies the
+ USB accessories that you're interested in:</p>
+ <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+ &lt;usb-accessory manufacturer="Google, Inc." model="DemoKit" version="1.0" /&gt;
+&lt;/resources&gt;
+</pre>
+
+ <p>In your activity, you can obtain the {@link android.hardware.usb.UsbAccessory} that represents
+ the attached accessory from the intent like this (with the add-on library):</p>
+ <pre>
+UsbAccessory accessory = UsbManager.getAccessory(intent);
+</pre>
+
+ <p>or like this (with the platform APIs):</p>
+ <pre>
+UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+</pre>
+
+ <h4 id="discover-a-enumerate">Enumerating accessories</h4>
+
+ <p>You can have your application enumerate accesories that have identified themselves while your
+ application is running.</p>
+
+ <p>Use the {@link android.hardware.usb.UsbManager#getAccessoryList() getAccessoryList()} method
+ to get an array all the USB accessories that are connected:</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+UsbAccessory[] accessoryList = manager.getAcccessoryList();
+</pre>
+
+ <p class="note"><strong>Note:</strong> Currently, only one connected accessory is supported at
+ one time, but the API is designed to support multiple accessories in the future.</p>
+
+ <h3 id="permission-a">Obtaining permission to communicate with an accessory</h3>
+
+ <p>Before communicating with the USB accessory, your applicaton must have permission from your
+ users.</p>
+
+ <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
+ intent filter</a> to discover accessories as they're connected, it automatically receives
+ permission if the user allows your application to handle the intent. If not, you must request
+ permission explicitly in your application before connecting to the accessory.</p>
+
+ <p>Explicitly asking for permission might be neccessary in some situations such as when your
+ application enumerates accessories that are already connected and then wants to communicate with
+ one. You must check for permission to access an accessory before trying to communicate with it.
+ If not, you will receive a runtime error if the user denied permission to access the
+ accessory.</p>
+
+ <p>To explicitly obtain permission, first create a broadcast receiver. This receiver listens for
+ the intent that gets broadcast when you call {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()}. The call to {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()} displays a dialog to the
+ user asking for permission to connect to the accessory. The following sample code shows how to
+ create the broadcast receiver:</p>
+ <pre>
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ACTION_USB_PERMISSION.equals(action)) {
+ synchronized (this) {
+ UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ if(accessory != null){
+ //call method to set up accessory communication
+ }
+ }
+ else {
+ Log.d(TAG, "permission denied for accessory " + accessory);
+ }
+ }
+ }
+ }
+};
+</pre>
+
+ <p>To register the broadcast receiver, put this in your <code>onCreate()</code> method in your
+ activity:</p>
+ <pre>
+UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+...
+mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+registerReceiver(mUsbReceiver, filter);
+</pre>
+
+ <p>To display the dialog that asks users for permission to connect to the accessory, call the
+ {@link android.hardware.usb.UsbManager#requestPermission requestPermission()} method:</p>
+ <pre>
+UsbAccessory accessory;
+...
+mUsbManager.requestPermission(accessory, mPermissionIntent);
+</pre>
+
+ <p>When users reply to the dialog, your broadcast receiver receives the intent that contains the
+ {@link android.hardware.usb.UsbManager#EXTRA_PERMISSION_GRANTED} extra, which is a boolean
+ representing the answer. Check this extra for a value of true before connecting to the
+ accessory.</p>
+
+ <h3 id="communicating-a">Communicating with an accessory</h3>
+
+ <p>You can communicate with the accessory by using the {@link android.hardware.usb.UsbManager} to
+ obtain a file descriptor that you can set up input and output streams to read and write data to
+ descriptor. The streams represent the accessory's input and output bulk endpoints. You should set
+ up the communication between the device and accessory in another thread, so you don't lock the
+ main UI thread. The following example shows how to open an accessory to communicate with:</p>
+ <pre>
+UsbAccessory mAccessory;
+ParcelFileDescriptor mFileDescriptor;
+FileInputStream mInputStream;
+FileOutputStream mOutputStream;
+
+...
+
+private void openAccessory() {
+ Log.d(TAG, "openAccessory: " + accessory);
+ mFileDescriptor = mUsbManager.openAccessory(mAccessory);
+ if (mFileDescriptor != null) {
+ FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+ mInputStream = new FileInputStream(fd);
+ mOutputStream = new FileOutputStream(fd);
+ Thread thread = new Thread(null, this, "AccessoryThread");
+ thread.start();
+ }
+}
+</pre>
+
+ <p>In the thread's <code>run()</code> method, you can read and write to the accessory by using
+ the {@link java.io.FileInputStream} or {@link java.io.FileOutputStream} objects. When reading
+ data from an accessory with a {@link java.io.FileInputStream} object, ensure that the buffer that
+ you use is big enough to store the USB packet data. The Android accessory protocol supports
+ packet buffers up to 16384 bytes, so you can choose to always declare your buffer to be of this
+ size for simplicity.</p>
+
+ <p class="note"><strong>Note:</strong> At a lower level, the packets are 64 bytes for USB
+ full-speed accessories and 512 bytes for USB high-speed accessories. The Android accessory
+ protocol bundles the packets together for both speeds into one logical packet for simplicity.</p>
+
+ <p>For more information about using threads in Android, see <a href=
+ "{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes and
+ Threads</a>.</p>
+
+ <h3 id="terminating-a">Terminating communication with an accessory</h3>
+
+ <p>When you are done communicating with an accessory or if the accessory was detached, close the
+ file descriptor that you opened by calling {@link android.os.ParcelFileDescriptor#close close()}.
+ To listen for detached events, create a broadcast receiver like below:</p>
+ <pre>
+BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+ UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (accessory != null) {
+ // call your method that cleans up and closes communication with the accessory
+ }
+ }
+ }
+};
+</pre>
+
+ <p>Creating the broadcast receiver within the application, and not the manifest, allows your
+ application to only handle detached events while it is running. This way, detached events are
+ only sent to the application that is currently running and not broadcast to all applications.</p>
+
diff --git a/docs/html/guide/topics/usb/host.jd b/docs/html/guide/topics/usb/host.jd
new file mode 100644
index 000000000000..942708dabf74
--- /dev/null
+++ b/docs/html/guide/topics/usb/host.jd
@@ -0,0 +1,443 @@
+page.title=USB Host
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+
+ <ol>
+ <li><a href="#api">API Overview</a></li>
+
+ <li><a href="#usage">Android Manifest Requirements</a></li>
+
+ <li>
+ <a href="#working-d">Working with devices</a>
+
+ <ol>
+ <li><a href="#discovering-d">Discovering a device</a></li>
+
+ <li><a href="#permission-d">Obtaining permission to communicate with a device</a></li>
+
+ <li><a href="#communicating-d">Communicating with a device</a></li>
+
+ <li><a href="#terminating-d">Terminating communication with a device</a></li>
+ </ol>
+ </li>
+ </ol>
+
+ <h2>Related Samples</h2>
+
+ <ol>
+ <li><a href="{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest</a></li>
+
+ <li><a href=
+ "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher</a></li>
+ </ol>
+ </div>
+ </div>
+
+ <p>When your Android-powered device is in USB host mode, it acts as the USB host, powers the bus,
+ and enumerates connected USB devices. USB host mode is supported in Android 3.1 and higher.</p>
+
+ <h2 id="api">API Overview</h2>
+
+ <p>Before you begin, it is important to understand the classes that you need to work with. The
+ following table describes the USB host APIs in the {@link android.hardware.usb} package.</p>
+
+ <p class="table-caption"><strong>Table 1.</strong> USB Host APIs</p>
+
+ <table>
+ <tr>
+ <th>Class</th>
+
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbManager}</td>
+
+ <td>Allows you to enumerate and communicate with connected USB devices.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbDevice}</td>
+
+ <td>Represents a connected USB device and contains methods to access its identifying
+ information, interfaces, and endpoints.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbInterface}</td>
+
+ <td>Represents an interface of a USB device, which defines a set of functionality for the
+ device. A device can have one or more interfaces on which to communicate on.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbEndpoint}</td>
+
+ <td>Represents an interface endpoint, which is a communication channel for this interface. An
+ interface can have one or more endpoints, and usually has input and output endpoints for
+ two-way communication with the device.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbDeviceConnection}</td>
+
+ <td>Represents a connection to the device, which transfers data on endpoints. This class
+ allows you to send data back and forth sychronously or asynchronously.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbRequest}</td>
+
+ <td>Represents an asynchronous request to communicate with a device through a {@link
+ android.hardware.usb.UsbDeviceConnection}.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.hardware.usb.UsbConstants}</td>
+
+ <td>Defines USB constants that correspond to definitions in linux/usb/ch9.h of the Linux
+ kernel.</td>
+ </tr>
+ </table>
+
+ <p>In most situations, you need to use all of these classes ({@link
+ android.hardware.usb.UsbRequest} is only required if you are doing asynchronous communication)
+ when communicating with a USB device. In general, you obtain a {@link
+ android.hardware.usb.UsbManager} to retrieve the desired {@link android.hardware.usb.UsbDevice}.
+ When you have the device, you need to find the appropriate {@link
+ android.hardware.usb.UsbInterface} and the {@link android.hardware.usb.UsbEndpoint} of that
+ interface to communicate on. Once you obtain the correct endpoint, open a {@link
+ android.hardware.usb.UsbDeviceConnection} to communicate with the USB device.</p>
+
+ <h2 id="manifest">Android Manifest Requirements</h2>
+
+ <p>The following list describes what you need to add to your application's manifest file before
+ working with the USB host APIs:</p>
+
+ <ul>
+ <li>Because not all Android-powered devices are guaranteed to support the USB host APIs,
+ include a <code>&lt;uses-feature&gt;</code> element that declares that your application uses
+ the <code>android.hardware.usb.host</code> feature.</li>
+
+ <li>Set the minimum SDK of the application to API Level 12 or higher. The USB host APIs are not
+ present on earlier API levels.</li>
+
+ <li>If you want your application to be notified of an attached USB device, specify an
+ <code>&lt;intent-filter&gt;</code> and <code>&lt;meta-data&gt;</code> element pair for the
+ <code>android.hardware.usb.action.USB_DEVICE_ATTACHED</code> intent in your main activity. The
+ <code>&lt;meta-data&gt;</code> element points to an external XML resource file that declares
+ identifying information about the device that you want to detect.
+
+ <p>In the XML resource file, declare <code>&lt;usb-device&gt;</code> elements for the USB
+ devices that you want to filter. The following list describes the attributes of
+ <code>&lt;usb-device&gt;</code>. In general, use vendor and product ID if you want to filter
+ for a specific device and use class, subclass, and protocol if you want to filter for a group
+ of USB devices, such as mass storage devices or digital cameras.</p>
+
+ <ul>
+ <li><code>vendor-id</code></li>
+
+ <li><code>product-id</code></li>
+
+ <li><code>class</code></li>
+
+ <li><code>subclass</code></li>
+
+ <li><code>protocol</code> (device or interface)</li>
+ </ul>
+
+ <p>Save the resource file in the <code>res/xml/</code> directory. The resource file name
+ (without the .xml extension) must be the same as the one you specified in the
+ <code>&lt;meta-data&gt;</code> element. The format for the XML resource file is in the
+ <a href="#example">example</a> below.</p>
+ </li>
+ </ul>
+
+ <h3 id="manifest-example">Manifest and resource file examples</h3>
+
+ <p>The following example shows a sample manifest and its corresponding resource file:</p>
+ <pre>
+&lt;manifest ...&gt;
+ &lt;uses-feature android:name="android.hardware.usb.host" /&gt;
+ &lt;uses-sdk android:minSdkVersion="12" /&gt;
+ ...
+ &lt;application&gt;
+ &lt;activity ...&gt;
+ ...
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /&gt;
+ &lt;/intent-filter&gt;
+
+ &lt;meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+ android:resource="@xml/device_filter" /&gt;
+ &lt;/activity&gt;
+ &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+ <p>In this case, the following resource file should be saved in
+ <code>res/xml/device_filter.xml</code> and specifies that any USB device with the corresponding
+ vendor ID and product ID should be filtered. These IDs are specific to the device and are
+ specified by the device's manufacturer:</p>
+ <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+ &lt;usb-device vendor-id="1234" product-id="5678" /&gt;
+&lt;/resources&gt;
+</pre>
+
+ <h2 id="working-d">Working with Devices</h2>
+
+ <p>When users connect USB devices to an Android-powered device, the Android system can determine
+ whether your application is interested in the connected device. If so, you can set up
+ communication with the device if desired. To do this, your application has to:</p>
+
+ <ol>
+ <li>Discover connected USB devices by using an intent filter to be notified when the user
+ connects a USB device or by enumerating USB devices that are already connected.</li>
+
+ <li>Ask the user for permission to connect to the USB device, if not already obtained.</li>
+
+ <li>Communicate with the USB device by reading and writing data on the appropriate interface
+ endpoints.</li>
+ </ol>
+
+ <h3 id="discovering-d">Discovering a device</h3>
+
+ <p>Your application can discover USB devices by either using an intent filter to be notified when
+ the user connects a device or by enumerating USB devices that are already connected. Using an
+ intent filter is useful if you want to be able to have your application automatically detect a
+ desired device. Enumerating connected USB devices is useful if you want to get a list of all
+ connected devices or if your application did not filter for an intent.</p>
+
+ <h4 id="using-intents">Using an intent filter</h4>
+
+ <p>To have your application discover a particular USB device, you can specify an intent filter to
+ filter for the <code>android.hardware.usb.action.USB_DEVICE_ATTACHED</code> intent. Along with
+ this intent filter, you need to specify a resource file that specifies properties of the USB
+ device, such as product and vendor ID. When users connect a device that matches your device
+ filter, the system presents them with a dialog that asks if they want to start your application.
+ If users accept, your application automatically has permission to access the device until the
+ device is disconnected.</p>
+
+ <p>The following example shows how to declare the intent filter:</p>
+ <pre>
+&lt;activity ...&gt;
+...
+ &lt;intent-filter&gt;
+ &lt;action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /&gt;
+ &lt;/intent-filter&gt;
+
+ &lt;meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
+ android:resource="@xml/device_filter" /&gt;
+&lt;/activity&gt;
+</pre>
+
+ <p>The following example shows how to declare the corresponding resource file that specifies the
+ USB devices that you're interested in:</p>
+ <pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+
+&lt;resources&gt;
+ &lt;usb-device vendor-id="1234" product-id="5678" /&gt;
+&lt;/resources&gt;
+</pre><!-- REMEMBER TO ADD PROTOCOL, and device class and subclass, if applicable -->
+
+ <p>In your activity, you can obtain the {@link android.hardware.usb.UsbDevice} that represents
+ the attached device from the intent like this:</p>
+ <pre>
+UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+</pre>
+
+ <h4>Enumerating devices</h4>
+
+ <p>If your application is interested in inspecting all of the USB devices currently connected
+ while your application is running, it can enumerate devices on the bus. Use the {@link
+ android.hardware.usb.UsbManager#getDeviceList() getDeviceList()} method to get a hash map of all
+ the USB devices that are connected. The hash map is keyed by the USB device's name if you want to
+ obtain a device from the map.</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+...
+HashMap&lt;String, UsbDevice&gt; deviceList = manager.getDeviceList();
+Iterator&lt;UsbDevice&gt; deviceIterator = deviceList.values().iterator();
+while(deviceIterator.hasNext()){
+ UsbDevice device = deviceIterator.next();
+ // your code
+}
+</pre>
+
+ <p>If desired, you can also just obtain an iterator from the hash map and process each device one
+ by one:</p>
+ <pre>
+UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+...
+HashMap&lt;String, UsbDevice&gt; deviceList = manager.getDeviceList();
+Iterator&lt;UsbDevice&gt; deviceIterator = deviceList.values().iterator();
+while(deviceIterator.hasNext()){
+ UsbDevice device = deviceIterator.next()
+ //your code
+}
+</pre>
+
+ <h3 id="permission-d">Obtaining permission to communicate with a device</h3>
+
+ <p>Before communicating with the USB device, your applicaton must have permission from your
+ users.</p>
+
+ <p class="note"><strong>Note:</strong> If your application <a href="#using-intents">uses an
+ intent filter</a> to discover USB devices as they're connected, it automatically receives
+ permission if the user allows your application to handle the intent. If not, you must request
+ permission explicitly in your application before connecting to the device.</p>
+
+ <p>Explicitly asking for permission might be neccessary in some situations such as when your
+ application enumerates USB devices that are already connected and then wants to communicate with
+ one. You must check for permission to access a device before trying to communicate with it. If
+ not, you will receive a runtime error if the user denied permission to access the device.</p>
+
+ <p>To explicitly obtain permission, first create a broadcast receiver. This receiver listens for
+ the intent that gets broadcast when you call {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()}. The call to {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()} displays a dialog to the
+ user asking for permission to connect to the device. The following sample code shows how to
+ create the broadcast receiver:</p>
+ <pre>
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ACTION_USB_PERMISSION.equals(action)) {
+ synchronized (this) {
+ UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ if(device != null){
+ //call method to set up device communication
+ }
+ }
+ else {
+ Log.d(TAG, "permission denied for device " + device);
+ }
+ }
+ }
+ }
+};
+</pre>
+
+ <p>To register the broadcast receiver, add this in your <code>onCreate()</code> method in your
+ activity:</p>
+ <pre>
+UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+private static final String ACTION_USB_PERMISSION =
+ "com.android.example.USB_PERMISSION";
+...
+mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+registerReceiver(mUsbReceiver, filter);
+</pre>
+
+ <p>To display the dialog that asks users for permission to connect to the device, call the {@link
+ android.hardware.usb.UsbManager#requestPermission requestPermission()} method:</p>
+ <pre>
+UsbDevice device;
+...
+mUsbManager.requestPermission(device, mPermissionIntent);
+</pre>
+
+ <p>When users reply to the dialog, your broadcast receiver receives the intent that contains the
+ {@link android.hardware.usb.UsbManager#EXTRA_PERMISSION_GRANTED} extra, which is a boolean
+ representing the answer. Check this extra for a value of true before connecting to the
+ device.</p>
+
+ <h3 id="communicating-d">Communicating with a device</h3>
+
+ <p>Communication with a USB device can be either synchronous or asynchronous. In either case, you
+ should create a new thread on which to carry out all data transmissions, so you don't block the
+ UI thread. To properly set up communication with a device, you need to obtain the appropriate
+ {@link android.hardware.usb.UsbInterface} and {@link android.hardware.usb.UsbEndpoint} of the
+ device that you want to communicate on and send requests on this endpoint with a {@link
+ android.hardware.usb.UsbDeviceConnection}. In general, your code should:</p>
+
+ <ul>
+ <li>Check a {@link android.hardware.usb.UsbDevice} object's attributes, such as product ID,
+ vendor ID, or device class to figure out whether or not you want to communicate with the
+ device.</li>
+
+ <li>When you are certain that you want to communicate with the device, find the appropriate
+ {@link android.hardware.usb.UsbInterface} that you want to use to communicate along with the
+ appropriate {@link android.hardware.usb.UsbEndpoint} of that interface. Interfaces can have one
+ or more endpoints, and commonly will have an input and output endpoint for two-way
+ communication.</li>
+
+ <li>When you find the correct endpoint, open a {@link android.hardware.usb.UsbDeviceConnection}
+ on that endpoint.</li>
+
+ <li>Supply the data that you want to transmit on the endpoint with the {@link
+ android.hardware.usb.UsbDeviceConnection#bulkTransfer bulkTransfer()} or {@link
+ android.hardware.usb.UsbDeviceConnection#controlTransfer controlTransfer()} method. You should
+ carry out this step in another thread to prevent blocking the main UI thread. For more
+ information about using threads in Android, see <a href=
+ "{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes and
+ Threads</a>.</li>
+ </ul>
+
+ <p>The following code snippet is a trivial way to do a synchronous data transfer. Your code
+ should have more logic to correctly find the correct interface and endpoints to communicate on
+ and also should do any transferring of data in a different thread than the main UI thread:</p>
+ <pre>
+private Byte[] bytes
+private static int TIMEOUT = 0;
+private boolean forceClaim = true;
+
+...
+
+UsbInterface intf = device.getInterface(0);
+UsbEndpoint endpoint = intf.getEndpoint(0);
+UsbDeviceConnection connection = mUsbManager.openDevice(device);
+connection.claimInterface(intf, forceClaim);
+connection.bulkTransfer(endpoint, bytes, bytes.length, TIMEOUT); //do in another thread
+</pre>
+
+ <p>To send data asynchronously, use the {@link android.hardware.usb.UsbRequest} class to {@link
+ android.hardware.usb.UsbRequest#initialize initialize} and {@link
+ android.hardware.usb.UsbRequest#queue queue} an asynchronous request, then wait for the result
+ with {@link android.hardware.usb.UsbDeviceConnection#requestWait requestWait()}.</p>
+
+ <p>For more information, see the <a href=
+ "{@docRoot}resources/samples/USB/AdbTest/index.html">AdbTest sample</a>, which shows how to do
+ asynchronous bulk transfers, and the <a href=
+ "{@docRoot}resources/samples/USB/MissileLauncher/index.html">MissleLauncher sample</a>, which
+ shows how to listen on an interrupt endpoint asynchronously.</p>
+
+ <h3 id="terminating-d">Terminating communication with a device</h3>
+
+ <p>When you are done communicating with a device or if the device was detached, close the {@link
+ android.hardware.usb.UsbInterface} and {@link android.hardware.usb.UsbDeviceConnection} by
+ calling {@link android.hardware.usb.UsbDeviceConnection#releaseInterface releaseInterface()} and
+ {@link android.hardware.usb.UsbDeviceConnection#close() close()}. To listen for detached events,
+ create a broadcast receiver like below:</p>
+ <pre>
+BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
+ UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ if (device != null) {
+ // call your method that cleans up and closes communication with the device
+ }
+ }
+ }
+};
+</pre>
+
+ <p>Creating the broadcast receiver within the application, and not the manifest, allows your
+ application to only handle detached events while it is running. This way, detached events are
+ only sent to the application that is currently running and not broadcast to all applications.</p>
+
diff --git a/docs/html/guide/topics/usb/index.jd b/docs/html/guide/topics/usb/index.jd
new file mode 100644
index 000000000000..18af06ac666c
--- /dev/null
+++ b/docs/html/guide/topics/usb/index.jd
@@ -0,0 +1,67 @@
+page.title=USB Host and Accessory
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>Topics</h2>
+
+ <ol>
+ <li><a href="{@docRoot}/guide/topics/USB/accessory.jd">USB Accessory</a></li>
+
+ <li><a href="{@docRoot}/guide/topics/USB/host.jd">USB Host</a></li>
+ </ol>
+ </div>
+ </div>
+
+ <p>Android supports a variety of USB peripherals and Android USB accessories (hardware that
+ implements the Android accessory protocol) through two modes: USB accessory and USB host. In USB
+ accessory mode, the external USB hardware act as the USB hosts. Examples of accessories might
+ include robotics controllers; docking stations; diagnostic and musical equipment; kiosks; card
+ readers; and much more. This gives Android-powered devices that do not have host capabilities the
+ ability to interact with USB hardware. Android USB accessories must be designed to work with
+ Android-powered devices and must adhere to the <a href=
+ "http://accessories.android.com/demokit">Android accessory communication protocol</a>. In USB
+ host mode, the Android-powered device acts as the host. Examples of devices include digital
+ cameras, keyboards, mice, and game controllers. USB devices that are designed for a wide range of
+ applications and environments can still interact with Android applications that can correctly
+ communicate with the device.</p>
+
+ <p>Figure 1 shows the differences between the two modes. When the Android-powered device is in
+ host mode, it acts as the USB host and powers the bus. When the Android-powered device is in USB
+ accessory mode, the connected USB hardware (an Android USB accessory in this case) acts as the
+ host and powers the bus.</p><img src="{@docRoot}images/usb-host-accessory.png" alt="">
+
+ <p class="img-caption"><strong>Figure 1.</strong> USB Host and Accessory Modes</p>
+
+ <p>USB accessory and host modes are directly supported in Android 3.1 (API level 12) or newer
+ platforms. USB accessory mode is also backported to Android 2.3.4 (API level 10) as an add-on
+ library to support a broader range of devices. Device manufacturers can choose whether or not to
+ include the add-on library on the device's system image.</p>
+
+ <p class="note"><strong>Note:</strong> Support for USB host and accessory modes are ultimately
+ dependant on the device's hardware, regardless of platform level. You can filter for devices that
+ support USB host and accessory through a <a href=
+ "{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a> element. See
+ the USB <a href="{@docRoot}guide/topics/USB/accessory.html">accessory</a> and <a href=
+ "{@docRoot}guide/topics/USB/host.html">host</a> documentation for more details.</p>
+
+ <h2>Debugging considerations</h2>
+
+ <p>When debugging applications that use USB accessory or host features, you most likely will have
+ USB hardware connected to your Android-powered device. This will prevent you from having an
+ <code>adb</code> connection to the Android-powered device via USB. You can still access
+ <code>adb</code> over a network connection. To enable <code>adb</code> over a network
+ connection:</p>
+
+ <ol>
+ <li>Connect the Android-powered device via USB to your computer.</li>
+
+ <li>From your SDK <code>platform-tools/</code> directory, enter <code>adb tcpip 5555</code> at
+ the command prompt.</li>
+
+ <li>Enter <code>adb connect &lt;device-ip-address&gt;:5555</code> You should now be connected
+ to the Android-powered device and can issue the usual <code>adb</code> commands like <code>adb
+ logcat</code>.</li>
+
+ <li>To set your device to listen on USB, enter <code>adb usb</code>.</li>
+ </ol>
diff --git a/docs/html/images/admin/device-admin-activate-prompt.png b/docs/html/images/admin/device-admin-activate-prompt.png
index fd001bd0cd2a..2851194b4b05 100755..100644
--- a/docs/html/images/admin/device-admin-activate-prompt.png
+++ b/docs/html/images/admin/device-admin-activate-prompt.png
Binary files differ
diff --git a/docs/html/images/admin/device-admin-app.png b/docs/html/images/admin/device-admin-app.png
index d966a28ef15f..c96defc266ba 100755..100644
--- a/docs/html/images/admin/device-admin-app.png
+++ b/docs/html/images/admin/device-admin-app.png
Binary files differ
diff --git a/docs/html/images/usb-host-accessory.png b/docs/html/images/usb-host-accessory.png
new file mode 100644
index 000000000000..f82fd6ffd7da
--- /dev/null
+++ b/docs/html/images/usb-host-accessory.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 78f71acb6ed0..d5f19a1ca9fc 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -129,17 +129,20 @@ href="{@docRoot}resources/dashboard/platform-versions.html">Learn more &raquo;</
'sdk': {
'layout':"imgLeft",
'icon':"sdk-small.png",
- 'name':"Android 3.0",
+ 'name':"Android 3.1",
'img':"honeycomb-android.png",
- 'title':"Android 3.0 is here!",
- 'desc': "<p>Android 3.0 is now available for the Android SDK. It offers a redesigned UI and "
-+ "all new developer APIs for an optimized experience on tablets and similar devices. "
-+ "For more information about what's in Android 3.0, read the "
-+ "<a href='{@docRoot}sdk/android-3.0.html'>version notes</a>.</p>"
+ 'title':"Android 3.1 now available!",
+ 'desc': "<p>Android 3.1 includes new developer features such as APIs for USB "
++ "accessories, MTP/PTP, and RTP, as well as new input events from mice, trackballs, joysticks, "
++ "and more.</p>"
++ "<p>For more information about all the new APIs in Android 3.1, read the "
++ "<a href='{@docRoot}sdk/android-3.1.html'>version notes</a>.</p>"
+/*
+ "<p>If you have an existing SDK, add Android 3.0 as an "
+ "<a href='{@docRoot}sdk/adding-components.html'>SDK "
+ "component</a>. If you're new to Android, install the "
+ "<a href='{@docRoot}sdk/index.html'>SDK starter package</a>."
+*/
},
'tv': {
@@ -152,8 +155,7 @@ href="{@docRoot}resources/dashboard/platform-versions.html">Learn more &raquo;</
+ "for television built on Android. Google "
+ "has partnered with Sony and Logitech to integrate "
+ "this platform into TVs, blu-ray players, and companion "
- + "boxes. An add-on for the Android SDK will be "
- + "available early next year. </p>"
+ + "boxes. </p>"
+ "<p><a href='http://www.google.com/tv/'>Learn more about "
+ "Google TV &raquo;</a></p>"
},
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 5d7b651d3918..368164d55904 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@ Android Market within a 14-day period ending on the data collection date noted b
<div class="dashboard-panel">
<img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.7,3.5,27.2,63.9,0.8,1.7,0.2&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.3,3.0,24.5,65.9,1.0,3.0,0.3&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0&chco=c4df9b,6fad0c" />
<table>
<tr>
@@ -60,16 +60,16 @@ src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:2.7,3.5,27.2,63
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td>Android 1.5</td><td>3</td><td>2.7%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>3.5%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>27.2%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>63.9%</td></tr>
-<tr><td>Android 2.3</td><td>9</td><td>0.8%</td></tr>
-<tr><td>Android 2.3.3</td><td>10</td><td>1.7%</td></tr>
-<tr><td>Android 3.0</td><td>11</td><td>0.2%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>2.3%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>3.0%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>24.5%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>65.9%</td></tr>
+<tr><td>Android 2.3</td><td>9</td><td>1.0%</td></tr>
+<tr><td>Android 2.3.3</td><td>10</td><td>3.0%</td></tr>
+<tr><td>Android 3.0</td><td>11</td><td>0.3%</td></tr>
</table>
-<p><em>Data collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Data collected during two weeks ending on May 2, 2011</em></p>
<!--
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
-->
@@ -98,9 +98,9 @@ Android Market within a 14-day period ending on the date indicated on the x-axis
<div class="dashboard-panel">
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C1%3A%7C2010%7C%7C%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.9,99.9,100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7|90.2,91.1,92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0|73.8,75.3,77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5|33.4,34.5,37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.3|0.0,0.0,0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C02/15%7C03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C1%3A%7C2010%7C%7C%7C%7C2011%7C%7C%7C%7C%7C%7C%7C%7C2011%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:100.0,99.9,99.8,99.7,100.0,99.9,99.9,99.9,100.0,99.8,99.7,99.6,99.6|92.0,92.7,93.4,94.1,95.2,95.6,96.0,96.3,96.7,96.8,97.0,97.1,97.3|77.4,79.6,82.2,84.4,87.2,88.3,89.7,90.5,91.5,92.0,93.5,93.9,94.3|37.1,40.5,44.3,47.7,51.8,54.3,58.3,59.7,61.5,63.0,66.4,68.0,69.8|0.0,0.0,0.0,0.0,0.4,0.6,0.7,0.8,1.1,1.7,2.5,3.1,4.0|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.7,2.2,3.0&chm=b,c3df9b,0,1,0|tAndroid 1.6,689326,1,0,15,,t::-5|b,b4db77,1,2,0|tAndroid 2.1,547a19,2,0,15,,t::-5|b,a5db51,2,3,0|tAndroid 2.2,3f5e0e,3,0,15,,t::-5|b,96dd28,3,4,0|b,83c916,4,5,0|B,6fad0c,5,6,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3&chco=add274,9dd14f,8ece2a,7ab61c,659b11,507d08" />
-<p><em>Last historical dataset collected during two weeks ending on April 1, 2011</em></p>
+<p><em>Last historical dataset collected during two weeks ending on May 2, 2011</em></p>
</div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/resources-data.js b/docs/html/resources/resources-data.js
index 14118bbcd5fa..03a5c02ee6fa 100644
--- a/docs/html/resources/resources-data.js
+++ b/docs/html/resources/resources-data.js
@@ -606,6 +606,16 @@ var ANDROID_RESOURCES = [
}
},
{
+ tags: ['sample', 'new', 'newfeature'],
+ path: 'samples/USB/index.html',
+ title: {
+ en: 'USB'
+ },
+ description: {
+ en: 'A set of samples that demonstrate how to use various features of the USB APIs.'
+ }
+ },
+ {
tags: ['sample', 'ui', 'widgets'],
path: 'samples/Wiktionary/index.html',
title: {
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index cfae0c1d7fad..3c43a3923bd0 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -34,8 +34,9 @@ import android.os.Message;
* the stream to be skipped.
*
* <p>When sampling from the texture one should first transform the texture coordinates using the
- * matrix queried via {@link #getTransformMatrix}. The transform matrix may change each time {@link
- * #updateTexImage} is called, so it should be re-queried each time the texture image is updated.
+ * matrix queried via {@link #getTransformMatrix(float[])}. The transform matrix may change each
+ * time {@link #updateTexImage} is called, so it should be re-queried each time the texture image
+ * is updated.
* This matrix transforms traditional 2D OpenGL ES texture coordinate column vectors of the form (s,
* t, 0, 1) where s and t are on the inclusive interval [0, 1] to the proper sampling location in
* the streamed texture. This transform compensates for any properties of the image stream source
@@ -63,8 +64,13 @@ public class SurfaceTexture {
private EventHandler mEventHandler;
private OnFrameAvailableListener mOnFrameAvailableListener;
- @SuppressWarnings("unused")
- private int mSurfaceTexture;
+ /**
+ * This field is used by native code, do not access or modify.
+ *
+ * @hide
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ public int mSurfaceTexture;
/**
* Callback interface for being notified that a new stream frame is available.
@@ -176,10 +182,13 @@ public class SurfaceTexture {
if (mOnFrameAvailableListener != null) {
mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this);
}
- return;
}
}
+ /**
+ * This method is invoked from native code only.
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
private static void postEventFromNative(Object selfRef) {
WeakReference weakSelf = (WeakReference)selfRef;
SurfaceTexture st = (SurfaceTexture)weakSelf.get();
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 4c505ec95e1d..eea0986c694e 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -839,6 +839,9 @@ public class RenderScript {
rs.mDev = rs.nDeviceCreate();
rs.mContext = rs.nContextCreate(rs.mDev, 0);
+ if (rs.mContext == 0) {
+ throw new RSDriverException("Failed to create RS context.");
+ }
rs.mMessageThread = new MessageThread(rs);
rs.mMessageThread.start();
return rs;
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 3c6dccc73e61..7106bfa6606f 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -20,122 +20,28 @@
#include <utils/Timers.h>
#include <camera/ICameraClient.h>
#include <gui/ISurfaceTexture.h>
+#include <system/camera.h>
namespace android {
-/*
- * A set of bit masks for specifying how the received preview frames are
- * handled before the previewCallback() call.
- *
- * The least significant 3 bits of an "int" value are used for this purpose:
- *
- * ..... 0 0 0
- * ^ ^ ^
- * | | |---------> determine whether the callback is enabled or not
- * | |-----------> determine whether the callback is one-shot or not
- * |-------------> determine whether the frame is copied out or not
- *
- * WARNING:
- * When a frame is sent directly without copying, it is the frame receiver's
- * responsiblity to make sure that the frame data won't get corrupted by
- * subsequent preview frames filled by the camera. This flag is recommended
- * only when copying out data brings significant performance price and the
- * handling/processing of the received frame data is always faster than
- * the preview frame rate so that data corruption won't occur.
- *
- * For instance,
- * 1. 0x00 disables the callback. In this case, copy out and one shot bits
- * are ignored.
- * 2. 0x01 enables a callback without copying out the received frames. A
- * typical use case is the Camcorder application to avoid making costly
- * frame copies.
- * 3. 0x05 is enabling a callback with frame copied out repeatedly. A typical
- * use case is the Camera application.
- * 4. 0x07 is enabling a callback with frame copied out only once. A typical use
- * case is the Barcode scanner application.
- */
-#define FRAME_CALLBACK_FLAG_ENABLE_MASK 0x01
-#define FRAME_CALLBACK_FLAG_ONE_SHOT_MASK 0x02
-#define FRAME_CALLBACK_FLAG_COPY_OUT_MASK 0x04
-
-// Typical use cases
-#define FRAME_CALLBACK_FLAG_NOOP 0x00
-#define FRAME_CALLBACK_FLAG_CAMCORDER 0x01
-#define FRAME_CALLBACK_FLAG_CAMERA 0x05
-#define FRAME_CALLBACK_FLAG_BARCODE_SCANNER 0x07
-
-// msgType in notifyCallback and dataCallback functions
-enum {
- CAMERA_MSG_ERROR = 0x0001,
- CAMERA_MSG_SHUTTER = 0x0002,
- CAMERA_MSG_FOCUS = 0x0004,
- CAMERA_MSG_ZOOM = 0x0008,
- CAMERA_MSG_PREVIEW_FRAME = 0x0010,
- CAMERA_MSG_VIDEO_FRAME = 0x0020,
- CAMERA_MSG_POSTVIEW_FRAME = 0x0040,
- CAMERA_MSG_RAW_IMAGE = 0x0080,
- CAMERA_MSG_COMPRESSED_IMAGE = 0x0100,
- CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x0200,
- CAMERA_MSG_ALL_MSGS = 0xFFFF
-};
-
-// cmdType in sendCommand functions
-enum {
- CAMERA_CMD_START_SMOOTH_ZOOM = 1,
- CAMERA_CMD_STOP_SMOOTH_ZOOM = 2,
- // Set the clockwise rotation of preview display (setPreviewDisplay) in
- // degrees. This affects the preview frames and the picture displayed after
- // snapshot. This method is useful for portrait mode applications. Note that
- // preview display of front-facing cameras is flipped horizontally before
- // the rotation, that is, the image is reflected along the central vertical
- // axis of the camera sensor. So the users can see themselves as looking
- // into a mirror.
- //
- // This does not affect the order of byte array of CAMERA_MSG_PREVIEW_FRAME,
- // CAMERA_MSG_VIDEO_FRAME, CAMERA_MSG_POSTVIEW_FRAME, CAMERA_MSG_RAW_IMAGE,
- // or CAMERA_MSG_COMPRESSED_IMAGE. This is not allowed to be set during
- // preview.
- CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
-
- // cmdType to disable/enable shutter sound.
- // In sendCommand passing arg1 = 0 will disable,
- // while passing arg1 = 1 will enable the shutter sound.
- CAMERA_CMD_ENABLE_SHUTTER_SOUND = 4,
-
- // cmdType to play recording sound.
- CAMERA_CMD_PLAY_RECORDING_SOUND = 5,
-};
-
-// camera fatal errors
-enum {
- CAMERA_ERROR_UNKNOWN = 1,
- CAMERA_ERROR_SERVER_DIED = 100
-};
-
-enum {
- CAMERA_FACING_BACK = 0, /* The facing of the camera is opposite to that of the screen. */
- CAMERA_FACING_FRONT = 1 /* The facing of the camera is the same as that of the screen. */
-};
-
struct CameraInfo {
-
/**
- * The direction that the camera faces to. It should be
- * CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
+ * The direction that the camera faces to. It should be CAMERA_FACING_BACK
+ * or CAMERA_FACING_FRONT.
*/
int facing;
/**
* The orientation of the camera image. The value is the angle that the
- * camera image needs to be rotated clockwise so it shows correctly on
- * the display in its natural orientation. It should be 0, 90, 180, or 270.
+ * camera image needs to be rotated clockwise so it shows correctly on the
+ * display in its natural orientation. It should be 0, 90, 180, or 270.
*
* For example, suppose a device has a naturally tall screen. The
* back-facing camera sensor is mounted in landscape. You are looking at
* the screen. If the top side of the camera sensor is aligned with the
* right edge of the screen in natural orientation, the value should be
- * 90. If the top side of a front-facing camera sensor is aligned with
- * the right of the screen, the value should be 270.
+ * 90. If the top side of a front-facing camera sensor is aligned with the
+ * right of the screen, the value should be 270.
*/
int orientation;
};
diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h
deleted file mode 100644
index 3f34120dfff5..000000000000
--- a/include/camera/CameraHardwareInterface.h
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2008 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_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
-
-#include <binder/IMemory.h>
-#include <ui/egl/android_natives.h>
-#include <utils/RefBase.h>
-#include <surfaceflinger/ISurface.h>
-#include <ui/android_native_buffer.h>
-#include <ui/GraphicBuffer.h>
-#include <camera/Camera.h>
-#include <camera/CameraParameters.h>
-
-namespace android {
-
-typedef void (*notify_callback)(int32_t msgType,
- int32_t ext1,
- int32_t ext2,
- void* user);
-
-typedef void (*data_callback)(int32_t msgType,
- const sp<IMemory>& dataPtr,
- void* user);
-
-typedef void (*data_callback_timestamp)(nsecs_t timestamp,
- int32_t msgType,
- const sp<IMemory>& dataPtr,
- void* user);
-
-/**
- * CameraHardwareInterface.h defines the interface to the
- * camera hardware abstraction layer, used for setting and getting
- * parameters, live previewing, and taking pictures.
- *
- * It is a referenced counted interface with RefBase as its base class.
- * CameraService calls openCameraHardware() to retrieve a strong pointer to the
- * instance of this interface and may be called multiple times. The
- * following steps describe a typical sequence:
- *
- * -# After CameraService calls openCameraHardware(), getParameters() and
- * setParameters() are used to initialize the camera instance.
- * CameraService calls getPreviewHeap() to establish access to the
- * preview heap so it can be registered with SurfaceFlinger for
- * efficient display updating while in preview mode.
- * -# startPreview() is called. The camera instance then periodically
- * sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
- * a new preview frame is available. If data callback code needs to use
- * this memory after returning, it must copy the data.
- *
- * Prior to taking a picture, CameraService calls autofocus(). When auto
- * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
- * which informs the application whether focusing was successful. The camera instance
- * only sends this message once and it is up to the application to call autoFocus()
- * again if refocusing is desired.
- *
- * CameraService calls takePicture() to request the camera instance take a
- * picture. At this point, if a shutter, postview, raw, and/or compressed callback
- * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
- * any memory provided in a data callback must be copied if it's needed after returning.
- */
-class CameraHardwareInterface : public virtual RefBase {
-public:
- virtual ~CameraHardwareInterface() { }
-
- /** Set the ANativeWindow to which preview frames are sent */
- virtual status_t setPreviewWindow(const sp<ANativeWindow>& buf) = 0;
-
- /** Set the notification and data callbacks */
- virtual void setCallbacks(notify_callback notify_cb,
- data_callback data_cb,
- data_callback_timestamp data_cb_timestamp,
- void* user) = 0;
-
- /**
- * The following three functions all take a msgtype,
- * which is a bitmask of the messages defined in
- * include/ui/Camera.h
- */
-
- /**
- * Enable a message, or set of messages.
- */
- virtual void enableMsgType(int32_t msgType) = 0;
-
- /**
- * Disable a message, or a set of messages.
- *
- * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera hal
- * should not rely on its client to call releaseRecordingFrame() to release
- * video recording frames sent out by the cameral hal before and after the
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera hal clients must not
- * modify/access any video recording frame after calling
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
- */
- virtual void disableMsgType(int32_t msgType) = 0;
-
- /**
- * Query whether a message, or a set of messages, is enabled.
- * Note that this is operates as an AND, if any of the messages
- * queried are off, this will return false.
- */
- virtual bool msgTypeEnabled(int32_t msgType) = 0;
-
- /**
- * Start preview mode.
- */
- virtual status_t startPreview() = 0;
-
- /**
- * Stop a previously started preview.
- */
- virtual void stopPreview() = 0;
-
- /**
- * Returns true if preview is enabled.
- */
- virtual bool previewEnabled() = 0;
-
- /**
- * Request the camera hal to store meta data or real YUV data in
- * the video buffers send out via CAMERA_MSG_VIDEO_FRRAME for a
- * recording session. If it is not called, the default camera
- * hal behavior is to store real YUV data in the video buffers.
- *
- * This method should be called before startRecording() in order
- * to be effective.
- *
- * If meta data is stored in the video buffers, it is up to the
- * receiver of the video buffers to interpret the contents and
- * to find the actual frame data with the help of the meta data
- * in the buffer. How this is done is outside of the scope of
- * this method.
- *
- * Some camera hal may not support storing meta data in the video
- * buffers, but all camera hal should support storing real YUV data
- * in the video buffers. If the camera hal does not support storing
- * the meta data in the video buffers when it is requested to do
- * do, INVALID_OPERATION must be returned. It is very useful for
- * the camera hal to pass meta data rather than the actual frame
- * data directly to the video encoder, since the amount of the
- * uncompressed frame data can be very large if video size is large.
- *
- * @param enable if true to instruct the camera hal to store
- * meta data in the video buffers; false to instruct
- * the camera hal to store real YUV data in the video
- * buffers.
- *
- * @return OK on success.
- */
- virtual status_t storeMetaDataInBuffers(bool enable) {
- return enable? INVALID_OPERATION: OK;
- }
-
- /**
- * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
- * message is sent with the corresponding frame. Every record frame must be released
- * by a cameral hal client via releaseRecordingFrame() before the client calls
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls
- * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's responsibility
- * to manage the life-cycle of the video recording frames, and the client must
- * not modify/access any video recording frames.
- */
- virtual status_t startRecording() = 0;
-
- /**
- * Stop a previously started recording.
- */
- virtual void stopRecording() = 0;
-
- /**
- * Returns true if recording is enabled.
- */
- virtual bool recordingEnabled() = 0;
-
- /**
- * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
- *
- * It is camera hal client's responsibility to release video recording
- * frames sent out by the camera hal before the camera hal receives
- * a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives
- * the call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's
- * responsibility of managing the life-cycle of the video recording
- * frames.
- */
- virtual void releaseRecordingFrame(const sp<IMemory>& mem) = 0;
-
- /**
- * Start auto focus, the notification callback routine is called
- * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
- * will be called again if another auto focus is needed.
- */
- virtual status_t autoFocus() = 0;
-
- /**
- * Cancels auto-focus function. If the auto-focus is still in progress,
- * this function will cancel it. Whether the auto-focus is in progress
- * or not, this function will return the focus position to the default.
- * If the camera does not support auto-focus, this is a no-op.
- */
- virtual status_t cancelAutoFocus() = 0;
-
- /**
- * Take a picture.
- */
- virtual status_t takePicture() = 0;
-
- /**
- * Cancel a picture that was started with takePicture. Calling this
- * method when no picture is being taken is a no-op.
- */
- virtual status_t cancelPicture() = 0;
-
- /**
- * Set the camera parameters. This returns BAD_VALUE if any parameter is
- * invalid or not supported. */
- virtual status_t setParameters(const CameraParameters& params) = 0;
-
- /** Return the camera parameters. */
- virtual CameraParameters getParameters() const = 0;
-
- /**
- * Send command to camera driver.
- */
- virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
-
- /**
- * Release the hardware resources owned by this object. Note that this is
- * *not* done in the destructor.
- */
- virtual void release() = 0;
-
- /**
- * Dump state of the camera hardware
- */
- virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
-};
-
-/**
- * The functions need to be provided by the camera HAL.
- *
- * If getNumberOfCameras() returns N, the valid cameraId for getCameraInfo()
- * and openCameraHardware() is 0 to N-1.
- */
-extern "C" int HAL_getNumberOfCameras();
-extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo);
-/* HAL should return NULL if it fails to open camera hardware. */
-extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId);
-
-}; // namespace android
-
-#endif
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index db81721aa287..513239f55424 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -309,6 +309,25 @@ public:
// 0.3333, EV is -2.
// Example value: "0.333333333" or "0.5". Read only.
static const char KEY_EXPOSURE_COMPENSATION_STEP[];
+ // The state of the auto-exposure lock. "true" means that auto-exposure is
+ // locked to its current value and will not change. "false" means the
+ // auto-exposure routine is free to change exposure settings. Changing
+ // exposure compensation settings will still affect the exposure settings
+ // while auto-exposure is locked. Stopping preview or taking a still image
+ // will release the lock. However, the lock can be re-enabled prior to
+ // preview being re-started, to keep the exposure values from the previous
+ // lock. In conjunction with exposure compensation, this allows for
+ // capturing multi-exposure brackets with known relative exposure
+ // values. Locking auto-exposure after open but before the first cal to
+ // startPreview may result in severly over- or under-exposed images. The
+ // driver may independently enable the AE lock after auto-focus
+ // completes. If it does so, this key must have its value updated to reflect
+ // the lock's existence. Applications are free to release such a lock, to
+ // re-enable AE without restarting preview.
+ static const char KEY_AUTO_EXPOSURE_LOCK[];
+ // Whether locking the auto-exposure is supported. "true" means it is, and
+ // "false" or this key not existing means it is not supported.
+ static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
// The maximum number of metering areas supported. This is the maximum
// length of KEY_METERING_AREAS.
// Example value: "0" or "2". Read only.
@@ -428,6 +447,7 @@ public:
// Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
static const char TRUE[];
+ static const char FALSE[];
// Value for KEY_FOCUS_DISTANCES.
static const char FOCUS_DISTANCE_INFINITY[];
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index fe9b04917ed8..c77bc4cd27b8 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -45,20 +45,20 @@ private:
SurfaceTextureClient(const SurfaceTextureClient& rhs);
// ANativeWindow hooks
- static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
- static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+ static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int perform(ANativeWindow* window, int operation, ...);
- static int query(ANativeWindow* window, int what, int* value);
- static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+ static int query(const ANativeWindow* window, int what, int* value);
+ static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
static int setSwapInterval(ANativeWindow* window, int interval);
- int cancelBuffer(android_native_buffer_t* buffer);
- int dequeueBuffer(android_native_buffer_t** buffer);
- int lockBuffer(android_native_buffer_t* buffer);
+ int cancelBuffer(ANativeWindowBuffer* buffer);
+ int dequeueBuffer(ANativeWindowBuffer** buffer);
+ int lockBuffer(ANativeWindowBuffer* buffer);
int perform(int operation, va_list args);
- int query(int what, int* value);
- int queueBuffer(android_native_buffer_t* buffer);
+ int query(int what, int* value) const;
+ int queueBuffer(ANativeWindowBuffer* buffer);
int setSwapInterval(int interval);
int dispatchConnect(va_list args);
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 3e343e08f888..28f305d5392a 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -52,6 +52,7 @@ enum {
METADATA_KEY_VIDEO_WIDTH = 18,
METADATA_KEY_VIDEO_HEIGHT = 19,
METADATA_KEY_BITRATE = 20,
+ METADATA_KEY_TIMED_TEXT_LANGUAGES = 21,
// Add more here...
};
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 241626c04071..cfa4cfd4007f 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -125,6 +125,9 @@ enum media_player_states {
MEDIA_PLAYER_PLAYBACK_COMPLETE = 1 << 7
};
+enum media_set_parameter_keys {
+ KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000,
+};
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class MediaPlayerListener: virtual public RefBase
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
new file mode 100644
index 000000000000..fa3ab8af17eb
--- /dev/null
+++ b/include/media/stagefright/AACWriter.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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 AAC_WRITER_H_
+#define AAC_WRITER_H_
+
+#include <media/stagefright/MediaWriter.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct MediaSource;
+struct MetaData;
+
+struct AACWriter : public MediaWriter {
+ AACWriter(const char *filename);
+ AACWriter(int fd);
+
+ status_t initCheck() const;
+
+ virtual status_t addSource(const sp<MediaSource> &source);
+ virtual bool reachedEOS();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual status_t pause();
+
+protected:
+ virtual ~AACWriter();
+
+private:
+ enum {
+ kAdtsHeaderLength = 7, // # of bytes for the adts header
+ kSamplesPerFrame = 1024, // # of samples in a frame
+ };
+
+ int mFd;
+ status_t mInitCheck;
+ sp<MediaSource> mSource;
+ bool mStarted;
+ volatile bool mPaused;
+ volatile bool mResumed;
+ volatile bool mDone;
+ volatile bool mReachedEOS;
+ pthread_t mThread;
+ int64_t mEstimatedSizeBytes;
+ int64_t mEstimatedDurationUs;
+ int32_t mChannelCount;
+ int32_t mSampleRate;
+ int32_t mFrameDurationUs;
+
+ static void *ThreadWrapper(void *);
+ status_t threadFunc();
+ bool exceedsFileSizeLimit();
+ bool exceedsFileDurationLimit();
+ status_t writeAdtsHeader(uint32_t frameLength);
+
+ DISALLOW_EVIL_CONSTRUCTORS(AACWriter);
+};
+
+} // namespace android
+
+#endif // AAC_WRITER_H_
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index d1ecaafea88b..946a0aaa8f6c 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -84,7 +84,7 @@ struct UseAndroidNativeBufferParams {
OMX_U32 nPortIndex;
OMX_PTR pAppPrivate;
OMX_BUFFERHEADERTYPE **bufferHeader;
- const sp<android_native_buffer_t>& nativeBuffer;
+ const sp<ANativeWindowBuffer>& nativeBuffer;
};
// A pointer to this struct is passed to OMX_GetParameter when the extension
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 6a21627c5477..5e471c199b06 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -49,6 +49,8 @@ extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
+extern const char *MEDIA_MIMETYPE_TEXT_3GPP;
+
} // namespace android
#endif // MEDIA_DEFS_H_
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index f7f2235eee08..4044c5d61a1d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -114,6 +114,9 @@ enum {
// An indication that a video buffer has been rendered.
kKeyRendered = 'rend', // bool (int32_t)
+
+ // The language code for this media
+ kKeyMediaLanguage = 'lang', // cstring
};
enum {
diff --git a/include/private/opengles/gl_context.h b/include/private/opengles/gl_context.h
index 72416c1a22c7..6b1fa770281d 100644
--- a/include/private/opengles/gl_context.h
+++ b/include/private/opengles/gl_context.h
@@ -31,8 +31,6 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
-struct android_native_buffer_t;
-
namespace android {
@@ -603,13 +601,6 @@ struct prims_t {
void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
};
-struct copybits_context_t {
- // A handle to the blit engine, if it exists, else NULL.
- int32_t minScale;
- int32_t maxScale;
- android_native_buffer_t* drawSurfaceBuffer;
-};
-
struct ogles_context_t {
context_t rasterizer;
array_machine_t arrays __attribute__((aligned(32)));
@@ -634,13 +625,6 @@ struct ogles_context_t {
EGLSurfaceManager* surfaceManager;
EGLBufferObjectManager* bufferObjectManager;
- // copybits is only used if LIBAGL_USE_GRALLOC_COPYBITS is
- // defined, but it is always present because ogles_context_t is a public
- // struct that is used by clients of libagl. We want the size and offsets
- // to stay the same, whether or not LIBAGL_USE_GRALLOC_COPYBITS is defined.
-
- copybits_context_t copybits;
-
GLenum error;
static inline ogles_context_t* get() {
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 3923e61ad8c5..ab30f45dd541 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -202,18 +202,18 @@ private:
* ANativeWindow hooks
*/
static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
- static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int query(ANativeWindow* window, int what, int* value);
+ static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int query(const ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
- int dequeueBuffer(android_native_buffer_t** buffer);
- int lockBuffer(android_native_buffer_t* buffer);
- int queueBuffer(android_native_buffer_t* buffer);
- int cancelBuffer(android_native_buffer_t* buffer);
- int query(int what, int* value);
+ int dequeueBuffer(ANativeWindowBuffer** buffer);
+ int lockBuffer(ANativeWindowBuffer* buffer);
+ int queueBuffer(ANativeWindowBuffer* buffer);
+ int cancelBuffer(ANativeWindowBuffer* buffer);
+ int query(int what, int* value) const;
int perform(int operation, va_list args);
void dispatch_setUsage(va_list args);
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 16117adca92a..302d01239eeb 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -67,10 +67,10 @@ private:
friend class LightRefBase<FramebufferNativeWindow>;
~FramebufferNativeWindow(); // this class cannot be overloaded
static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
- static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
- static int query(ANativeWindow* window, int what, int* value);
+ static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int query(const ANativeWindow* window, int what, int* value);
static int perform(ANativeWindow* window, int operation, ...);
framebuffer_device_t* fbDev;
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 02d6f8ffd20e..370253a9c1d1 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -26,7 +26,7 @@
#include <utils/Flattenable.h>
#include <pixelflinger/pixelflinger.h>
-struct android_native_buffer_t;
+struct ANativeWindowBuffer;
namespace android {
@@ -38,7 +38,7 @@ class GraphicBufferMapper;
class GraphicBuffer
: public EGLNativeBase<
- android_native_buffer_t,
+ ANativeWindowBuffer,
GraphicBuffer,
LightRefBase<GraphicBuffer> >, public Flattenable
{
@@ -74,8 +74,8 @@ public:
GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
uint32_t stride, native_handle_t* handle, bool keepOwnership);
- // create a buffer from an existing android_native_buffer_t
- GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership);
+ // create a buffer from an existing ANativeWindowBuffer
+ GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership);
// return status
status_t initCheck() const;
@@ -94,7 +94,7 @@ public:
status_t lock(GGLSurface* surface, uint32_t usage);
status_t unlock();
- android_native_buffer_t* getNativeBuffer() const;
+ ANativeWindowBuffer* getNativeBuffer() const;
void setIndex(int index);
int getIndex() const;
@@ -149,7 +149,7 @@ private:
// If we're wrapping another buffer then this reference will make sure it
// doesn't get freed.
- sp<android_native_buffer_t> mWrappedBuffer;
+ sp<ANativeWindowBuffer> mWrappedBuffer;
};
}; // namespace android
diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h
index 402843e20565..b6e1db460063 100644
--- a/include/ui/android_native_buffer.h
+++ b/include/ui/android_native_buffer.h
@@ -19,53 +19,4 @@
#include <ui/egl/android_natives.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-typedef struct android_native_buffer_t
-{
-#ifdef __cplusplus
- android_native_buffer_t() {
- common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
- common.version = sizeof(android_native_buffer_t);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- // Implement the methods that sp<android_native_buffer_t> expects so that it
- // can be used to automatically refcount android_native_buffer_t's.
- void incStrong(const void* id) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* id) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- int width;
- int height;
- int stride;
- int format;
- int usage;
-
- void* reserved[2];
-
- buffer_handle_t handle;
-
- void* reserved_proc[8];
-} android_native_buffer_t;
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-/*****************************************************************************/
-
#endif /* ANDROID_ANDROID_NATIVES_PRIV_H */
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 0a6e4fbd5e92..9ac50a5a39a8 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -21,400 +21,9 @@
#include <string.h>
#include <hardware/gralloc.h>
-
+#include <system/window.h>
+// FIXME: remove this header, it's for legacy use. native_window is pulled from frameworks/base/native/include/android/
#include <android/native_window.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*****************************************************************************/
-
-#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
- (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
-
-#define ANDROID_NATIVE_WINDOW_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
-
-#define ANDROID_NATIVE_BUFFER_MAGIC \
- ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-// ---------------------------------------------------------------------------
-
-struct android_native_buffer_t;
-
-typedef struct android_native_rect_t
-{
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-} android_native_rect_t;
-
-// ---------------------------------------------------------------------------
-
-typedef struct android_native_base_t
-{
- /* a magic value defined by the actual EGL native type */
- int magic;
-
- /* the sizeof() of the actual EGL native type */
- int version;
-
- void* reserved[4];
-
- /* reference-counting interface */
- void (*incRef)(struct android_native_base_t* base);
- void (*decRef)(struct android_native_base_t* base);
-} android_native_base_t;
-
-// ---------------------------------------------------------------------------
-
-/* attributes queriable with query() */
-enum {
- NATIVE_WINDOW_WIDTH = 0,
- NATIVE_WINDOW_HEIGHT,
- NATIVE_WINDOW_FORMAT,
-
- /* The minimum number of buffers that must remain un-dequeued after a buffer
- * has been queued. This value applies only if set_buffer_count was used to
- * override the number of buffers and if a buffer has since been queued.
- * Users of the set_buffer_count ANativeWindow method should query this
- * value before calling set_buffer_count. If it is necessary to have N
- * buffers simultaneously dequeued as part of the steady-state operation,
- * and this query returns M then N+M buffers should be requested via
- * native_window_set_buffer_count.
- *
- * Note that this value does NOT apply until a single buffer has been
- * queued. In particular this means that it is possible to:
- *
- * 1. Query M = min undequeued buffers
- * 2. Set the buffer count to N + M
- * 3. Dequeue all N + M buffers
- * 4. Cancel M buffers
- * 5. Queue, dequeue, queue, dequeue, ad infinitum
- */
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-
- /* Check whether queueBuffer operations on the ANativeWindow send the buffer
- * to the window compositor. The query sets the returned 'value' argument
- * to 1 if the ANativeWindow DOES send queued buffers directly to the window
- * compositor and 0 if the buffers do not go directly to the window
- * compositor.
- *
- * This can be used to determine whether protected buffer content should be
- * sent to the ANativeWindow. Note, however, that a result of 1 does NOT
- * indicate that queued buffers will be protected from applications or users
- * capturing their contents. If that behavior is desired then some other
- * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
- * conjunction with this query.
- */
- NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
-
- /* Get the concrete type of a ANativeWindow. See below for the list of
- * possible return values.
- *
- * This query should not be used outside the Android framework and will
- * likely be removed in the near future.
- */
- NATIVE_WINDOW_CONCRETE_TYPE,
-};
-
-/* valid operations for the (*perform)() hook */
-enum {
- NATIVE_WINDOW_SET_USAGE = 0,
- NATIVE_WINDOW_CONNECT,
- NATIVE_WINDOW_DISCONNECT,
- NATIVE_WINDOW_SET_CROP,
- NATIVE_WINDOW_SET_BUFFER_COUNT,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
-};
-
-/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
-enum {
- NATIVE_WINDOW_API_EGL = 1
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
-enum {
- /* flip source image horizontally */
- NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
- /* flip source image vertically */
- NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
- /* rotate source image 90 degrees clock-wise */
- NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
- /* rotate source image 180 degrees */
- NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
- /* rotate source image 270 degrees clock-wise */
- NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
-};
-
-/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
-enum {
- NATIVE_WINDOW_FRAMEBUFFER, // FramebufferNativeWindow
- NATIVE_WINDOW_SURFACE, // Surface
- NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, // SurfaceTextureClient
-};
-
-/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
- *
- * Special timestamp value to indicate that timestamps should be auto-generated
- * by the native window when queueBuffer is called. This is equal to INT64_MIN,
- * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
- */
-const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
-
-struct ANativeWindow
-{
-#ifdef __cplusplus
- ANativeWindow()
- : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
- {
- common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
- common.version = sizeof(ANativeWindow);
- memset(common.reserved, 0, sizeof(common.reserved));
- }
-
- // Implement the methods that sp<ANativeWindow> expects so that it
- // can be used to automatically refcount ANativeWindow's.
- void incStrong(const void* id) const {
- common.incRef(const_cast<android_native_base_t*>(&common));
- }
- void decStrong(const void* id) const {
- common.decRef(const_cast<android_native_base_t*>(&common));
- }
-#endif
-
- struct android_native_base_t common;
-
- /* flags describing some attributes of this surface or its updater */
- const uint32_t flags;
-
- /* min swap interval supported by this updated */
- const int minSwapInterval;
-
- /* max swap interval supported by this updated */
- const int maxSwapInterval;
-
- /* horizontal and vertical resolution in DPI */
- const float xdpi;
- const float ydpi;
-
- /* Some storage reserved for the OEM's driver. */
- intptr_t oem[4];
-
-
- /*
- * Set the swap interval for this surface.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*setSwapInterval)(struct ANativeWindow* window,
- int interval);
-
- /*
- * hook called by EGL to acquire a buffer. After this call, the buffer
- * is not locked, so its content cannot be modified.
- * this call may block if no buffers are available.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*dequeueBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t** buffer);
-
- /*
- * hook called by EGL to lock a buffer. This MUST be called before modifying
- * the content of a buffer. The buffer must have been acquired with
- * dequeueBuffer first.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*lockBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t* buffer);
- /*
- * hook called by EGL when modifications to the render buffer are done.
- * This unlocks and post the buffer.
- *
- * Buffers MUST be queued in the same order than they were dequeued.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*queueBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t* buffer);
-
- /*
- * hook used to retrieve information about the native window.
- *
- * Returns 0 on success or -errno on error.
- */
- int (*query)(struct ANativeWindow* window,
- int what, int* value);
-
- /*
- * hook used to perform various operations on the surface.
- * (*perform)() is a generic mechanism to add functionality to
- * ANativeWindow while keeping backward binary compatibility.
- *
- * This hook should not be called directly, instead use the helper functions
- * defined below.
- *
- * (*perform)() returns -ENOENT if the 'what' parameter is not supported
- * by the surface's implementation.
- *
- * The valid operations are:
- * NATIVE_WINDOW_SET_USAGE
- * NATIVE_WINDOW_CONNECT
- * NATIVE_WINDOW_DISCONNECT
- * NATIVE_WINDOW_SET_CROP
- * NATIVE_WINDOW_SET_BUFFER_COUNT
- * NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
- * NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
- * NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
- *
- */
-
- int (*perform)(struct ANativeWindow* window,
- int operation, ... );
-
- /*
- * hook used to cancel a buffer that has been dequeued.
- * No synchronization is performed between dequeue() and cancel(), so
- * either external synchronization is needed, or these functions must be
- * called from the same thread.
- */
- int (*cancelBuffer)(struct ANativeWindow* window,
- struct android_native_buffer_t* buffer);
-
-
- void* reserved_proc[2];
-};
-
-// Backwards compatibility... please switch to ANativeWindow.
-typedef struct ANativeWindow android_native_window_t;
-
-/*
- * native_window_set_usage(..., usage)
- * Sets the intended usage flags for the next buffers
- * acquired with (*lockBuffer)() and on.
- * By default (if this function is never called), a usage of
- * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
- * is assumed.
- * Calling this function will usually cause following buffers to be
- * reallocated.
- */
-
-static inline int native_window_set_usage(
- ANativeWindow* window, int usage)
-{
- return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
-}
-
-/*
- * native_window_connect(..., NATIVE_WINDOW_API_EGL)
- * Must be called by EGL when the window is made current.
- * Returns -EINVAL if for some reason the window cannot be connected, which
- * can happen if it's connected to some other API.
- */
-static inline int native_window_connect(
- ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_CONNECT, api);
-}
-
-/*
- * native_window_disconnect(..., NATIVE_WINDOW_API_EGL)
- * Must be called by EGL when the window is made not current.
- * An error is returned if for instance the window wasn't connected in the
- * first place.
- */
-static inline int native_window_disconnect(
- ANativeWindow* window, int api)
-{
- return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);
-}
-
-/*
- * native_window_set_crop(..., crop)
- * Sets which region of the next queued buffers needs to be considered.
- * A buffer's crop region is scaled to match the surface's size.
- *
- * The specified crop region applies to all buffers queued after it is called.
- *
- * if 'crop' is NULL, subsequently queued buffers won't be cropped.
- *
- * An error is returned if for instance the crop region is invalid,
- * out of the buffer's bound or if the window is invalid.
- */
-static inline int native_window_set_crop(
- ANativeWindow* window,
- android_native_rect_t const * crop)
-{
- return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
-}
-
-/*
- * native_window_set_buffer_count(..., count)
- * Sets the number of buffers associated with this native window.
- */
-static inline int native_window_set_buffer_count(
- ANativeWindow* window,
- size_t bufferCount)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
-}
-
-/*
- * native_window_set_buffers_geometry(..., int w, int h, int format)
- * All buffers dequeued after this call will have the geometry specified.
- * In particular, all buffers will have a fixed-size, independent form the
- * native-window size. They will be appropriately scaled to the window-size
- * upon composition.
- *
- * If all parameters are 0, the normal behavior is restored. That is,
- * dequeued buffers following this call will be sized to the window's size.
- *
- * Calling this function will reset the window crop to a NULL value, which
- * disables cropping of the buffers.
- */
-static inline int native_window_set_buffers_geometry(
- ANativeWindow* window,
- int w, int h, int format)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
- w, h, format);
-}
-
-/*
- * native_window_set_buffers_transform(..., int transform)
- * All buffers queued after this call will be displayed transformed according
- * to the transform parameter specified.
- */
-static inline int native_window_set_buffers_transform(
- ANativeWindow* window,
- int transform)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
- transform);
-}
-
-/*
- * native_window_set_buffers_timestamp(..., int64_t timestamp)
- * All buffers queued after this call will be associated with the timestamp
- * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
- * (the default), timestamps will be generated automatically when queueBuffer is
- * called. The timestamp is measured in nanoseconds, and must be monotonically
- * increasing.
- */
-static inline int native_window_set_buffers_timestamp(
- ANativeWindow* window,
- int64_t timestamp)
-{
- return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
- timestamp);
-}
-
// ---------------------------------------------------------------------------
/* FIXME: this is legacy for pixmaps */
@@ -437,13 +46,6 @@ typedef struct egl_native_pixmap_t
/*****************************************************************************/
#ifdef __cplusplus
-}
-#endif
-
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
#include <utils/RefBase.h>
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 214cd4df8280..4f3da404a57d 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -68,6 +68,8 @@ const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensatio
const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
const char CameraParameters::KEY_ZOOM[] = "zoom";
@@ -82,6 +84,7 @@ const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
const char CameraParameters::TRUE[] = "true";
+const char CameraParameters::FALSE[] = "false";
const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
// Values for white balance settings.
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 44d9b4b4d329..0c5767b8c2e9 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -513,32 +513,32 @@ int Surface::setSwapInterval(ANativeWindow* window, int interval) {
}
int Surface::dequeueBuffer(ANativeWindow* window,
- android_native_buffer_t** buffer) {
+ ANativeWindowBuffer** buffer) {
Surface* self = getSelf(window);
return self->dequeueBuffer(buffer);
}
int Surface::cancelBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->cancelBuffer(buffer);
}
int Surface::lockBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->lockBuffer(buffer);
}
int Surface::queueBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
Surface* self = getSelf(window);
return self->queueBuffer(buffer);
}
-int Surface::query(ANativeWindow* window,
+int Surface::query(const ANativeWindow* window,
int what, int* value) {
- Surface* self = getSelf(window);
+ const Surface* self = getSelf(window);
return self->query(what, value);
}
@@ -570,7 +570,7 @@ bool Surface::needNewBuffer(int bufIdx,
return newNeewBuffer;
}
-int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+int Surface::dequeueBuffer(ANativeWindowBuffer** buffer)
{
status_t err = validate();
if (err != NO_ERROR)
@@ -624,7 +624,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer)
return err;
}
-int Surface::cancelBuffer(android_native_buffer_t* buffer)
+int Surface::cancelBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate(true);
switch (err) {
@@ -651,7 +651,7 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer)
}
-int Surface::lockBuffer(android_native_buffer_t* buffer)
+int Surface::lockBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate();
if (err != NO_ERROR)
@@ -670,7 +670,7 @@ int Surface::lockBuffer(android_native_buffer_t* buffer)
return err;
}
-int Surface::queueBuffer(android_native_buffer_t* buffer)
+int Surface::queueBuffer(ANativeWindowBuffer* buffer)
{
status_t err = validate();
if (err != NO_ERROR)
@@ -697,7 +697,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)
return err;
}
-int Surface::query(int what, int* value)
+int Surface::query(int what, int* value) const
{
switch (what) {
case NATIVE_WINDOW_WIDTH:
@@ -969,7 +969,7 @@ status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
// we're intending to do software rendering from this point
setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
- android_native_buffer_t* out;
+ ANativeWindowBuffer* out;
status_t err = dequeueBuffer(&out);
LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
@@ -1063,7 +1063,7 @@ int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
if (idx < 0) {
// The buffer doesn't have an index set. See if the handle the same as
// one of the buffers for which we do know the index. This can happen
- // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
+ // e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that
// was dequeued from an ANativeWindow.
for (size_t i = 0; i < mBuffers.size(); i++) {
if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f4b24162f0bf..ec6da4324d30 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -53,31 +53,32 @@ int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
}
int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
- android_native_buffer_t** buffer) {
+ ANativeWindowBuffer** buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->cancelBuffer(buffer);
}
int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->lockBuffer(buffer);
}
int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer) {
+ ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->queueBuffer(buffer);
}
-int SurfaceTextureClient::query(ANativeWindow* window, int what, int* value) {
- SurfaceTextureClient* c = getSelf(window);
+int SurfaceTextureClient::query(const ANativeWindow* window,
+ int what, int* value) {
+ const SurfaceTextureClient* c = getSelf(window);
return c->query(what, value);
}
@@ -160,7 +161,7 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
return BAD_VALUE;
}
-int SurfaceTextureClient::query(int what, int* value) {
+int SurfaceTextureClient::query(int what, int* value) const {
LOGV("SurfaceTextureClient::query");
Mutex::Autolock lock(mMutex);
switch (what) {
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index db781dec0eba..753e93391b35 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -113,7 +113,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) {
TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
@@ -123,7 +123,7 @@ TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -134,7 +134,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(1, buf->width);
@@ -145,7 +145,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -156,7 +156,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -173,7 +173,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
sp<ANativeWindow> anw(mSTC);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(1, buf->width);
@@ -191,7 +191,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
EXPECT_EQ(16, buf->width);
@@ -203,7 +203,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);
- android_native_buffer_t* buf[2];
+ ANativeWindowBuffer* buf[2];
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
@@ -224,7 +224,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
sp<ANativeWindow> anw(mSTC);
sp<SurfaceTexture> st(mST);
- android_native_buffer_t* buf[2];
+ ANativeWindowBuffer* buf[2];
EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 6c713439dca2..8747ba5c7c53 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -476,7 +476,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
- android_native_buffer_t* anb;
+ ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
@@ -524,7 +524,7 @@ TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledYV12BufferPow2) {
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
- android_native_buffer_t* anb;
+ ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
@@ -583,7 +583,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
- android_native_buffer_t* anb;
+ ANativeWindowBuffer* anb;
ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
ASSERT_TRUE(anb != NULL);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 440a48b7c0df..35c86405584b 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -93,7 +93,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) {
ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
GRALLOC_USAGE_PROTECTED));
ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
- android_native_buffer_t* buf = 0;
+ ANativeWindowBuffer* buf = 0;
for (int i = 0; i < 4; i++) {
// Loop to make sure SurfaceFlinger has retired a protected buffer.
ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index faecadde245a..596781e31aa4 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -62,8 +62,10 @@ static const TextureVertex gMeshVertices[] = {
static const GLsizei gMeshStride = sizeof(TextureVertex);
static const GLsizei gVertexStride = sizeof(Vertex);
static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
+static const GLsizei gAAVertexStride = sizeof(AAVertex);
static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
-static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
+static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
+static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
static const GLsizei gMeshCount = 4;
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 34dda9a71bc6..f8582d8fff9e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -177,6 +177,331 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
void DisplayList::init() {
}
+/**
+ * This function is a simplified version of replay(), where we simply retrieve and log the
+ * display list. This function should remain in sync with the replay() function.
+ */
+void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
+ TextContainer text;
+
+ uint32_t count = (level + 1) * 2;
+ char indent[count + 1];
+ for (uint32_t i = 0; i < count; i++) {
+ indent[i] = ' ';
+ }
+ indent[count] = '\0';
+ LOGD("%sStart display list (%p)", (char*) indent + 2, this);
+
+ int saveCount = renderer.getSaveCount() - 1;
+
+ mReader.rewind();
+
+ while (!mReader.eof()) {
+ int op = mReader.readInt();
+
+ switch (op) {
+ case DrawGLFunction: {
+ Functor *functor = (Functor *) getInt();
+ LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
+ }
+ break;
+ case Save: {
+ int rendererNum = getInt();
+ LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
+ }
+ break;
+ case Restore: {
+ LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case RestoreToCount: {
+ int restoreCount = saveCount + getInt();
+ LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
+ }
+ break;
+ case SaveLayer: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ SkPaint* paint = getPaint();
+ int flags = getInt();
+ LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
+ OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+ }
+ break;
+ case SaveLayerAlpha: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ int alpha = getInt();
+ int flags = getInt();
+ LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
+ OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+ }
+ break;
+ case Translate: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
+ }
+ break;
+ case Rotate: {
+ float rotation = getFloat();
+ LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
+ }
+ break;
+ case Scale: {
+ float sx = getFloat();
+ float sy = getFloat();
+ LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+ }
+ break;
+ case Skew: {
+ float sx = getFloat();
+ float sy = getFloat();
+ LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+ }
+ break;
+ case SetMatrix: {
+ SkMatrix* matrix = getMatrix();
+ LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+ }
+ break;
+ case ConcatMatrix: {
+ SkMatrix* matrix = getMatrix();
+ LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+ }
+ break;
+ case ClipRect: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ int regionOp = getInt();
+ LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
+ f1, f2, f3, f4, regionOp);
+ }
+ break;
+ case DrawDisplayList: {
+ DisplayList* displayList = getDisplayList();
+ uint32_t width = getUInt();
+ uint32_t height = getUInt();
+ LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
+ displayList, width, height, level + 1);
+ renderer.outputDisplayList(displayList, level + 1);
+ }
+ break;
+ case DrawLayer: {
+ Layer* layer = (Layer*) getInt();
+ float x = getFloat();
+ float y = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+ layer, x, y, paint);
+ }
+ break;
+ case DrawBitmap: {
+ SkBitmap* bitmap = getBitmap();
+ float x = getFloat();
+ float y = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+ bitmap, x, y, paint);
+ }
+ break;
+ case DrawBitmapMatrix: {
+ SkBitmap* bitmap = getBitmap();
+ SkMatrix* matrix = getMatrix();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
+ bitmap, matrix, paint);
+ }
+ break;
+ case DrawBitmapRect: {
+ SkBitmap* bitmap = getBitmap();
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ float f5 = getFloat();
+ float f6 = getFloat();
+ float f7 = getFloat();
+ float f8 = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+ (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+ }
+ break;
+ case DrawBitmapMesh: {
+ int verticesCount = 0;
+ uint32_t colorsCount = 0;
+ SkBitmap* bitmap = getBitmap();
+ uint32_t meshWidth = getInt();
+ uint32_t meshHeight = getInt();
+ float* vertices = getFloats(verticesCount);
+ bool hasColors = getInt();
+ int* colors = hasColors ? getInts(colorsCount) : NULL;
+ SkPaint* paint = getPaint();
+ LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case DrawPatch: {
+ int32_t* xDivs = NULL;
+ int32_t* yDivs = NULL;
+ uint32_t* colors = NULL;
+ uint32_t xDivsCount = 0;
+ uint32_t yDivsCount = 0;
+ int8_t numColors = 0;
+ SkBitmap* bitmap = getBitmap();
+ xDivs = getInts(xDivsCount);
+ yDivs = getInts(yDivsCount);
+ colors = getUInts(numColors);
+ DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ getFloat();
+ getFloat();
+ getFloat();
+ getFloat();
+ getPaint();
+ }
+ break;
+ case DrawColor: {
+ int color = getInt();
+ int xferMode = getInt();
+ LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
+ }
+ break;
+ case DrawRect: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+ f1, f2, f3, f4, paint);
+ }
+ break;
+ case DrawRoundRect: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ float f5 = getFloat();
+ float f6 = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+ }
+ break;
+ case DrawCircle: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %.2f, %.2f, %.2f, %p",
+ (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+ }
+ break;
+ case DrawOval: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+ }
+ break;
+ case DrawArc: {
+ float f1 = getFloat();
+ float f2 = getFloat();
+ float f3 = getFloat();
+ float f4 = getFloat();
+ float f5 = getFloat();
+ float f6 = getFloat();
+ int i1 = getInt();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+ }
+ break;
+ case DrawPath: {
+ SkPath* path = getPath();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
+ }
+ break;
+ case DrawLines: {
+ int count = 0;
+ float* points = getFloats(count);
+ SkPaint* paint = getPaint();
+ LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case DrawPoints: {
+ int count = 0;
+ float* points = getFloats(count);
+ SkPaint* paint = getPaint();
+ LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case DrawText: {
+ getText(&text);
+ int count = getInt();
+ float x = getFloat();
+ float y = getFloat();
+ SkPaint* paint = getPaint();
+ LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+ text.text(), text.length(), count, x, y, paint);
+ }
+ break;
+ case ResetShader: {
+ LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case SetupShader: {
+ SkiaShader* shader = getShader();
+ LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
+ }
+ break;
+ case ResetColorFilter: {
+ LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case SetupColorFilter: {
+ SkiaColorFilter *colorFilter = getColorFilter();
+ LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
+ }
+ break;
+ case ResetShadow: {
+ LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case SetupShadow: {
+ float radius = getFloat();
+ float dx = getFloat();
+ float dy = getFloat();
+ int color = getInt();
+ LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
+ radius, dx, dy, color);
+ }
+ break;
+ default:
+ LOGD("Display List error: op not handled: %s%s",
+ (char*) indent, OP_NAMES[op]);
+ break;
+ }
+ }
+
+ LOGD("%sDone", (char*) indent + 2);
+}
+
+/**
+ * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
+ * in the output() function, since that function processes the same list of opcodes for the
+ * purposes of logging display list info for a given view.
+ */
bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
bool needsInvalidate = false;
TextContainer text;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b78210305be6..dcf2cf2ddb39 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -107,6 +107,8 @@ public:
bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
+ void output(OpenGLRenderer& renderer, uint32_t level = 0);
+
static void outputLogBuffer(int fd);
private:
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 16566b80164d..0310bc344798 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -47,6 +47,7 @@ struct Layer {
meshElementCount = 0;
isCacheable = true;
isTextureLayer = false;
+ renderTarget = GL_TEXTURE_2D;
}
~Layer() {
@@ -155,6 +156,11 @@ struct Layer {
* Optional texture coordinates transform.
*/
mat4 texTransform;
+
+ /**
+ * Indicates the render target.
+ */
+ GLenum renderTarget;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e167336c8657..f316ba79a1ea 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -185,17 +185,7 @@ Layer* LayerRenderer::createTextureLayer() {
layer->region.clear();
glActiveTexture(GL_TEXTURE0);
-
glGenTextures(1, &layer->texture);
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, layer->texture);
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-
- glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
return layer;
}
@@ -280,7 +270,7 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
}
void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
- float* transform) {
+ GLenum renderTarget, float* transform) {
if (layer) {
layer->width = width;
layer->height = height;
@@ -288,6 +278,15 @@ void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t he
layer->region.set(width, height);
layer->regionRect.set(0.0f, 0.0f, width, height);
layer->texTransform.load(transform);
+ layer->renderTarget = renderTarget;
+
+ glBindTexture(layer->renderTarget, layer->texture);
+
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(layer->renderTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index b3cd5db4fbe2..59cab963ca0a 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -57,7 +57,7 @@ public:
static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
- float* transform);
+ GLenum renderTarget, float* transform);
static void destroyLayer(Layer* layer);
static void destroyLayerDeferred(Layer* layer);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 34d8fd31e206..f6a21d4ce887 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -637,7 +637,12 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
float alpha = layer->alpha / 255.0f;
setupDraw();
- setupDrawWithExternalTexture();
+ if (layer->renderTarget == GL_TEXTURE_2D) {
+ setupDrawWithTexture();
+ } else {
+ setupDrawWithExternalTexture();
+ }
+ setupDrawTextureTransform();
setupDrawColor(alpha, alpha, alpha, alpha);
setupDrawColorFilter();
setupDrawBlending(layer->blend, layer->mode);
@@ -645,8 +650,12 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
- setupDrawExternalTexture(layer->texture);
- setupDrawTextureTransform(layer->texTransform);
+ if (layer->renderTarget == GL_TEXTURE_2D) {
+ setupDrawTexture(layer->texture);
+ } else {
+ setupDrawExternalTexture(layer->texture);
+ }
+ setupDrawTextureTransformUniforms(layer->texTransform);
setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
@@ -915,7 +924,7 @@ void OpenGLRenderer::setupDrawWithExternalTexture() {
}
void OpenGLRenderer::setupDrawAALine() {
- mDescription.hasWidth = true;
+ mDescription.isAA = true;
}
void OpenGLRenderer::setupDrawPoint(float pointSize) {
@@ -1095,7 +1104,11 @@ void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
glEnableVertexAttribArray(mTexCoordsSlot);
}
-void OpenGLRenderer::setupDrawTextureTransform(mat4& transform) {
+void OpenGLRenderer::setupDrawTextureTransform() {
+ mDescription.hasTextureTransform = true;
+}
+
+void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
GL_FALSE, &transform.data[0]);
}
@@ -1121,25 +1134,30 @@ void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
/**
* Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an
- * outer boundary that fades out to 0. The variables set in the shader define the width of the
- * core line primitive ("width") and the width of the fading boundary ("boundaryWidth"). The
- * "vtxDistance" attribute (one per vertex) is a value from zero to one that tells the fragment
- * shader where the fragment is in relation to the line width overall; this value is then used
- * to compute the proper color, based on whether the fragment lies in the fading AA region of
- * the line.
+ * outer boundary that fades out to 0. The variables set in the shader define the proportion of
+ * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength
+ * attributes (one per vertex) are values from zero to one that tells the fragment
+ * shader where the fragment is in relation to the line width/length overall; these values are
+ * then used to compute the proper color, based on whether the fragment lies in the fading AA
+ * region of the line.
+ * Note that we only pass down the width values in this setup function. The length coordinates
+ * are set up for each individual segment.
*/
-void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth) {
+void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
+ GLvoid* lengthCoords, float strokeWidth) {
mCaches.unbindMeshBuffer();
glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gAlphaVertexStride, vertices);
- int distanceSlot = mCaches.currentProgram->getAttrib("vtxDistance");
- glEnableVertexAttribArray(distanceSlot);
- glVertexAttribPointer(distanceSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, distanceCoords);
- int widthSlot = mCaches.currentProgram->getUniform("width");
+ gAAVertexStride, vertices);
+ int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
+ glEnableVertexAttribArray(widthSlot);
+ glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
+ int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
+ glEnableVertexAttribArray(lengthSlot);
+ glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
+ // Setting the inverse value saves computations per-fragment in the shader
int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
float boundaryWidth = (1 - strokeWidth) / 2;
- glUniform1f(widthSlot, strokeWidth);
glUniform1f(boundaryWidthSlot, boundaryWidth);
glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidth));
}
@@ -1167,6 +1185,12 @@ bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, u
return false;
}
+void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
+ if (displayList) {
+ displayList->output(*this, level);
+ }
+}
+
void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
int alpha;
SkXfermode::Mode mode;
@@ -1480,20 +1504,21 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
}
Vertex lines[verticesCount];
Vertex* vertices = &lines[0];
- AlphaVertex wLines[verticesCount];
- AlphaVertex* aaVertices = &wLines[0];
+ AAVertex wLines[verticesCount];
+ AAVertex* aaVertices = &wLines[0];
if (!isAA) {
setupDrawVertices(vertices);
} else {
- void* alphaCoords = ((GLbyte*) aaVertices) + gVertexAlphaOffset;
+ void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
+ void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
// innerProportion is the ratio of the inner (non-AA) port of the line to the total
// AA stroke width (the base stroke width expanded by a half pixel on either side).
// This value is used in the fragment shader to determine how to fill fragments.
float innerProportion = fmax(strokeWidth - 1.0f, 0) / (strokeWidth + .5f);
- setupDrawAALine((void*) aaVertices, alphaCoords, innerProportion);
+ setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, innerProportion);
}
- AlphaVertex *prevAAVertex = NULL;
+ AAVertex *prevAAVertex = NULL;
Vertex *prevVertex = NULL;
float inverseScaleX = 1.0f;
float inverseScaleY = 1.0f;
@@ -1516,15 +1541,17 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
}
}
+ int boundaryLengthSlot = -1;
+ int inverseBoundaryLengthSlot = -1;
for (int i = 0; i < count; i += 4) {
// a = start point, b = end point
vec2 a(points[i], points[i + 1]);
vec2 b(points[i + 2], points[i + 3]);
+ float length = 0;
// Find the normal to the line
vec2 n = (b - a).copyNormalized() * strokeWidth;
if (isHairLine) {
- n *= inverseScaleX;
if (isAA) {
float wideningFactor;
if (fabs(n.x) >= fabs(n.y)) {
@@ -1534,27 +1561,35 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
}
n *= wideningFactor;
}
+ n.x *= inverseScaleX;
+ n.y *= inverseScaleY;
}
float x = n.x;
n.x = -n.y;
n.y = x;
+ // aa lines expand the endpoint vertices to encompass the AA boundary
+ if (isAA) {
+ vec2 abVector = (b - a);
+ length = abVector.length();
+ abVector.normalize();
+ a -= abVector;
+ b += abVector;
+ }
+
// Four corners of the rectangle defining a thick line
vec2 p1 = a - n;
vec2 p2 = a + n;
vec2 p3 = b + n;
vec2 p4 = b - n;
+
const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x)));
const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x)));
const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y)));
const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y)));
if (!quickReject(left, top, right, bottom)) {
- // Draw the line as 2 triangles, could be optimized
- // by using only 4 vertices and the correct indices
- // Also we should probably used non textured vertices
- // when line AA is disabled to save on bandwidth
if (!isAA) {
if (prevVertex != NULL) {
// Issue two repeat vertices to create degenerate triangles to bridge
@@ -1572,24 +1607,36 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
prevVertex = vertices - 1;
generatedVerticesCount += 4;
} else {
+ if (boundaryLengthSlot < 0) {
+ boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
+ inverseBoundaryLengthSlot =
+ mCaches.currentProgram->getUniform("inverseBoundaryLength");
+ }
+ float innerProportion = (length) / (length + 2);
+ float boundaryLength = (1 - innerProportion) / 2;
+ glUniform1f(boundaryLengthSlot, boundaryLength);
+ glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLength));
+
if (prevAAVertex != NULL) {
// Issue two repeat vertices to create degenerate triangles to bridge
// between the previous line and the new one. This is necessary because
// we are creating a single triangle_strip which will contain
// potentially discontinuous line segments.
- AlphaVertex::set(aaVertices++,prevAAVertex->position[0],
- prevAAVertex->position[1], prevAAVertex->alpha);
- AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
+ AAVertex::set(aaVertices++,prevAAVertex->position[0],
+ prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length);
+ AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
generatedVerticesCount += 2;
}
- AlphaVertex::set(aaVertices++, p4.x, p4.y, 1);
- AlphaVertex::set(aaVertices++, p1.x, p1.y, 1);
- AlphaVertex::set(aaVertices++, p3.x, p3.y, 0);
- AlphaVertex::set(aaVertices++, p2.x, p2.y, 0);
+ AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
+ AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0);
+ AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1);
+ AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0);
prevAAVertex = aaVertices - 1;
generatedVerticesCount += 4;
}
- dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
+ dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top,
+ a.x == b.x ? right: right, a.y == b.y ? bottom: bottom,
+ *mSnapshot->transform);
}
}
if (generatedVerticesCount > 0) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 0ffd70b4ef99..271e4b16090b 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,6 +98,7 @@ public:
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
Rect& dirty, uint32_t level = 0);
+ virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -465,10 +466,12 @@ private:
void setupDrawSimpleMesh();
void setupDrawTexture(GLuint texture);
void setupDrawExternalTexture(GLuint texture);
- void setupDrawTextureTransform(mat4& transform);
+ void setupDrawTextureTransform();
+ void setupDrawTextureTransformUniforms(mat4& transform);
void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
void setupDrawVertices(GLvoid* vertices);
- void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth);
+ void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
+ float strokeWidth);
void finishDrawTexture();
void drawRegionRects(const Region& region);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 62ac2baaf7b6..d419e3eab38c 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -39,8 +39,9 @@ const char* gVS_Header_Attributes =
"attribute vec4 position;\n";
const char* gVS_Header_Attributes_TexCoords =
"attribute vec2 texCoords;\n";
-const char* gVS_Header_Attributes_Distance =
- "attribute float vtxDistance;\n";
+const char* gVS_Header_Attributes_AAParameters =
+ "attribute float vtxWidth;\n"
+ "attribute float vtxLength;\n";
const char* gVS_Header_Uniforms_TextureTransform =
"uniform mat4 mainTextureTransform;\n";
const char* gVS_Header_Uniforms =
@@ -60,8 +61,9 @@ const char* gVS_Header_Uniforms_HasBitmap =
"uniform mediump vec2 textureDimension;\n";
const char* gVS_Header_Varyings_HasTexture =
"varying vec2 outTexCoords;\n";
-const char* gVS_Header_Varyings_HasWidth =
- "varying float distance;\n";
+const char* gVS_Header_Varyings_IsAA =
+ "varying float widthProportion;\n"
+ "varying float lengthProportion;\n";
const char* gVS_Header_Varyings_HasBitmap =
"varying vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_PointHasBitmap =
@@ -96,8 +98,9 @@ const char* gVS_Main_Position =
" gl_Position = transform * position;\n";
const char* gVS_Main_PointSize =
" gl_PointSize = pointSize;\n";
-const char* gVS_Main_Width =
- " distance = vtxDistance;\n";
+const char* gVS_Main_AA =
+ " widthProportion = vtxWidth;\n"
+ " lengthProportion = vtxLength;\n";
const char* gVS_Footer =
"}\n\n";
@@ -113,10 +116,11 @@ const char* gFS_Header =
"precision mediump float;\n\n";
const char* gFS_Uniforms_Color =
"uniform vec4 color;\n";
-const char* gFS_Uniforms_Width =
- "uniform float width;\n"
+const char* gFS_Uniforms_AA =
"uniform float boundaryWidth;\n"
- "uniform float inverseBoundaryWidth;\n";
+ "uniform float inverseBoundaryWidth;\n"
+ "uniform float boundaryLength;\n"
+ "uniform float inverseBoundaryLength;\n";
const char* gFS_Header_Uniforms_PointHasBitmap =
"uniform vec2 textureDimension;\n"
"uniform float pointSize;\n";
@@ -189,11 +193,16 @@ const char* gFS_Main_FetchColor =
" fragColor = color;\n";
const char* gFS_Main_ModulateColor =
" fragColor *= color.a;\n";
-const char* gFS_Main_AccountForWidth =
- " if (distance < boundaryWidth) {\n"
- " fragColor *= (distance * inverseBoundaryWidth);\n"
- " } else if (distance > (1.0 - boundaryWidth)) {\n"
- " fragColor *= ((1.0 - distance) * inverseBoundaryWidth);\n"
+const char* gFS_Main_AccountForAA =
+ " if (widthProportion < boundaryWidth) {\n"
+ " fragColor *= (widthProportion * inverseBoundaryWidth);\n"
+ " } else if (widthProportion > (1.0 - boundaryWidth)) {\n"
+ " fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n"
+ " }\n"
+ " if (lengthProportion < boundaryLength) {\n"
+ " fragColor *= (lengthProportion * inverseBoundaryLength);\n"
+ " } else if (lengthProportion > (1.0 - boundaryLength)) {\n"
+ " fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n"
" }\n";
const char* gFS_Main_FetchTexture[2] = {
// Don't modulate
@@ -380,12 +389,12 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Attributes_TexCoords);
}
- if (description.hasWidth) {
- shader.append(gVS_Header_Attributes_Distance);
+ if (description.isAA) {
+ shader.append(gVS_Header_Attributes_AAParameters);
}
// Uniforms
shader.append(gVS_Header_Uniforms);
- if (description.hasExternalTexture) {
+ if (description.hasTextureTransform) {
shader.append(gVS_Header_Uniforms_TextureTransform);
}
if (description.hasGradient) {
@@ -401,8 +410,8 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
}
- if (description.hasWidth) {
- shader.append(gVS_Header_Varyings_HasWidth);
+ if (description.isAA) {
+ shader.append(gVS_Header_Varyings_IsAA);
}
if (description.hasGradient) {
shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -415,14 +424,13 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
// Begin the shader
shader.append(gVS_Main); {
- if (description.hasTexture) {
- shader.append(gVS_Main_OutTexCoords);
- }
- if (description.hasExternalTexture) {
+ if (description.hasTextureTransform) {
shader.append(gVS_Main_OutTransformedTexCoords);
+ } else if (description.hasTexture || description.hasExternalTexture) {
+ shader.append(gVS_Main_OutTexCoords);
}
- if (description.hasWidth) {
- shader.append(gVS_Main_Width);
+ if (description.isAA) {
+ shader.append(gVS_Main_AA);
}
if (description.hasGradient) {
shader.append(gVS_Main_OutGradient[description.gradientType]);
@@ -464,8 +472,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
}
- if (description.hasWidth) {
- shader.append(gVS_Header_Varyings_HasWidth);
+ if (description.isAA) {
+ shader.append(gVS_Header_Varyings_IsAA);
}
if (description.hasGradient) {
shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]);
@@ -487,12 +495,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
}
if (description.hasTexture) {
shader.append(gFS_Uniforms_TextureSampler);
- }
- if (description.hasExternalTexture) {
+ } else if (description.hasExternalTexture) {
shader.append(gFS_Uniforms_ExternalTextureSampler);
}
- if (description.hasWidth) {
- shader.append(gFS_Uniforms_Width);
+ if (description.isAA) {
+ shader.append(gFS_Uniforms_AA);
}
if (description.hasGradient) {
shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
@@ -502,7 +509,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
}
// Optimization for common cases
- if (!description.hasWidth && !blendFramebuffer &&
+ if (!description.isAA && !blendFramebuffer &&
description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
bool fast = false;
@@ -587,8 +594,8 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
shader.append(gFS_Main_FetchColor);
}
}
- if (description.hasWidth) {
- shader.append(gFS_Main_AccountForWidth);
+ if (description.isAA) {
+ shader.append(gFS_Main_AccountForAA);
}
if (description.hasGradient) {
shader.append(gFS_Main_FetchGradient[description.gradientType]);
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 70909fd622bf..5c7197b620cd 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -75,9 +75,10 @@ namespace uirenderer {
#define PROGRAM_IS_POINT_SHIFT 36
-#define PROGRAM_HAS_WIDTH_SHIFT 37
+#define PROGRAM_HAS_AA_SHIFT 37
#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
+#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -116,6 +117,7 @@ struct ProgramDescription {
bool hasTexture;
bool hasAlpha8Texture;
bool hasExternalTexture;
+ bool hasTextureTransform;
// Modulate, this should only be set when setColor() return true
bool modulate;
@@ -124,7 +126,7 @@ struct ProgramDescription {
bool hasBitmap;
bool isBitmapNpot;
- bool hasWidth;
+ bool isAA;
bool hasGradient;
Gradient gradientType;
@@ -155,8 +157,9 @@ struct ProgramDescription {
hasTexture = false;
hasAlpha8Texture = false;
hasExternalTexture = false;
+ hasTextureTransform = false;
- hasWidth = false;
+ isAA = false;
modulate = false;
@@ -243,8 +246,9 @@ struct ProgramDescription {
if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
- if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
+ if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
+ if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
return key;
}
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c120428e16d0..38455dc93274 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -68,6 +68,25 @@ struct AlphaVertex : Vertex {
}
}; // struct AlphaVertex
+/**
+ * Simple structure to describe a vertex with a position and an alpha value.
+ */
+struct AAVertex : Vertex {
+ float width;
+ float length;
+
+ static inline void set(AAVertex* vertex, float x, float y, float width, float length) {
+ Vertex::set(vertex, x, y);
+ vertex[0].width = width;
+ vertex[0].length = length;
+ }
+
+ static inline void setColor(AAVertex* vertex, float width, float length) {
+ vertex[0].width = width;
+ vertex[0].length = length;
+ }
+}; // struct AlphaVertex
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index a99a599e2225..232ab36ceb88 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -110,20 +110,23 @@ LOCAL_SRC_FILES:= \
rsScriptC.cpp \
rsScriptC_Lib.cpp \
rsScriptC_LibGL.cpp \
- rsShaderCache.cpp \
rsSignal.cpp \
rsStream.cpp \
rsThreadIO.cpp \
rsType.cpp \
- rsVertexArray.cpp \
driver/rsdBcc.cpp \
driver/rsdCore.cpp \
driver/rsdGL.cpp \
+ driver/rsdMesh.cpp \
+ driver/rsdMeshObj.cpp \
+ driver/rsdProgram.cpp \
driver/rsdProgramRaster.cpp \
driver/rsdProgramStore.cpp \
driver/rsdRuntimeMath.cpp \
- driver/rsdRuntimeStubs.cpp
-
+ driver/rsdRuntimeStubs.cpp \
+ driver/rsdShader.cpp \
+ driver/rsdShaderCache.cpp \
+ driver/rsdVertexArray.cpp
LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 5b80439974cb..d5d23c755ab7 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -19,6 +19,9 @@
#include "rsdGL.h"
#include "rsdProgramStore.h"
#include "rsdProgramRaster.h"
+#include "rsdProgramVertex.h"
+#include "rsdProgramFragment.h"
+#include "rsdMesh.h"
#include <malloc.h>
#include "rsContext.h"
@@ -69,6 +72,24 @@ static RsdHalFunctions FunctionTable = {
rsdProgramRasterInit,
rsdProgramRasterSetActive,
rsdProgramRasterDestroy
+ },
+
+ {
+ rsdProgramVertexInit,
+ rsdProgramVertexSetActive,
+ rsdProgramVertexDestroy
+ },
+
+ {
+ rsdProgramFragmentInit,
+ rsdProgramFragmentSetActive,
+ rsdProgramFragmentDestroy
+ },
+
+ {
+ rsdMeshInit,
+ rsdMeshDraw,
+ rsdMeshDestroy
}
};
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 26e1bdf4fa27..48690d54490c 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -40,6 +40,8 @@
#include <malloc.h>
#include "rsContext.h"
+#include "rsdShaderCache.h"
+#include "rsdVertexArray.h"
using namespace android;
using namespace android::renderscript;
@@ -128,6 +130,11 @@ static void DumpDebug(RsdHal *dc) {
void rsdGLShutdown(const Context *rsc) {
RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ dc->gl.shaderCache->cleanupAll();
+ delete dc->gl.shaderCache;
+
+ delete dc->gl.vertexArrayState;
+
LOGV("%p, deinitEGL", rsc);
if (dc->gl.egl.context != EGL_NO_CONTEXT) {
@@ -287,6 +294,10 @@ bool rsdGLInit(const Context *rsc) {
DumpDebug(dc);
}
+ dc->gl.shaderCache = new RsdShaderCache();
+ dc->gl.vertexArrayState = new RsdVertexArrayState();
+ dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
+
LOGV("initGLThread end %p", rsc);
return true;
}
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 246931f8ff7c..351b2d5dd4e2 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -19,7 +19,8 @@
#include <rs_hal.h>
-
+class RsdShaderCache;
+class RsdVertexArrayState;
typedef void (* InvokeFunc_t)(void);
typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
@@ -64,6 +65,8 @@ typedef struct RsdGLRec {
ANativeWindow *wndSurface;
uint32_t width;
uint32_t height;
+ RsdShaderCache *shaderCache;
+ RsdVertexArrayState *vertexArrayState;
} RsdGL;
diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
new file mode 100644
index 000000000000..eb62ddb6a845
--- /dev/null
+++ b/libs/rs/driver/rsdMesh.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 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 <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdCore.h"
+#include "rsdMesh.h"
+#include "rsdMeshObj.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdMeshInit(const Context *rsc, const Mesh *m) {
+ RsdMeshObj *drv = NULL;
+ if(m->mHal.drv) {
+ drv = (RsdMeshObj*)m->mHal.drv;
+ delete drv;
+ }
+ drv = new RsdMeshObj(rsc, m);
+ m->mHal.drv = drv;
+ return drv->init();
+}
+
+void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
+ if(m->mHal.drv) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ if (!dc->gl.shaderCache->setup(rsc)) {
+ return;
+ }
+
+ RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+ drv->renderPrimitiveRange(rsc, primIndex, start, len);
+ }
+}
+
+void rsdMeshDestroy(const Context *rsc, const Mesh *m) {
+ if(m->mHal.drv) {
+ RsdMeshObj *drv = (RsdMeshObj*)m->mHal.drv;
+ delete drv;
+ }
+}
+
+
diff --git a/libs/rs/driver/rsdMesh.h b/libs/rs/driver/rsdMesh.h
new file mode 100644
index 000000000000..d2714fd24a29
--- /dev/null
+++ b/libs/rs/driver/rsdMesh.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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 RSD_MESH_H
+#define RSD_MESH_H
+
+#include <rs_hal.h>
+
+
+bool rsdMeshInit(const android::renderscript::Context *rsc,
+ const android::renderscript::Mesh *m);
+void rsdMeshDraw(const android::renderscript::Context *rsc,
+ const android::renderscript::Mesh *m,
+ uint32_t primIndex, uint32_t start, uint32_t len);
+void rsdMeshDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::Mesh *m);
+
+
+#endif
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
new file mode 100644
index 000000000000..6bb33f76fe95
--- /dev/null
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2011 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 <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsMesh.h>
+
+#include "rsdMeshObj.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdMeshObj::RsdMeshObj(const Context *rsc, const Mesh *rsMesh) {
+ mRSMesh = rsMesh;
+
+ mAttribs = NULL;
+ mAttribAllocationIndex = NULL;
+ mGLPrimitives = NULL;
+
+ mAttribCount = 0;
+}
+
+RsdMeshObj::~RsdMeshObj() {
+ if (mAttribs) {
+ delete[] mAttribs;
+ delete[] mAttribAllocationIndex;
+ }
+ if (mGLPrimitives) {
+ delete[] mGLPrimitives;
+ }
+}
+
+bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
+ // Do not create attribs for padding
+ if (elem->getFieldName(fieldIdx)[0] == '#') {
+ return false;
+ }
+
+ // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
+ // Filter rs types accordingly
+ RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+ if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
+ dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
+ dt != RS_TYPE_SIGNED_16) {
+ return false;
+ }
+
+ // Now make sure they are not arrays
+ uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+ if (arraySize != 1) {
+ return false;
+ }
+
+ return true;
+}
+
+bool RsdMeshObj::init() {
+
+ updateGLPrimitives();
+
+ // Count the number of gl attrs to initialize
+ mAttribCount = 0;
+ for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+ const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+ for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+ if (isValidGLComponent(elem, ct)) {
+ mAttribCount ++;
+ }
+ }
+ }
+
+ if (mAttribs) {
+ delete [] mAttribs;
+ delete [] mAttribAllocationIndex;
+ mAttribs = NULL;
+ mAttribAllocationIndex = NULL;
+ }
+ if (!mAttribCount) {
+ return false;
+ }
+
+ mAttribs = new RsdVertexArray::Attrib[mAttribCount];
+ mAttribAllocationIndex = new uint32_t[mAttribCount];
+
+ uint32_t userNum = 0;
+ for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
+ const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
+ uint32_t stride = elem->getSizeBytes();
+ for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
+ const Component &c = elem->getField(fieldI)->getComponent();
+
+ if (!isValidGLComponent(elem, fieldI)) {
+ continue;
+ }
+
+ mAttribs[userNum].size = c.getVectorSize();
+ mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
+ mAttribs[userNum].type = c.getGLType();
+ mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+ mAttribs[userNum].stride = stride;
+ String8 tmp(RS_SHADER_ATTR);
+ tmp.append(elem->getFieldName(fieldI));
+ mAttribs[userNum].name.setTo(tmp.string());
+
+ // Remember which allocation this attribute came from
+ mAttribAllocationIndex[userNum] = ct;
+ userNum ++;
+ }
+ }
+
+ return true;
+}
+
+void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
+ if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
+ LOGE("Invalid mesh or parameters");
+ return;
+ }
+
+ rsc->checkError("Mesh::renderPrimitiveRange 1");
+ // update attributes with either buffer information or data ptr based on their current state
+ for (uint32_t ct=0; ct < mAttribCount; ct++) {
+ uint32_t allocIndex = mAttribAllocationIndex[ct];
+ Allocation *alloc = mRSMesh->mHal.state.vertexBuffers[allocIndex].get();
+ if (alloc->getIsBufferObject() && alloc->getBufferObjectID()) {
+ mAttribs[ct].buffer = alloc->getBufferObjectID();
+ mAttribs[ct].ptr = NULL;
+ } else {
+ mAttribs[ct].buffer = 0;
+ mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
+ }
+ }
+
+ RsdVertexArray va(mAttribs, mAttribCount);
+ va.setupGL2(rsc);
+
+ rsc->checkError("Mesh::renderPrimitiveRange 2");
+ Mesh::Primitive_t *prim = mRSMesh->mHal.state.primitives[primIndex];
+ if (prim->mIndexBuffer.get()) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
+ glDrawElements(mGLPrimitives[primIndex], len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
+ } else {
+ glDrawArrays(mGLPrimitives[primIndex], start, len);
+ }
+
+ rsc->checkError("Mesh::renderPrimitiveRange");
+}
+
+void RsdMeshObj::updateGLPrimitives() {
+ mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
+ for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
+ switch (mRSMesh->mHal.state.primitives[i]->mPrimitive) {
+ case RS_PRIMITIVE_POINT: mGLPrimitives[i] = GL_POINTS; break;
+ case RS_PRIMITIVE_LINE: mGLPrimitives[i] = GL_LINES; break;
+ case RS_PRIMITIVE_LINE_STRIP: mGLPrimitives[i] = GL_LINE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break;
+ case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
+ case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+ }
+ }
+}
diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
new file mode 100644
index 000000000000..8b1271baeaf7
--- /dev/null
+++ b/libs/rs/driver/rsdMeshObj.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 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_RSD_MESH_OBJ_H
+#define ANDROID_RSD_MESH_OBJ_H
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+ class Context;
+ class Mesh;
+ class Element;
+
+}
+}
+
+#include "driver/rsdVertexArray.h"
+
+// An element is a group of Components that occupies one cell in a structure.
+class RsdMeshObj {
+public:
+ RsdMeshObj(const android::renderscript::Context *,
+ const android::renderscript::Mesh *);
+ ~RsdMeshObj();
+
+ void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+
+ bool init();
+
+protected:
+ const android::renderscript::Mesh *mRSMesh;
+
+ uint32_t *mGLPrimitives;
+ void updateGLPrimitives();
+
+ bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
+ // Attribues that allow us to map to GL
+ RsdVertexArray::Attrib *mAttribs;
+ // This allows us to figure out which allocation the attribute
+ // belongs to. In the event the allocation is uploaded to GL
+ // buffer, it lets us properly map it
+ uint32_t *mAttribAllocationIndex;
+ uint32_t mAttribCount;
+};
+
+#endif //ANDROID_RSD_MESH_OBJ_H
+
+
+
diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
new file mode 100644
index 000000000000..502c5ee5903e
--- /dev/null
+++ b/libs/rs/driver/rsdProgram.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 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 "rsdCore.h"
+#include "rsdProgramVertex.h"
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+#include "rsContext.h"
+#include "rsProgramVertex.h"
+#include "rsProgramFragment.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv,
+ const char* shader, uint32_t shaderLen) {
+ RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen);
+ pv->mHal.drv = drv;
+
+ return drv->createShader();
+}
+
+void rsdProgramVertexSetActive(const Context *rsc, const ProgramVertex *pv) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ dc->gl.shaderCache->setActiveVertex((RsdShader*)pv->mHal.drv);
+}
+
+void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ RsdShader *drv = NULL;
+ if(pv->mHal.drv) {
+ drv = (RsdShader*)pv->mHal.drv;
+ if (rsc->props.mLogShaders) {
+ LOGV("Destroying vertex shader with ID %u", drv->getShaderID());
+ }
+ if (drv->getShaderID()) {
+ dc->gl.shaderCache->cleanupVertex(drv->getShaderID());
+ }
+ delete drv;
+ }
+}
+
+bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf,
+ const char* shader, uint32_t shaderLen) {
+ RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen);
+ pf->mHal.drv = drv;
+
+ return drv->createShader();
+}
+
+void rsdProgramFragmentSetActive(const Context *rsc, const ProgramFragment *pf) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ dc->gl.shaderCache->setActiveFragment((RsdShader*)pf->mHal.drv);
+}
+
+void rsdProgramFragmentDestroy(const Context *rsc, const ProgramFragment *pf) {
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+
+ RsdShader *drv = NULL;
+ if(pf->mHal.drv) {
+ drv = (RsdShader*)pf->mHal.drv;
+ if (rsc->props.mLogShaders) {
+ LOGV("Destroying fragment shader with ID %u", drv->getShaderID());
+ }
+ if (drv->getShaderID()) {
+ dc->gl.shaderCache->cleanupFragment(drv->getShaderID());
+ }
+ delete drv;
+ }
+}
+
+
diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h
new file mode 100644
index 000000000000..366cb40d2962
--- /dev/null
+++ b/libs/rs/driver/rsdProgramFragment.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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 RSD_PROGRAM_FRAGMENT_H
+#define RSD_PROGRAM_FRAGMENT_H
+
+#include <rs_hal.h>
+
+
+bool rsdProgramFragmentInit(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramFragment *,
+ const char* shader, uint32_t shaderLen);
+void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramFragment *);
+void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramFragment *);
+
+
+#endif //RSD_PROGRAM_Fragment_H
diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h
new file mode 100644
index 000000000000..e99857298165
--- /dev/null
+++ b/libs/rs/driver/rsdProgramVertex.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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 RSD_PROGRAM_VERTEX_H
+#define RSD_PROGRAM_VERTEX_H
+
+#include <rs_hal.h>
+
+bool rsdProgramVertexInit(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramVertex *,
+ const char* shader, uint32_t shaderLen);
+void rsdProgramVertexSetActive(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramVertex *);
+void rsdProgramVertexDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::ProgramVertex *);
+
+
+#endif //RSD_PROGRAM_VERTEX_H
diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index 093e311e5a3d..acb990d8c78b 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/driver/rsdRuntimeMath.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index b70a1232ef3d..9cbff9526b16 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
new file mode 100644
index 000000000000..fc623d689dfd
--- /dev/null
+++ b/libs/rs/driver/rsdShader.cpp
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2011 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 <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsProgram.h>
+
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+RsdShader::RsdShader(const Program *p, uint32_t type,
+ const char * shaderText, uint32_t shaderLength) {
+
+ mUserShader.setTo(shaderText, shaderLength);
+ mRSProgram = p;
+ mType = type;
+ initMemberVars();
+ initAttribAndUniformArray();
+ init();
+}
+
+RsdShader::~RsdShader() {
+ if (mShaderID) {
+ glDeleteShader(mShaderID);
+ }
+
+ delete[] mAttribNames;
+ delete[] mUniformNames;
+ delete[] mUniformArraySizes;
+}
+
+void RsdShader::initMemberVars() {
+ mDirty = true;
+ mShaderID = 0;
+ mAttribCount = 0;
+ mUniformCount = 0;
+
+ mAttribNames = NULL;
+ mUniformNames = NULL;
+ mUniformArraySizes = NULL;
+
+ mIsValid = false;
+}
+
+void RsdShader::init() {
+ uint32_t attribCount = 0;
+ uint32_t uniformCount = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ initAddUserElement(mRSProgram->mHal.state.inputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
+ }
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
+ }
+
+ mTextureUniformIndexStart = uniformCount;
+ char buf[256];
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+ snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
+ mUniformNames[uniformCount].setTo(buf);
+ mUniformArraySizes[uniformCount] = 1;
+ uniformCount++;
+ }
+}
+
+String8 RsdShader::getGLSLInputString() const {
+ String8 s;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+
+ // Cannot be complex
+ rsAssert(!f->getFieldCount());
+ switch (f->getComponent().getVectorSize()) {
+ case 1: s.append("attribute float ATTRIB_"); break;
+ case 2: s.append("attribute vec2 ATTRIB_"); break;
+ case 3: s.append("attribute vec3 ATTRIB_"); break;
+ case 4: s.append("attribute vec4 ATTRIB_"); break;
+ default:
+ rsAssert(0);
+ }
+
+ s.append(e->getFieldName(field));
+ s.append(";\n");
+ }
+ }
+ return s;
+}
+
+void RsdShader::appendAttributes() {
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ const Element *e = mRSProgram->mHal.state.inputElements[ct].get();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+ const char *fn = e->getFieldName(field);
+
+ if (fn[0] == '#') {
+ continue;
+ }
+
+ // Cannot be complex
+ rsAssert(!f->getFieldCount());
+ switch (f->getComponent().getVectorSize()) {
+ case 1: mShader.append("attribute float ATTRIB_"); break;
+ case 2: mShader.append("attribute vec2 ATTRIB_"); break;
+ case 3: mShader.append("attribute vec3 ATTRIB_"); break;
+ case 4: mShader.append("attribute vec4 ATTRIB_"); break;
+ default:
+ rsAssert(0);
+ }
+
+ mShader.append(fn);
+ mShader.append(";\n");
+ }
+ }
+}
+
+void RsdShader::appendTextures() {
+ char buf[256];
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+ if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
+ snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+ } else {
+ snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
+ }
+ mShader.append(buf);
+ }
+}
+
+bool RsdShader::createShader() {
+
+ if (mType == GL_FRAGMENT_SHADER) {
+ mShader.append("precision mediump float;\n");
+ }
+ appendUserConstants();
+ appendAttributes();
+ appendTextures();
+
+ mShader.append(mUserShader);
+
+ return true;
+}
+
+bool RsdShader::loadShader(const Context *rsc) {
+ mShaderID = glCreateShader(mType);
+ rsAssert(mShaderID);
+
+ if (rsc->props.mLogShaders) {
+ LOGV("Loading shader type %x, ID %i", mType, mShaderID);
+ LOGV("%s", mShader.string());
+ }
+
+ if (mShaderID) {
+ const char * ss = mShader.string();
+ glShaderSource(mShaderID, 1, &ss, NULL);
+ glCompileShader(mShaderID);
+
+ GLint compiled = 0;
+ glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen) {
+ char* buf = (char*) malloc(infoLen);
+ if (buf) {
+ glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
+ LOGE("Could not compile shader \n%s\n", buf);
+ free(buf);
+ }
+ glDeleteShader(mShaderID);
+ mShaderID = 0;
+ rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
+ return false;
+ }
+ }
+ }
+
+ if (rsc->props.mLogShaders) {
+ LOGV("--Shader load result %x ", glGetError());
+ }
+ mIsValid = true;
+ return true;
+}
+
+void RsdShader::appendUserConstants() {
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+ const char *fn = e->getFieldName(field);
+
+ if (fn[0] == '#') {
+ continue;
+ }
+
+ // Cannot be complex
+ rsAssert(!f->getFieldCount());
+ if (f->getType() == RS_TYPE_MATRIX_4X4) {
+ mShader.append("uniform mat4 UNI_");
+ } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+ mShader.append("uniform mat3 UNI_");
+ } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+ mShader.append("uniform mat2 UNI_");
+ } else {
+ switch (f->getComponent().getVectorSize()) {
+ case 1: mShader.append("uniform float UNI_"); break;
+ case 2: mShader.append("uniform vec2 UNI_"); break;
+ case 3: mShader.append("uniform vec3 UNI_"); break;
+ case 4: mShader.append("uniform vec4 UNI_"); break;
+ default:
+ rsAssert(0);
+ }
+ }
+
+ mShader.append(fn);
+ if (e->getFieldArraySize(field) > 1) {
+ mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+ }
+ mShader.append(";\n");
+ }
+ }
+}
+
+void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
+ RsDataType dataType = field->getType();
+ uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+ for (uint32_t i = 0; i < arraySize; i ++) {
+ if (arraySize > 1) {
+ LOGV("Array Element [%u]", i);
+ }
+ if (dataType == RS_TYPE_MATRIX_4X4) {
+ LOGV("Matrix4x4");
+ LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]);
+ LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]);
+ LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]);
+ LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
+ } else if (dataType == RS_TYPE_MATRIX_3X3) {
+ LOGV("Matrix3x3");
+ LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]);
+ LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]);
+ LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
+ } else if (dataType == RS_TYPE_MATRIX_2X2) {
+ LOGV("Matrix2x2");
+ LOGV("{%f, %f", fd[0], fd[2]);
+ LOGV(" %f, %f}", fd[1], fd[3]);
+ } else {
+ switch (field->getComponent().getVectorSize()) {
+ case 1:
+ LOGV("Uniform 1 = %f", fd[0]);
+ break;
+ case 2:
+ LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
+ break;
+ case 3:
+ LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
+ break;
+ case 4:
+ LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
+ break;
+ default:
+ rsAssert(0);
+ }
+ }
+ LOGE("Element size %u data=%p", elementSize, fd);
+ fd += elementSize;
+ LOGE("New data=%p", fd);
+ }
+}
+
+void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
+ int32_t slot, uint32_t arraySize ) {
+ RsDataType dataType = field->getType();
+ if (dataType == RS_TYPE_MATRIX_4X4) {
+ glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
+ } else if (dataType == RS_TYPE_MATRIX_3X3) {
+ glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
+ } else if (dataType == RS_TYPE_MATRIX_2X2) {
+ glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
+ } else {
+ switch (field->getComponent().getVectorSize()) {
+ case 1:
+ glUniform1fv(slot, arraySize, fd);
+ break;
+ case 2:
+ glUniform2fv(slot, arraySize, fd);
+ break;
+ case 3:
+ glUniform3fv(slot, arraySize, fd);
+ break;
+ case 4:
+ glUniform4fv(slot, arraySize, fd);
+ break;
+ default:
+ rsAssert(0);
+ }
+ }
+}
+
+void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) {
+ if (mRSProgram->mHal.state.texturesCount == 0) {
+ return;
+ }
+
+ uint32_t numTexturesToBind = mRSProgram->mHal.state.texturesCount;
+ uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
+ if (numTexturesToBind >= numTexturesAvailable) {
+ LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
+ mRSProgram->mHal.state.texturesCount, (uint32_t)this, numTexturesAvailable);
+ rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
+ numTexturesToBind = numTexturesAvailable;
+ }
+
+ for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
+ glActiveTexture(GL_TEXTURE0 + ct);
+ if (!mRSProgram->mHal.state.textures[ct].get()) {
+ LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
+ rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
+ continue;
+ }
+
+ GLenum target = (GLenum)mRSProgram->mHal.state.textures[ct]->getGLTarget();
+ if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
+ LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
+ rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
+ }
+ glBindTexture(target, mRSProgram->mHal.state.textures[ct]->getTextureID());
+ rsc->checkError("ProgramFragment::setupGL2 tex bind");
+ if (mRSProgram->mHal.state.samplers[ct].get()) {
+ mRSProgram->mHal.state.samplers[ct]->setupGL(rsc, mRSProgram->mHal.state.textures[ct].get());
+ } else {
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ rsc->checkError("ProgramFragment::setupGL2 tex env");
+ }
+
+ glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
+ rsc->checkError("ProgramFragment::setupGL2 uniforms");
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ mDirty = false;
+ rsc->checkError("ProgramFragment::setupGL2");
+}
+
+void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool isFragment) {
+ uint32_t uidx = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ Allocation *alloc = mRSProgram->mHal.state.constants[ct].get();
+ if (!alloc) {
+ LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
+ rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
+ continue;
+ }
+
+ const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
+ const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+ for (uint32_t field=0; field < e->getFieldCount(); field++) {
+ const Element *f = e->getField(field);
+ const char *fieldName = e->getFieldName(field);
+ // If this field is padding, skip it
+ if (fieldName[0] == '#') {
+ continue;
+ }
+
+ uint32_t offset = e->getFieldOffsetBytes(field);
+ const float *fd = reinterpret_cast<const float *>(&data[offset]);
+
+ int32_t slot = -1;
+ uint32_t arraySize = 1;
+ if (!isFragment) {
+ slot = sc->vtxUniformSlot(uidx);
+ arraySize = sc->vtxUniformSize(uidx);
+ } else {
+ slot = sc->fragUniformSlot(uidx);
+ arraySize = sc->fragUniformSize(uidx);
+ }
+ if (rsc->props.mLogShadersUniforms) {
+ LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
+ }
+ uidx ++;
+ if (slot < 0) {
+ continue;
+ }
+
+ if (rsc->props.mLogShadersUniforms) {
+ logUniform(f, fd, arraySize);
+ }
+ setUniform(rsc, f, fd, slot, arraySize);
+ }
+ }
+}
+
+void RsdShader::setup(const android::renderscript::Context *rsc, RsdShaderCache *sc) {
+
+ setupUserConstants(rsc, sc, mType == GL_FRAGMENT_SHADER);
+ setupTextures(rsc, sc);
+}
+
+void RsdShader::initAttribAndUniformArray() {
+ mAttribCount = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
+ const Element *elem = mRSProgram->mHal.state.inputElements[ct].get();
+ for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+ if (elem->getFieldName(field)[0] != '#') {
+ mAttribCount ++;
+ }
+ }
+ }
+
+ mUniformCount = 0;
+ for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
+ const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
+
+ for (uint32_t field=0; field < elem->getFieldCount(); field++) {
+ if (elem->getFieldName(field)[0] != '#') {
+ mUniformCount ++;
+ }
+ }
+ }
+ mUniformCount += mRSProgram->mHal.state.texturesCount;
+
+ if (mAttribCount) {
+ mAttribNames = new String8[mAttribCount];
+ }
+ if (mUniformCount) {
+ mUniformNames = new String8[mUniformCount];
+ mUniformArraySizes = new uint32_t[mUniformCount];
+ }
+}
+
+void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
+ rsAssert(e->getFieldCount());
+ for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
+ const Element *ce = e->getField(ct);
+ if (ce->getFieldCount()) {
+ initAddUserElement(ce, names, arrayLengths, count, prefix);
+ } else if (e->getFieldName(ct)[0] != '#') {
+ String8 tmp(prefix);
+ tmp.append(e->getFieldName(ct));
+ names[*count].setTo(tmp.string());
+ if (arrayLengths) {
+ arrayLengths[*count] = e->getFieldArraySize(ct);
+ }
+ (*count)++;
+ }
+ }
+}
diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
new file mode 100644
index 000000000000..37b1c3d0b496
--- /dev/null
+++ b/libs/rs/driver/rsdShader.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2011 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_RSD_SHADER_H
+#define ANDROID_RSD_SHADER_H
+
+#include <utils/String8.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Element;
+class Context;
+class Program;
+
+}
+}
+
+class RsdShaderCache;
+
+#define RS_SHADER_ATTR "ATTRIB_"
+#define RS_SHADER_UNI "UNI_"
+
+class RsdShader {
+public:
+
+ RsdShader(const android::renderscript::Program *p, uint32_t type,
+ const char * shaderText, uint32_t shaderLength);
+ virtual ~RsdShader();
+
+ bool createShader();
+
+ uint32_t getShaderID() const {return mShaderID;}
+
+ uint32_t getAttribCount() const {return mAttribCount;}
+ uint32_t getUniformCount() const {return mUniformCount;}
+ const android::String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
+ const android::String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
+ uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
+
+ android::String8 getGLSLInputString() const;
+
+ bool isValid() const {return mIsValid;}
+ void forceDirty() const {mDirty = true;}
+
+ bool loadShader(const android::renderscript::Context *);
+ void setup(const android::renderscript::Context *, RsdShaderCache *sc);
+
+protected:
+
+ const android::renderscript::Program *mRSProgram;
+ bool mIsValid;
+
+ // Applies to vertex and fragment shaders only
+ void appendUserConstants();
+ void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment);
+ void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
+ void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc);
+
+ void appendAttributes();
+ void appendTextures();
+
+ void initAttribAndUniformArray();
+
+ mutable bool mDirty;
+ android::String8 mShader;
+ android::String8 mUserShader;
+ uint32_t mShaderID;
+ uint32_t mType;
+
+ uint32_t mTextureCount;
+ uint32_t mAttribCount;
+ uint32_t mUniformCount;
+ android::String8 *mAttribNames;
+ android::String8 *mUniformNames;
+ uint32_t *mUniformArraySizes;
+
+ int32_t mTextureUniformIndexStart;
+
+ void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize );
+ void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize );
+ void initMemberVars();
+ void init();
+};
+
+#endif //ANDROID_RSD_SHADER_H
+
+
+
+
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
index e8d89c21cb77..18a8225f0847 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,25 +14,30 @@
* limitations under the License.
*/
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
+#include "rsdShader.h"
+#include "rsdShaderCache.h"
+
#include <GLES/gl.h>
#include <GLES2/gl2.h>
-#endif //ANDROID_RS_SERIALIZE
using namespace android;
using namespace android::renderscript;
-ShaderCache::ShaderCache() {
+RsdShaderCache::RsdShaderCache() {
mEntries.setCapacity(16);
+ mVertexDirty = true;
+ mFragmentDirty = true;
}
-ShaderCache::~ShaderCache() {
+RsdShaderCache::~RsdShaderCache() {
cleanupAll();
}
-void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+void RsdShaderCache::updateUniformArrayData(const Context *rsc, RsdShader *prog, uint32_t linkedID,
UniformData *data, const char* logTag,
UniformQueryData **uniformList, uint32_t uniListSize) {
@@ -54,14 +59,14 @@ void ShaderCache::updateUniformArrayData(Context *rsc, Program *prog, uint32_t l
}
}
-void ShaderCache::populateUniformData(Program *prog, uint32_t linkedID, UniformData *data) {
+void RsdShaderCache::populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data) {
for (uint32_t ct=0; ct < prog->getUniformCount(); ct++) {
data[ct].slot = glGetUniformLocation(linkedID, prog->getUniformName(ct));
data[ct].arraySize = prog->getUniformArraySize(ct);
}
}
-bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::hasArrayUniforms(RsdShader *vtx, RsdShader *frag) {
UniformData *data = mCurrent->vtxUniforms;
for (uint32_t ct=0; ct < vtx->getUniformCount(); ct++) {
if (data[ct].slot >= 0 && data[ct].arraySize > 1) {
@@ -77,7 +82,31 @@ bool ShaderCache::hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag) {
return false;
}
-bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag) {
+bool RsdShaderCache::setup(const Context *rsc) {
+ if (!mVertexDirty && !mFragmentDirty) {
+ return true;
+ }
+
+ if (!link(rsc)) {
+ return false;
+ }
+
+ if (mFragmentDirty) {
+ mFragment->setup(rsc, this);
+ mFragmentDirty = false;
+ }
+ if (mVertexDirty) {
+ mVertex->setup(rsc, this);
+ mVertexDirty = false;
+ }
+
+ return true;
+}
+
+bool RsdShaderCache::link(const Context *rsc) {
+
+ RsdShader *vtx = mVertex;
+ RsdShader *frag = mFragment;
if (!vtx->getShaderID()) {
vtx->loadShader(rsc);
}
@@ -89,7 +118,7 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag
if (!vtx->getShaderID() || !frag->getShaderID()) {
return false;
}
- //LOGV("ShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
+ //LOGV("rsdShaderCache lookup vtx %i, frag %i", vtx->getShaderID(), frag->getShaderID());
uint32_t entryCount = mEntries.size();
for (uint32_t ct = 0; ct < entryCount; ct ++) {
if ((mEntries[ct]->vtx == vtx->getShaderID()) &&
@@ -98,13 +127,13 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag
//LOGV("SC using program %i", mEntries[ct]->program);
glUseProgram(mEntries[ct]->program);
mCurrent = mEntries[ct];
- //LOGV("ShaderCache hit, using %i", ct);
- rsc->checkError("ShaderCache::lookup (hit)");
+ //LOGV("RsdShaderCache hit, using %i", ct);
+ rsc->checkError("RsdShaderCache::link (hit)");
return true;
}
}
- //LOGV("ShaderCache miss");
+ //LOGV("RsdShaderCache miss");
//LOGE("e0 %x", glGetError());
ProgramEntry *e = new ProgramEntry(vtx->getAttribCount(),
vtx->getUniformCount(),
@@ -120,12 +149,10 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag
//LOGE("e1 %x", glGetError());
glAttachShader(pgm, frag->getShaderID());
- if (!vtx->isUserProgram()) {
- glBindAttribLocation(pgm, 0, "ATTRIB_position");
- glBindAttribLocation(pgm, 1, "ATTRIB_color");
- glBindAttribLocation(pgm, 2, "ATTRIB_normal");
- glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
- }
+ glBindAttribLocation(pgm, 0, "ATTRIB_position");
+ glBindAttribLocation(pgm, 1, "ATTRIB_color");
+ glBindAttribLocation(pgm, 2, "ATTRIB_normal");
+ glBindAttribLocation(pgm, 3, "ATTRIB_texture0");
//LOGE("e2 %x", glGetError());
glLinkProgram(pgm);
@@ -203,11 +230,12 @@ bool ShaderCache::lookup(Context *rsc, ProgramVertex *vtx, ProgramFragment *frag
//LOGV("SC made program %i", e->program);
glUseProgram(e->program);
- rsc->checkError("ShaderCache::lookup (miss)");
+ rsc->checkError("RsdShaderCache::link (miss)");
+
return true;
}
-int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const {
+int32_t RsdShaderCache::vtxAttribSlot(const String8 &attrName) const {
for (uint32_t ct=0; ct < mCurrent->vtxAttrCount; ct++) {
if (attrName == mCurrent->vtxAttrs[ct].name) {
return mCurrent->vtxAttrs[ct].slot;
@@ -216,7 +244,7 @@ int32_t ShaderCache::vtxAttribSlot(const String8 &attrName) const {
return -1;
}
-void ShaderCache::cleanupVertex(uint32_t id) {
+void RsdShaderCache::cleanupVertex(uint32_t id) {
int32_t numEntries = (int32_t)mEntries.size();
for (int32_t ct = 0; ct < numEntries; ct ++) {
if (mEntries[ct]->vtx == id) {
@@ -230,7 +258,7 @@ void ShaderCache::cleanupVertex(uint32_t id) {
}
}
-void ShaderCache::cleanupFragment(uint32_t id) {
+void RsdShaderCache::cleanupFragment(uint32_t id) {
int32_t numEntries = (int32_t)mEntries.size();
for (int32_t ct = 0; ct < numEntries; ct ++) {
if (mEntries[ct]->frag == id) {
@@ -244,7 +272,7 @@ void ShaderCache::cleanupFragment(uint32_t id) {
}
}
-void ShaderCache::cleanupAll() {
+void RsdShaderCache::cleanupAll() {
for (uint32_t ct=0; ct < mEntries.size(); ct++) {
glDeleteProgram(mEntries[ct]->program);
free(mEntries[ct]);
diff --git a/libs/rs/rsShaderCache.h b/libs/rs/driver/rsdShaderCache.h
index 354036697e90..17ee3e83769f 100644
--- a/libs/rs/rsShaderCache.h
+++ b/libs/rs/driver/rsdShaderCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,38 +14,59 @@
* limitations under the License.
*/
-#ifndef ANDROID_SHADER_CACHE_H
-#define ANDROID_SHADER_CACHE_H
+#ifndef ANDROID_RSD_SHADER_CACHE_H
+#define ANDROID_RSD_SHADER_CACHE_H
-
-#include "rsObjectBase.h"
-#include "rsVertexArray.h"
-
-// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+class RsdShader;
+
+// ---------------------------------------------------------------------------
// An element is a group of Components that occupies one cell in a structure.
-class ShaderCache {
+class RsdShaderCache {
public:
- ShaderCache();
- virtual ~ShaderCache();
+ RsdShaderCache();
+ virtual ~RsdShaderCache();
+
+ void setActiveVertex(RsdShader *pv) {
+ mVertexDirty = true;
+ mVertex = pv;
+ }
- bool lookup(Context *rsc, ProgramVertex *, ProgramFragment *);
+ void setActiveFragment(RsdShader *pf) {
+ mFragmentDirty = true;
+ mFragment = pf;
+ }
+
+ bool setup(const android::renderscript::Context *rsc);
void cleanupVertex(uint32_t id);
void cleanupFragment(uint32_t id);
void cleanupAll();
- int32_t vtxAttribSlot(const String8 &attrName) const;
+ int32_t vtxAttribSlot(const android::String8 &attrName) const;
int32_t vtxUniformSlot(uint32_t a) const {return mCurrent->vtxUniforms[a].slot;}
uint32_t vtxUniformSize(uint32_t a) const {return mCurrent->vtxUniforms[a].arraySize;}
int32_t fragUniformSlot(uint32_t a) const {return mCurrent->fragUniforms[a].slot;}
uint32_t fragUniformSize(uint32_t a) const {return mCurrent->fragUniforms[a].arraySize;}
protected:
+ bool link(const android::renderscript::Context *rsc);
+ bool mFragmentDirty;
+ bool mVertexDirty;
+ RsdShader *mVertex;
+ RsdShader *mFragment;
+
struct UniformQueryData {
char *name;
uint32_t nameLength;
@@ -111,21 +132,19 @@ protected:
UniformData *vtxUniforms;
UniformData *fragUniforms;
};
- Vector<ProgramEntry*> mEntries;
+ android::Vector<ProgramEntry*> mEntries;
ProgramEntry *mCurrent;
- bool hasArrayUniforms(ProgramVertex *vtx, ProgramFragment *frag);
- void populateUniformData(Program *prog, uint32_t linkedID, UniformData *data);
- void updateUniformArrayData(Context *rsc, Program *prog, uint32_t linkedID,
+ bool hasArrayUniforms(RsdShader *vtx, RsdShader *frag);
+ void populateUniformData(RsdShader *prog, uint32_t linkedID, UniformData *data);
+ void updateUniformArrayData(const android::renderscript::Context *rsc,
+ RsdShader *prog, uint32_t linkedID,
UniformData *data, const char* logTag,
UniformQueryData **uniformList, uint32_t uniListSize);
};
-
-}
-}
-#endif //ANDROID_SHADER_CACHE_H
+#endif //ANDROID_RSD_SHADER_CACHE_H
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/driver/rsdVertexArray.cpp
index 354ee89f7c5b..d0a5a54b569f 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/driver/rsdVertexArray.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,28 +14,32 @@
* limitations under the License.
*/
-#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
+#include <rs_hal.h>
+#include <rsContext.h>
+
#include <GLES/gl.h>
#include <GLES2/gl2.h>
-#endif
+
+#include "rsdCore.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
using namespace android;
using namespace android::renderscript;
-VertexArray::VertexArray(const Attrib *attribs, uint32_t numAttribs) {
+RsdVertexArray::RsdVertexArray(const Attrib *attribs, uint32_t numAttribs) {
mAttribs = attribs;
mCount = numAttribs;
}
-VertexArray::~VertexArray() {
+RsdVertexArray::~RsdVertexArray() {
}
-VertexArray::Attrib::Attrib() {
+RsdVertexArray::Attrib::Attrib() {
clear();
}
-void VertexArray::Attrib::clear() {
+void RsdVertexArray::Attrib::clear() {
buffer = 0;
offset = 0;
type = 0;
@@ -46,7 +50,7 @@ void VertexArray::Attrib::clear() {
name.setTo("");
}
-void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
+void RsdVertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
bool normalized, uint32_t offset,
const char *name) {
clear();
@@ -58,7 +62,7 @@ void VertexArray::Attrib::set(uint32_t type, uint32_t size, uint32_t stride,
this->name.setTo(name);
}
-void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
+void RsdVertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
if (idx == 0) {
LOGV("Starting vertex attribute binding");
}
@@ -74,11 +78,15 @@ void VertexArray::logAttrib(uint32_t idx, uint32_t slot) const {
mAttribs[idx].offset);
}
-void VertexArray::setupGL2(const Context *rsc,
- class VertexArrayState *state,
- ShaderCache *sc) const {
- rsc->checkError("VertexArray::setupGL2 start");
+void RsdVertexArray::setupGL2(const Context *rsc) const {
+
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ RsdVertexArrayState *state = dc->gl.vertexArrayState;
+ RsdShaderCache *sc = dc->gl.shaderCache;
+
+ rsc->checkError("RsdVertexArray::setupGL2 start");
uint32_t maxAttrs = state->mAttrsEnabledSize;
+
for (uint32_t ct=1; ct < maxAttrs; ct++) {
if(state->mAttrsEnabled[ct]) {
glDisableVertexAttribArray(ct);
@@ -86,7 +94,7 @@ void VertexArray::setupGL2(const Context *rsc,
}
}
- rsc->checkError("VertexArray::setupGL2 disabled");
+ rsc->checkError("RsdVertexArray::setupGL2 disabled");
for (uint32_t ct=0; ct < mCount; ct++) {
int32_t slot = sc->vtxAttribSlot(mAttribs[ct].name);
if (rsc->props.mLogShadersAttr) {
@@ -105,22 +113,22 @@ void VertexArray::setupGL2(const Context *rsc,
mAttribs[ct].stride,
mAttribs[ct].ptr + mAttribs[ct].offset);
}
- rsc->checkError("VertexArray::setupGL2 done");
+ rsc->checkError("RsdVertexArray::setupGL2 done");
}
////////////////////////////////////////////
-VertexArrayState::VertexArrayState() {
+RsdVertexArrayState::RsdVertexArrayState() {
mAttrsEnabled = NULL;
mAttrsEnabledSize = 0;
}
-VertexArrayState::~VertexArrayState() {
+RsdVertexArrayState::~RsdVertexArrayState() {
if (mAttrsEnabled) {
delete[] mAttrsEnabled;
mAttrsEnabled = NULL;
}
}
-void VertexArrayState::init(Context *rsc) {
- mAttrsEnabledSize = rsc->getMaxVertexAttributes();
+void RsdVertexArrayState::init(uint32_t maxAttrs) {
+ mAttrsEnabledSize = maxAttrs;
mAttrsEnabled = new bool[mAttrsEnabledSize];
for (uint32_t ct = 0; ct < mAttrsEnabledSize; ct++) {
mAttrsEnabled[ct] = false;
diff --git a/libs/rs/rsVertexArray.h b/libs/rs/driver/rsdVertexArray.h
index 45d9e82ab108..925a6aebfb76 100644
--- a/libs/rs/rsVertexArray.h
+++ b/libs/rs/driver/rsdVertexArray.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-#ifndef ANDROID_VERTEX_ARRAY_H
-#define ANDROID_VERTEX_ARRAY_H
+#ifndef ANDROID_RSD_VERTEX_ARRAY_H
+#define ANDROID_RSD_VERTEX_ARRAY_H
-
-#include "rsObjectBase.h"
-
-// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-class ShaderCache;
+class Context;
+
+}
+}
+
+#include <utils/String8.h>
// An element is a group of Components that occupies one cell in a structure.
-class VertexArray {
+class RsdVertexArray {
public:
class Attrib {
public:
@@ -38,17 +39,17 @@ public:
uint32_t size;
uint32_t stride;
bool normalized;
- String8 name;
+ android::String8 name;
Attrib();
void clear();
void set(uint32_t type, uint32_t size, uint32_t stride, bool normalized, uint32_t offset, const char *name);
};
- VertexArray(const Attrib *attribs, uint32_t numAttribs);
- virtual ~VertexArray();
+ RsdVertexArray(const Attrib *attribs, uint32_t numAttribs);
+ virtual ~RsdVertexArray();
- void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
+ void setupGL2(const android::renderscript::Context *rsc) const;
void logAttrib(uint32_t idx, uint32_t slot) const;
protected:
@@ -61,20 +62,18 @@ protected:
};
-class VertexArrayState {
+class RsdVertexArrayState {
public:
- VertexArrayState();
- ~VertexArrayState();
- void init(Context *);
+ RsdVertexArrayState();
+ ~RsdVertexArrayState();
+ void init(uint32_t maxAttrs);
bool *mAttrsEnabled;
uint32_t mAttrsEnabledSize;
};
-}
-}
-#endif //ANDROID_VERTEX_ARRAY_H
+#endif //ANDROID_RSD_VERTEX_ARRAY_H
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 4321592ec7ab..e2e14f20ac58 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -215,15 +215,11 @@ void Context::timerPrint() {
}
bool Context::setupCheck() {
- if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) {
- LOGE("Context::setupCheck() 1 fail");
- return false;
- }
mFragmentStore->setup(this, &mStateFragmentStore);
- mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
+ mFragment->setupGL2(this, &mStateFragment);
mRaster->setup(this, &mStateRaster);
- mVertex->setupGL2(this, &mStateVertex, &mShaderCache);
+ mVertex->setupGL2(this, &mStateVertex);
mFBOCache.setupGL2(this);
return true;
}
@@ -274,17 +270,18 @@ void * Context::threadProc(void *vrsc) {
rsc->props.mLogVisual = getProp("debug.rs.visual");
if (!rsdHalInit(rsc, 0, 0)) {
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Failed initializing GL");
LOGE("Hal init failed");
return NULL;
}
rsc->mHal.funcs.setPriority(rsc, rsc->mThreadPriority);
- if (!rsc->initGLThread()) {
- rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL");
- return NULL;
- }
-
if (rsc->mIsGraphicsContext) {
+ if (!rsc->initGLThread()) {
+ rsc->setError(RS_ERROR_OUT_OF_MEMORY, "Failed initializing GL");
+ return NULL;
+ }
+
rsc->mStateRaster.init(rsc);
rsc->setProgramRaster(NULL);
rsc->mStateVertex.init(rsc);
@@ -295,7 +292,6 @@ void * Context::threadProc(void *vrsc) {
rsc->setProgramStore(NULL);
rsc->mStateFont.init(rsc);
rsc->setFont(NULL);
- rsc->mStateVertexArray.init(rsc);
}
rsc->mRunning = true;
@@ -356,7 +352,6 @@ void Context::destroyWorkerThreadResources() {
mStateFragment.deinit(this);
mStateFragmentStore.deinit(this);
mStateFont.deinit(this);
- mShaderCache.cleanupAll();
}
//LOGV("destroyWorkerThreadResources 2");
mExit = true;
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index df85a6bc9283..107f63926a56 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -37,9 +37,7 @@
#include "rsProgramStore.h"
#include "rsProgramRaster.h"
#include "rsProgramVertex.h"
-#include "rsShaderCache.h"
#include "rsFBOCache.h"
-#include "rsVertexArray.h"
#include "rsgApiStructs.h"
#include "rsLocklessFifo.h"
@@ -111,11 +109,9 @@ public:
ProgramStoreState mStateFragmentStore;
ProgramRasterState mStateRaster;
ProgramVertexState mStateVertex;
- VertexArrayState mStateVertexArray;
FontState mStateFont;
ScriptCState mScriptC;
- ShaderCache mShaderCache;
FBOCache mFBOCache;
void swapBuffers();
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index b7b85b68372a..5e47ddb17536 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -25,11 +25,6 @@
#include FT_FREETYPE_H
#include FT_BITMAP_H
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
using namespace android;
using namespace android::renderscript;
@@ -457,7 +452,7 @@ bool FontState::cacheBitmap(FT_Bitmap *bitmap, uint32_t *retOriginX, uint32_t *r
// This will dirty the texture and the shader so next time
// we draw it will upload the data
- mTextTexture->syncAll(mRSC, RS_ALLOCATION_USAGE_SCRIPT);
+ mTextTexture->deferredUploadToTexture(mRSC);
mFontShaderF->bindTexture(mRSC, 0, mTextTexture.get());
// Some debug code
@@ -568,7 +563,6 @@ void FontState::initVertexArrayBuffers() {
}
indexAlloc->deferredUploadToBufferObject(mRSC);
- mIndexBuffer.set(indexAlloc);
const Element *posElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 3);
const Element *texElem = Element::create(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 2);
@@ -585,7 +579,10 @@ void FontState::initVertexArrayBuffers() {
Allocation *vertexAlloc = new Allocation(mRSC, vertexDataType, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_VERTEX);
mTextMeshPtr = (float*)vertexAlloc->getPtr();
- mVertexArray.set(vertexAlloc);
+ mMesh.set(new Mesh(mRSC, 1, 1));
+ mMesh->setVertexBuffer(vertexAlloc, 0);
+ mMesh->setPrimitive(indexAlloc, RS_PRIMITIVE_TRIANGLE, 0);
+ mMesh->init();
}
// We don't want to allocate anything unless we actually draw text
@@ -625,18 +622,7 @@ void FontState::issueDrawCommand() {
return;
}
- float *vtx = (float*)mVertexArray->getPtr();
- float *tex = vtx + 3;
-
- VertexArray::Attrib attribs[2];
- attribs[0].set(GL_FLOAT, 3, 20, false, (uint32_t)vtx, "ATTRIB_position");
- attribs[1].set(GL_FLOAT, 2, 20, false, (uint32_t)tex, "ATTRIB_texture0");
- VertexArray va(attribs, 2);
- va.setupGL2(mRSC, &mRSC->mStateVertexArray, &mRSC->mShaderCache);
-
- mIndexBuffer->uploadCheck(mRSC);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->getBufferObjectID());
- glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, (uint16_t *)(0));
+ mMesh->renderPrimitiveRange(mRSC, 0, 0, mCurrentQuadIndex * 6);
}
void FontState::appendMeshQuad(float x1, float y1, float z1,
@@ -787,8 +773,7 @@ void FontState::deinit(Context *rsc) {
mFontShaderFConstant.clear();
- mIndexBuffer.clear();
- mVertexArray.clear();
+ mMesh.clear();
mFontShaderF.clear();
mFontSampler.clear();
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 91a5da90d067..d18c0d91566d 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -230,9 +230,7 @@ protected:
uint32_t mMaxNumberOfQuads;
void initVertexArrayBuffers();
- ObjectBaseRef<Allocation> mIndexBuffer;
- ObjectBaseRef<Allocation> mVertexArray;
-
+ ObjectBaseRef<Mesh> mMesh;
bool mInitialized;
diff --git a/libs/rs/rsMesh.cpp b/libs/rs/rsMesh.cpp
index e29c80028192..ed29063ab2e1 100644
--- a/libs/rs/rsMesh.cpp
+++ b/libs/rs/rsMesh.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -15,46 +15,53 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES2/gl2.h>
-#include <GLES/glext.h>
-#endif
using namespace android;
using namespace android::renderscript;
Mesh::Mesh(Context *rsc) : ObjectBase(rsc) {
- mPrimitives = NULL;
- mPrimitivesCount = 0;
- mVertexBuffers = NULL;
- mVertexBufferCount = 0;
-
-#ifndef ANDROID_RS_SERIALIZE
- mAttribs = NULL;
- mAttribAllocationIndex = NULL;
+ mHal.drv = NULL;
+ mHal.state.primitives = NULL;
+ mHal.state.primitivesCount = 0;
+ mHal.state.vertexBuffers = NULL;
+ mHal.state.vertexBuffersCount = 0;
+ mInitialized = false;
+}
- mAttribCount = 0;
-#endif
+Mesh::Mesh(Context *rsc,
+ uint32_t vertexBuffersCount,
+ uint32_t primitivesCount) : ObjectBase(rsc) {
+ mHal.drv = NULL;
+ mHal.state.primitivesCount = primitivesCount;
+ mHal.state.primitives = new Primitive_t *[mHal.state.primitivesCount];
+ for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+ mHal.state.primitives[i] = new Primitive_t;
+ }
+ mHal.state.vertexBuffersCount = vertexBuffersCount;
+ mHal.state.vertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount];
}
Mesh::~Mesh() {
- if (mVertexBuffers) {
- delete[] mVertexBuffers;
+#ifndef ANDROID_RS_SERIALIZE
+ mRSC->mHal.funcs.mesh.destroy(mRSC, this);
+#endif
+
+ if (mHal.state.vertexBuffers) {
+ delete[] mHal.state.vertexBuffers;
}
- if (mPrimitives) {
- for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
- delete mPrimitives[i];
+ if (mHal.state.primitives) {
+ for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
+ mHal.state.primitives[i]->mIndexBuffer.clear();
+ delete mHal.state.primitives[i];
}
- delete[] mPrimitives;
+ delete[] mHal.state.primitives;
}
+}
+void Mesh::init() {
#ifndef ANDROID_RS_SERIALIZE
- if (mAttribs) {
- delete[] mAttribs;
- delete[] mAttribAllocationIndex;
- }
+ mRSC->mHal.funcs.mesh.init(mRSC, this);
#endif
}
@@ -66,15 +73,15 @@ void Mesh::serialize(OStream *stream) const {
stream->addString(&name);
// Store number of vertex streams
- stream->addU32(mVertexBufferCount);
- for (uint32_t vCount = 0; vCount < mVertexBufferCount; vCount ++) {
- mVertexBuffers[vCount]->serialize(stream);
+ stream->addU32(mHal.state.vertexBuffersCount);
+ for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) {
+ mHal.state.vertexBuffers[vCount]->serialize(stream);
}
- stream->addU32(mPrimitivesCount);
+ stream->addU32(mHal.state.primitivesCount);
// Store the primitives
- for (uint32_t pCount = 0; pCount < mPrimitivesCount; pCount ++) {
- Primitive_t * prim = mPrimitives[pCount];
+ for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) {
+ Primitive_t * prim = mHal.state.primitives[pCount];
stream->addU8((uint8_t)prim->mPrimitive);
@@ -95,213 +102,119 @@ Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) {
return NULL;
}
- Mesh * mesh = new Mesh(rsc);
-
String8 name;
stream->loadString(&name);
- mesh->setName(name.string(), name.size());
- mesh->mVertexBufferCount = stream->loadU32();
- if (mesh->mVertexBufferCount) {
- mesh->mVertexBuffers = new ObjectBaseRef<Allocation>[mesh->mVertexBufferCount];
+ uint32_t vertexBuffersCount = stream->loadU32();
+ ObjectBaseRef<Allocation> *vertexBuffers = NULL;
+ if (vertexBuffersCount) {
+ vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount];
- for (uint32_t vCount = 0; vCount < mesh->mVertexBufferCount; vCount ++) {
+ for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
- mesh->mVertexBuffers[vCount].set(vertexAlloc);
+ vertexBuffers[vCount].set(vertexAlloc);
}
}
- mesh->mPrimitivesCount = stream->loadU32();
- if (mesh->mPrimitivesCount) {
- mesh->mPrimitives = new Primitive_t *[mesh->mPrimitivesCount];
+ uint32_t primitivesCount = stream->loadU32();
+ ObjectBaseRef<Allocation> *indexBuffers = NULL;
+ RsPrimitive *primitives = NULL;
+ if (primitivesCount) {
+ indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount];
+ primitives = new RsPrimitive[primitivesCount];
// load all primitives
- for (uint32_t pCount = 0; pCount < mesh->mPrimitivesCount; pCount ++) {
- Primitive_t * prim = new Primitive_t;
- mesh->mPrimitives[pCount] = prim;
-
- prim->mPrimitive = (RsPrimitive)stream->loadU8();
+ for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+ primitives[pCount] = (RsPrimitive)stream->loadU8();
// Check to see if the index buffer was stored
uint32_t isIndexPresent = stream->loadU32();
if (isIndexPresent) {
Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
- prim->mIndexBuffer.set(indexAlloc);
+ indexBuffers[pCount].set(indexAlloc);
}
}
}
-#ifndef ANDROID_RS_SERIALIZE
- mesh->updateGLPrimitives();
- mesh->initVertexAttribs();
- mesh->uploadAll(rsc);
-#endif
- return mesh;
-}
-
-#ifndef ANDROID_RS_SERIALIZE
-
-bool Mesh::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
- // Do not create attribs for padding
- if (elem->getFieldName(fieldIdx)[0] == '#') {
- return false;
- }
-
- // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
- // Filter rs types accordingly
- RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
- if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
- dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
- dt != RS_TYPE_SIGNED_16) {
- return false;
- }
-
- // Now make sure they are not arrays
- uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
- if (arraySize != 1) {
- return false;
+ Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount);
+ mesh->setName(name.string(), name.size());
+ for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
+ mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount);
}
-
- return true;
-}
-
-void Mesh::initVertexAttribs() {
- // Count the number of gl attrs to initialize
- mAttribCount = 0;
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- const Element *elem = mVertexBuffers[ct]->getType()->getElement();
- for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
- if (isValidGLComponent(elem, ct)) {
- mAttribCount ++;
- }
- }
+ for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
+ mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount);
}
- if (mAttribs) {
- delete [] mAttribs;
- delete [] mAttribAllocationIndex;
- mAttribs = NULL;
- mAttribAllocationIndex = NULL;
+ // Cleanup
+ if (vertexBuffersCount) {
+ delete[] vertexBuffers;
}
- if (!mAttribCount) {
- return;
+ if (primitivesCount) {
+ delete[] indexBuffers;
+ delete[] primitives;
}
- mAttribs = new VertexArray::Attrib[mAttribCount];
- mAttribAllocationIndex = new uint32_t[mAttribCount];
-
- uint32_t userNum = 0;
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- const Element *elem = mVertexBuffers[ct]->getType()->getElement();
- uint32_t stride = elem->getSizeBytes();
- for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
- const Component &c = elem->getField(fieldI)->getComponent();
-
- if (!isValidGLComponent(elem, fieldI)) {
- continue;
- }
-
- mAttribs[userNum].size = c.getVectorSize();
- mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
- mAttribs[userNum].type = c.getGLType();
- mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
- mAttribs[userNum].stride = stride;
- String8 tmp(RS_SHADER_ATTR);
- tmp.append(elem->getFieldName(fieldI));
- mAttribs[userNum].name.setTo(tmp.string());
-
- // Remember which allocation this attribute came from
- mAttribAllocationIndex[userNum] = ct;
- userNum ++;
- }
- }
+#ifndef ANDROID_RS_SERIALIZE
+ mesh->init();
+ mesh->uploadAll(rsc);
+#endif
+ return mesh;
}
+#ifndef ANDROID_RS_SERIALIZE
+
void Mesh::render(Context *rsc) const {
- for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
+ for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
renderPrimitive(rsc, ct);
}
}
void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
- if (primIndex >= mPrimitivesCount) {
+ if (primIndex >= mHal.state.primitivesCount) {
LOGE("Invalid primitive index");
return;
}
- Primitive_t *prim = mPrimitives[primIndex];
+ Primitive_t *prim = mHal.state.primitives[primIndex];
if (prim->mIndexBuffer.get()) {
renderPrimitiveRange(rsc, primIndex, 0, prim->mIndexBuffer->getType()->getDimX());
return;
}
- renderPrimitiveRange(rsc, primIndex, 0, mVertexBuffers[0]->getType()->getDimX());
+ renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX());
}
void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
- if (len < 1 || primIndex >= mPrimitivesCount || mAttribCount == 0) {
+ if (len < 1 || primIndex >= mHal.state.primitivesCount) {
LOGE("Invalid mesh or parameters");
return;
}
- rsc->checkError("Mesh::renderPrimitiveRange 1");
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- mVertexBuffers[ct]->uploadCheck(rsc);
+ for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+ mHal.state.vertexBuffers[ct]->uploadCheck(rsc);
}
- // update attributes with either buffer information or data ptr based on their current state
- for (uint32_t ct=0; ct < mAttribCount; ct++) {
- uint32_t allocIndex = mAttribAllocationIndex[ct];
- Allocation *alloc = mVertexBuffers[allocIndex].get();
- if (alloc->getIsBufferObject()) {
- mAttribs[ct].buffer = alloc->getBufferObjectID();
- mAttribs[ct].ptr = NULL;
- } else {
- mAttribs[ct].buffer = 0;
- mAttribs[ct].ptr = (const uint8_t*)alloc->getPtr();
- }
- }
-
- VertexArray va(mAttribs, mAttribCount);
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
- rsc->checkError("Mesh::renderPrimitiveRange 2");
- Primitive_t *prim = mPrimitives[primIndex];
+ Primitive_t *prim = mHal.state.primitives[primIndex];
if (prim->mIndexBuffer.get()) {
prim->mIndexBuffer->uploadCheck(rsc);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prim->mIndexBuffer->getBufferObjectID());
- glDrawElements(prim->mGLPrimitive, len, GL_UNSIGNED_SHORT, (uint16_t *)(start * 2));
- } else {
- glDrawArrays(prim->mGLPrimitive, start, len);
}
+ rsc->checkError("Mesh::renderPrimitiveRange upload check");
- rsc->checkError("Mesh::renderPrimitiveRange");
+ mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len);
+ rsc->checkError("Mesh::renderPrimitiveRange draw");
}
-
void Mesh::uploadAll(Context *rsc) {
- for (uint32_t ct = 0; ct < mVertexBufferCount; ct ++) {
- if (mVertexBuffers[ct].get()) {
- mVertexBuffers[ct]->deferredUploadToBufferObject(rsc);
+ for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) {
+ if (mHal.state.vertexBuffers[ct].get()) {
+ mHal.state.vertexBuffers[ct]->deferredUploadToBufferObject(rsc);
}
}
- for (uint32_t ct = 0; ct < mPrimitivesCount; ct ++) {
- if (mPrimitives[ct]->mIndexBuffer.get()) {
- mPrimitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
- }
- }
-}
-
-void Mesh::updateGLPrimitives() {
- for (uint32_t i = 0; i < mPrimitivesCount; i ++) {
- switch (mPrimitives[i]->mPrimitive) {
- case RS_PRIMITIVE_POINT: mPrimitives[i]->mGLPrimitive = GL_POINTS; break;
- case RS_PRIMITIVE_LINE: mPrimitives[i]->mGLPrimitive = GL_LINES; break;
- case RS_PRIMITIVE_LINE_STRIP: mPrimitives[i]->mGLPrimitive = GL_LINE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE: mPrimitives[i]->mGLPrimitive = GL_TRIANGLES; break;
- case RS_PRIMITIVE_TRIANGLE_STRIP: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_STRIP; break;
- case RS_PRIMITIVE_TRIANGLE_FAN: mPrimitives[i]->mGLPrimitive = GL_TRIANGLE_FAN; break;
+ for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
+ if (mHal.state.primitives[ct]->mIndexBuffer.get()) {
+ mHal.state.primitives[ct]->mIndexBuffer->deferredUploadToBufferObject(rsc);
}
}
}
@@ -312,8 +225,8 @@ void Mesh::computeBBox() {
uint32_t stride = 0;
uint32_t numVerts = 0;
// First we need to find the position ptr and stride
- for (uint32_t ct=0; ct < mVertexBufferCount; ct++) {
- const Type *bufferType = mVertexBuffers[ct]->getType();
+ for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
+ const Type *bufferType = mHal.state.vertexBuffers[ct]->getType();
const Element *bufferElem = bufferType->getElement();
for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) {
@@ -321,7 +234,7 @@ void Mesh::computeBBox() {
vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize();
stride = bufferElem->getSizeBytes() / sizeof(float);
uint32_t offset = bufferElem->getFieldOffsetBytes(ct);
- posPtr = (float*)((uint8_t*)mVertexBuffers[ct]->getPtr() + offset);
+ posPtr = (float*)((uint8_t*)mHal.state.vertexBuffers[ct]->getPtr() + offset);
numVerts = bufferType->getDimX();
break;
}
@@ -353,73 +266,62 @@ namespace android {
namespace renderscript {
RsMesh rsi_MeshCreate(Context *rsc, uint32_t vtxCount, uint32_t idxCount) {
- Mesh *sm = new Mesh(rsc);
+ Mesh *sm = new Mesh(rsc, vtxCount, idxCount);
sm->incUserRef();
- sm->mPrimitivesCount = idxCount;
- sm->mPrimitives = new Mesh::Primitive_t *[sm->mPrimitivesCount];
- for (uint32_t ct = 0; ct < idxCount; ct ++) {
- sm->mPrimitives[ct] = new Mesh::Primitive_t;
- }
-
- sm->mVertexBufferCount = vtxCount;
- sm->mVertexBuffers = new ObjectBaseRef<Allocation>[vtxCount];
-
return sm;
}
void rsi_MeshBindVertex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t slot) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(slot < sm->mVertexBufferCount);
+ rsAssert(slot < sm->mHal.state.vertexBuffersCount);
- sm->mVertexBuffers[slot].set((Allocation *)va);
+ sm->setVertexBuffer((Allocation *)va, slot);
}
void rsi_MeshBindIndex(Context *rsc, RsMesh mv, RsAllocation va, uint32_t primType, uint32_t slot) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(slot < sm->mPrimitivesCount);
+ rsAssert(slot < sm->mHal.state.primitivesCount);
- sm->mPrimitives[slot]->mIndexBuffer.set((Allocation *)va);
- sm->mPrimitives[slot]->mPrimitive = (RsPrimitive)primType;
- sm->updateGLPrimitives();
+ sm->setPrimitive((Allocation *)va, (RsPrimitive)primType, slot);
}
void rsi_MeshInitVertexAttribs(Context *rsc, RsMesh mv) {
Mesh *sm = static_cast<Mesh *>(mv);
- sm->initVertexAttribs();
+ sm->init();
}
}}
void rsaMeshGetVertexBufferCount(RsContext con, RsMesh mv, int32_t *numVtx) {
Mesh *sm = static_cast<Mesh *>(mv);
- *numVtx = sm->mVertexBufferCount;
+ *numVtx = sm->mHal.state.vertexBuffersCount;
}
void rsaMeshGetIndexCount(RsContext con, RsMesh mv, int32_t *numIdx) {
Mesh *sm = static_cast<Mesh *>(mv);
- *numIdx = sm->mPrimitivesCount;
+ *numIdx = sm->mHal.state.primitivesCount;
}
void rsaMeshGetVertices(RsContext con, RsMesh mv, RsAllocation *vtxData, uint32_t vtxDataCount) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(vtxDataCount == sm->mVertexBufferCount);
+ rsAssert(vtxDataCount == sm->mHal.state.vertexBuffersCount);
for (uint32_t ct = 0; ct < vtxDataCount; ct ++) {
- vtxData[ct] = sm->mVertexBuffers[ct].get();
- sm->mVertexBuffers[ct]->incUserRef();
+ vtxData[ct] = sm->mHal.state.vertexBuffers[ct].get();
+ sm->mHal.state.vertexBuffers[ct]->incUserRef();
}
}
void rsaMeshGetIndices(RsContext con, RsMesh mv, RsAllocation *va, uint32_t *primType, uint32_t idxDataCount) {
Mesh *sm = static_cast<Mesh *>(mv);
- rsAssert(idxDataCount == sm->mPrimitivesCount);
+ rsAssert(idxDataCount == sm->mHal.state.primitivesCount);
for (uint32_t ct = 0; ct < idxDataCount; ct ++) {
- va[ct] = sm->mPrimitives[ct]->mIndexBuffer.get();
- primType[ct] = sm->mPrimitives[ct]->mPrimitive;
- if (sm->mPrimitives[ct]->mIndexBuffer.get()) {
- sm->mPrimitives[ct]->mIndexBuffer->incUserRef();
+ va[ct] = sm->mHal.state.primitives[ct]->mIndexBuffer.get();
+ primType[ct] = sm->mHal.state.primitives[ct]->mPrimitive;
+ if (sm->mHal.state.primitives[ct]->mIndexBuffer.get()) {
+ sm->mHal.state.primitives[ct]->mIndexBuffer->incUserRef();
}
}
}
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 3e080e2aabb9..1e279f4d1320 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -29,57 +29,65 @@ namespace renderscript {
class Mesh : public ObjectBase {
public:
Mesh(Context *);
+ Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
~Mesh();
- // Contains vertex data
- // Position, normal, texcoord, etc could either be strided in one allocation
- // of provided separetely in multiple ones
- ObjectBaseRef<Allocation> *mVertexBuffers;
- uint32_t mVertexBufferCount;
-
// Either mIndexBuffer, mPrimitiveBuffer or both could have a NULL reference
// If both are null, mPrimitive only would be used to render the mesh
- struct Primitive_t
- {
+ struct Primitive_t {
ObjectBaseRef<Allocation> mIndexBuffer;
-
RsPrimitive mPrimitive;
- uint32_t mGLPrimitive;
};
+ // compatibility to not break the build
+ ObjectBaseRef<Allocation> *mVertexBuffers;
+ uint32_t mVertexBufferCount;
Primitive_t ** mPrimitives;
uint32_t mPrimitivesCount;
+ // end compatibility
virtual void serialize(OStream *stream) const;
virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
static Mesh *createFromStream(Context *rsc, IStream *stream);
+ void init();
+
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ // Contains vertex data
+ // Position, normal, texcoord, etc could either be strided in one allocation
+ // of provided separetely in multiple ones
+ ObjectBaseRef<Allocation> *vertexBuffers;
+ uint32_t vertexBuffersCount;
+
+ Primitive_t ** primitives;
+ uint32_t primitivesCount;
+ };
+ State state;
+ };
+ Hal mHal;
+
+ void setVertexBuffer(Allocation *vb, uint32_t index) {
+ mHal.state.vertexBuffers[index].set(vb);
+ }
+
+ void setPrimitive(Allocation *idx, RsPrimitive prim, uint32_t index) {
+ mHal.state.primitives[index]->mIndexBuffer.set(idx);
+ mHal.state.primitives[index]->mPrimitive = prim;
+ }
-#ifndef ANDROID_RS_SERIALIZE
void render(Context *) const;
void renderPrimitive(Context *, uint32_t primIndex) const;
void renderPrimitiveRange(Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
void uploadAll(Context *);
- void updateGLPrimitives();
-
-
// Bounding volumes
float mBBoxMin[3];
float mBBoxMax[3];
void computeBBox();
-
- void initVertexAttribs();
-
protected:
- bool isValidGLComponent(const Element *elem, uint32_t fieldIdx);
- // Attribues that allow us to map to GL
- VertexArray::Attrib *mAttribs;
- // This allows us to figure out which allocation the attribute
- // belongs to. In the event the allocation is uploaded to GL
- // buffer, it lets us properly map it
- uint32_t *mAttribAllocationIndex;
- uint32_t mAttribCount;
-#endif
+ bool mInitialized;
};
class MeshContext {
@@ -92,7 +100,7 @@ public:
}
}
-#endif //ANDROID_RS_TRIANGLE_MESH_H
+#endif //ANDROID_RS_MESH_H
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 4ef05bf4372f..28fa0617b99d 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -15,11 +15,6 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
#include "rsProgram.h"
using namespace android;
@@ -36,26 +31,22 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
initMemberVars();
for (uint32_t ct=0; ct < paramLength; ct+=2) {
if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
- mInputCount++;
- }
- if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
- mOutputCount++;
+ mHal.state.inputElementsCount++;
}
if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
- mConstantCount++;
+ mHal.state.constantsCount++;
}
if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
- mTextureCount++;
+ mHal.state.texturesCount++;
}
}
- mTextures = new ObjectBaseRef<Allocation>[mTextureCount];
- mSamplers = new ObjectBaseRef<Sampler>[mTextureCount];
- mTextureTargets = new RsTextureTarget[mTextureCount];
- mInputElements = new ObjectBaseRef<Element>[mInputCount];
- mOutputElements = new ObjectBaseRef<Element>[mOutputCount];
- mConstantTypes = new ObjectBaseRef<Type>[mConstantCount];
- mConstants = new ObjectBaseRef<Allocation>[mConstantCount];
+ mHal.state.textures = new ObjectBaseRef<Allocation>[mHal.state.texturesCount];
+ mHal.state.samplers = new ObjectBaseRef<Sampler>[mHal.state.texturesCount];
+ mHal.state.textureTargets = new RsTextureTarget[mHal.state.texturesCount];
+ mHal.state.inputElements = new ObjectBaseRef<Element>[mHal.state.inputElementsCount];
+ mHal.state.constantTypes = new ObjectBaseRef<Type>[mHal.state.constantsCount];
+ mHal.state.constants = new ObjectBaseRef<Allocation>[mHal.state.constantsCount];
uint32_t input = 0;
uint32_t output = 0;
@@ -63,16 +54,13 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
uint32_t texture = 0;
for (uint32_t ct=0; ct < paramLength; ct+=2) {
if (params[ct] == RS_PROGRAM_PARAM_INPUT) {
- mInputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
- }
- if (params[ct] == RS_PROGRAM_PARAM_OUTPUT) {
- mOutputElements[output++].set(reinterpret_cast<Element *>(params[ct+1]));
+ mHal.state.inputElements[input++].set(reinterpret_cast<Element *>(params[ct+1]));
}
if (params[ct] == RS_PROGRAM_PARAM_CONSTANT) {
- mConstantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
+ mHal.state.constantTypes[constant++].set(reinterpret_cast<Type *>(params[ct+1]));
}
if (params[ct] == RS_PROGRAM_PARAM_TEXTURE_TYPE) {
- mTextureTargets[texture++] = (RsTextureTarget)params[ct+1];
+ mHal.state.textureTargets[texture++] = (RsTextureTarget)params[ct+1];
}
}
mIsInternal = false;
@@ -84,88 +72,69 @@ Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
shaderLength -= internalTokenLen;
}
mUserShader.setTo(shaderText, shaderLength);
-
- initAttribAndUniformArray();
}
Program::~Program() {
- if (mRSC->props.mLogShaders) {
- LOGV("Program::~Program with shader id %u", mShaderID);
- }
- if (mShaderID) {
- glDeleteShader(mShaderID);
- }
-
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
+ for (uint32_t ct=0; ct < mHal.state.constantsCount; ct++) {
bindAllocation(NULL, NULL, ct);
}
- for (uint32_t ct=0; ct < mTextureCount; ct++) {
+ for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
bindTexture(NULL, ct, NULL);
bindSampler(NULL, ct, NULL);
}
- delete[] mTextures;
- delete[] mSamplers;
- delete[] mTextureTargets;
- delete[] mInputElements;
- delete[] mOutputElements;
- delete[] mConstantTypes;
- delete[] mConstants;
- delete[] mAttribNames;
- delete[] mUniformNames;
- delete[] mUniformArraySizes;
- mInputCount = 0;
- mOutputCount = 0;
- mConstantCount = 0;
+ delete[] mHal.state.textures;
+ delete[] mHal.state.samplers;
+ delete[] mHal.state.textureTargets;
+ delete[] mHal.state.inputElements;
+ delete[] mHal.state.constantTypes;
+ delete[] mHal.state.constants;
+ mHal.state.inputElementsCount = 0;
+ mHal.state.constantsCount = 0;
+ mHal.state.texturesCount = 0;
}
void Program::initMemberVars() {
mDirty = true;
- mShaderID = 0;
- mAttribCount = 0;
- mUniformCount = 0;
- mTextureCount = 0;
- mTextures = NULL;
- mSamplers = NULL;
- mTextureTargets = NULL;
- mInputElements = NULL;
- mOutputElements = NULL;
- mConstantTypes = NULL;
- mConstants = NULL;
- mAttribNames = NULL;
- mUniformNames = NULL;
- mUniformArraySizes = NULL;
- mInputCount = 0;
- mOutputCount = 0;
- mConstantCount = 0;
- mIsValid = false;
+ mHal.drv = NULL;
+ mHal.state.textures = NULL;
+ mHal.state.samplers = NULL;
+ mHal.state.textureTargets = NULL;
+ mHal.state.inputElements = NULL;
+ mHal.state.constantTypes = NULL;
+ mHal.state.constants = NULL;
+
+ mHal.state.inputElementsCount = 0;
+ mHal.state.constantsCount = 0;
+ mHal.state.texturesCount = 0;
+
mIsInternal = false;
}
void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) {
if (alloc != NULL) {
- if (slot >= mConstantCount) {
+ if (slot >= mHal.state.constantsCount) {
LOGE("Attempt to bind alloc at slot %u, on shader id %u, but const count is %u",
- slot, (uint32_t)this, mConstantCount);
+ slot, (uint32_t)this, mHal.state.constantsCount);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
return;
}
- if (!alloc->getType()->isEqual(mConstantTypes[slot].get())) {
+ if (!alloc->getType()->isEqual(mHal.state.constantTypes[slot].get())) {
LOGE("Attempt to bind alloc at slot %u, on shader id %u, but types mismatch",
slot, (uint32_t)this);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind allocation");
return;
}
}
- if (mConstants[slot].get() == alloc) {
+ if (mHal.state.constants[slot].get() == alloc) {
return;
}
- if (mConstants[slot].get()) {
- mConstants[slot].get()->removeProgramToDirty(this);
+ if (mHal.state.constants[slot].get()) {
+ mHal.state.constants[slot].get()->removeProgramToDirty(this);
}
- mConstants[slot].set(alloc);
+ mHal.state.constants[slot].set(alloc);
if (alloc) {
alloc->addProgramToDirty(this);
}
@@ -173,327 +142,38 @@ void Program::bindAllocation(Context *rsc, Allocation *alloc, uint32_t slot) {
}
void Program::bindTexture(Context *rsc, uint32_t slot, Allocation *a) {
- if (slot >= mTextureCount) {
- LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mTextureCount);
+ if (slot >= mHal.state.texturesCount) {
+ LOGE("Attempt to bind texture to slot %u but tex count is %u", slot, mHal.state.texturesCount);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind texture");
return;
}
- if (a && a->getType()->getDimFaces() && mTextureTargets[slot] != RS_TEXTURE_CUBE) {
+ if (a && a->getType()->getDimFaces() && mHal.state.textureTargets[slot] != RS_TEXTURE_CUBE) {
LOGE("Attempt to bind cubemap to slot %u but 2d texture needed", slot);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind cubemap to 2d texture slot");
return;
}
//LOGE("bindtex %i %p", slot, a);
- mTextures[slot].set(a);
+ mHal.state.textures[slot].set(a);
mDirty = true;
}
void Program::bindSampler(Context *rsc, uint32_t slot, Sampler *s) {
- if (slot >= mTextureCount) {
- LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mTextureCount);
+ if (slot >= mHal.state.texturesCount) {
+ LOGE("Attempt to bind sampler to slot %u but tex count is %u", slot, mHal.state.texturesCount);
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind sampler");
return;
}
- mSamplers[slot].set(s);
+ mHal.state.samplers[slot].set(s);
mDirty = true;
}
-String8 Program::getGLSLInputString() const {
- String8 s;
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- const Element *e = mInputElements[ct].get();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
-
- // Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
- case 1: s.append("attribute float ATTRIB_"); break;
- case 2: s.append("attribute vec2 ATTRIB_"); break;
- case 3: s.append("attribute vec3 ATTRIB_"); break;
- case 4: s.append("attribute vec4 ATTRIB_"); break;
- default:
- rsAssert(0);
- }
-
- s.append(e->getFieldName(field));
- s.append(";\n");
- }
- }
- return s;
-}
-
-String8 Program::getGLSLOutputString() const {
- return String8();
-}
-
-String8 Program::getGLSLConstantString() const {
- return String8();
-}
-
-void Program::createShader() {
-}
-
-bool Program::loadShader(Context *rsc, uint32_t type) {
- mShaderID = glCreateShader(type);
- rsAssert(mShaderID);
-
- if (rsc->props.mLogShaders) {
- LOGV("Loading shader type %x, ID %i", type, mShaderID);
- LOGV("%s", mShader.string());
- }
-
- if (mShaderID) {
- const char * ss = mShader.string();
- glShaderSource(mShaderID, 1, &ss, NULL);
- glCompileShader(mShaderID);
-
- GLint compiled = 0;
- glGetShaderiv(mShaderID, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- GLint infoLen = 0;
- glGetShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf) {
- glGetShaderInfoLog(mShaderID, infoLen, NULL, buf);
- LOGE("Could not compile shader \n%s\n", buf);
- free(buf);
- }
- glDeleteShader(mShaderID);
- mShaderID = 0;
- rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
- return false;
- }
- }
- }
-
- if (rsc->props.mLogShaders) {
- LOGV("--Shader load result %x ", glGetError());
- }
- mIsValid = true;
- return true;
-}
-
void Program::setShader(const char *txt, uint32_t len) {
mUserShader.setTo(txt, len);
}
-void Program::appendUserConstants() {
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- const Element *e = mConstantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
-
- // Cannot be complex
- rsAssert(!f->getFieldCount());
- if (f->getType() == RS_TYPE_MATRIX_4X4) {
- mShader.append("uniform mat4 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
- mShader.append("uniform mat3 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
- mShader.append("uniform mat2 UNI_");
- } else {
- switch (f->getComponent().getVectorSize()) {
- case 1: mShader.append("uniform float UNI_"); break;
- case 2: mShader.append("uniform vec2 UNI_"); break;
- case 3: mShader.append("uniform vec3 UNI_"); break;
- case 4: mShader.append("uniform vec4 UNI_"); break;
- default:
- rsAssert(0);
- }
- }
-
- mShader.append(fn);
- if (e->getFieldArraySize(field) > 1) {
- mShader.appendFormat("[%d]", e->getFieldArraySize(field));
- }
- mShader.append(";\n");
- }
- }
-}
-
-void Program::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
- uint32_t elementSize = field->getSizeBytes() / sizeof(float);
- for (uint32_t i = 0; i < arraySize; i ++) {
- if (arraySize > 1) {
- LOGV("Array Element [%u]", i);
- }
- if (dataType == RS_TYPE_MATRIX_4X4) {
- LOGV("Matrix4x4");
- LOGV("{%f, %f, %f, %f", fd[0], fd[4], fd[8], fd[12]);
- LOGV(" %f, %f, %f, %f", fd[1], fd[5], fd[9], fd[13]);
- LOGV(" %f, %f, %f, %f", fd[2], fd[6], fd[10], fd[14]);
- LOGV(" %f, %f, %f, %f}", fd[3], fd[7], fd[11], fd[15]);
- } else if (dataType == RS_TYPE_MATRIX_3X3) {
- LOGV("Matrix3x3");
- LOGV("{%f, %f, %f", fd[0], fd[3], fd[6]);
- LOGV(" %f, %f, %f", fd[1], fd[4], fd[7]);
- LOGV(" %f, %f, %f}", fd[2], fd[5], fd[8]);
- } else if (dataType == RS_TYPE_MATRIX_2X2) {
- LOGV("Matrix2x2");
- LOGV("{%f, %f", fd[0], fd[2]);
- LOGV(" %f, %f}", fd[1], fd[3]);
- } else {
- switch (field->getComponent().getVectorSize()) {
- case 1:
- LOGV("Uniform 1 = %f", fd[0]);
- break;
- case 2:
- LOGV("Uniform 2 = %f %f", fd[0], fd[1]);
- break;
- case 3:
- LOGV("Uniform 3 = %f %f %f", fd[0], fd[1], fd[2]);
- break;
- case 4:
- LOGV("Uniform 4 = %f %f %f %f", fd[0], fd[1], fd[2], fd[3]);
- break;
- default:
- rsAssert(0);
- }
- }
- LOGE("Element size %u data=%p", elementSize, fd);
- fd += elementSize;
- LOGE("New data=%p", fd);
- }
-}
-
-void Program::setUniform(Context *rsc, const Element *field, const float *fd,
- int32_t slot, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
- if (dataType == RS_TYPE_MATRIX_4X4) {
- glUniformMatrix4fv(slot, arraySize, GL_FALSE, fd);
- } else if (dataType == RS_TYPE_MATRIX_3X3) {
- glUniformMatrix3fv(slot, arraySize, GL_FALSE, fd);
- } else if (dataType == RS_TYPE_MATRIX_2X2) {
- glUniformMatrix2fv(slot, arraySize, GL_FALSE, fd);
- } else {
- switch (field->getComponent().getVectorSize()) {
- case 1:
- glUniform1fv(slot, arraySize, fd);
- break;
- case 2:
- glUniform2fv(slot, arraySize, fd);
- break;
- case 3:
- glUniform3fv(slot, arraySize, fd);
- break;
- case 4:
- glUniform4fv(slot, arraySize, fd);
- break;
- default:
- rsAssert(0);
- }
- }
-}
-
-void Program::setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment) {
- uint32_t uidx = 0;
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- Allocation *alloc = mConstants[ct].get();
- if (!alloc) {
- LOGE("Attempting to set constants on shader id %u, but alloc at slot %u is not set", (uint32_t)this, ct);
- rsc->setError(RS_ERROR_BAD_SHADER, "No constant allocation bound");
- continue;
- }
-
- const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
- const Element *e = mConstantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fieldName = e->getFieldName(field);
- // If this field is padding, skip it
- if (fieldName[0] == '#') {
- continue;
- }
-
- uint32_t offset = e->getFieldOffsetBytes(field);
- const float *fd = reinterpret_cast<const float *>(&data[offset]);
-
- int32_t slot = -1;
- uint32_t arraySize = 1;
- if (!isFragment) {
- slot = sc->vtxUniformSlot(uidx);
- arraySize = sc->vtxUniformSize(uidx);
- } else {
- slot = sc->fragUniformSlot(uidx);
- arraySize = sc->fragUniformSize(uidx);
- }
- if (rsc->props.mLogShadersUniforms) {
- LOGV("Uniform slot=%i, offset=%i, constant=%i, field=%i, uidx=%i, name=%s", slot, offset, ct, field, uidx, fieldName);
- }
- uidx ++;
- if (slot < 0) {
- continue;
- }
-
- if (rsc->props.mLogShadersUniforms) {
- logUniform(f, fd, arraySize);
- }
- setUniform(rsc, f, fd, slot, arraySize);
- }
- }
-}
-
-void Program::initAttribAndUniformArray() {
- mAttribCount = 0;
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- const Element *elem = mInputElements[ct].get();
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mAttribCount ++;
- }
- }
- }
-
- mUniformCount = 0;
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- const Element *elem = mConstantTypes[ct]->getElement();
-
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mUniformCount ++;
- }
- }
- }
- mUniformCount += mTextureCount;
-
- if (mAttribCount) {
- mAttribNames = new String8[mAttribCount];
- }
- if (mUniformCount) {
- mUniformNames = new String8[mUniformCount];
- mUniformArraySizes = new uint32_t[mUniformCount];
- }
-}
-
-void Program::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) {
- rsAssert(e->getFieldCount());
- for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
- const Element *ce = e->getField(ct);
- if (ce->getFieldCount()) {
- initAddUserElement(ce, names, arrayLengths, count, prefix);
- } else if (e->getFieldName(ct)[0] != '#') {
- String8 tmp(prefix);
- tmp.append(e->getFieldName(ct));
- names[*count].setTo(tmp.string());
- if (arrayLengths) {
- arrayLengths[*count] = e->getFieldArraySize(ct);
- }
- (*count)++;
- }
- }
-}
-
namespace android {
namespace renderscript {
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index c48464dadecc..bcf55196fbfa 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -23,7 +23,6 @@
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-class ShaderCache;
#define RS_SHADER_INTERNAL "//rs_shader_internal\n"
#define RS_SHADER_ATTR "ATTRIB_"
@@ -38,75 +37,53 @@ public:
virtual ~Program();
void bindAllocation(Context *, Allocation *, uint32_t slot);
- virtual void createShader();
bool isUserProgram() const {return !mIsInternal;}
void bindTexture(Context *, uint32_t slot, Allocation *);
void bindSampler(Context *, uint32_t slot, Sampler *);
- uint32_t getShaderID() const {return mShaderID;}
void setShader(const char *, uint32_t len);
- uint32_t getAttribCount() const {return mAttribCount;}
- uint32_t getUniformCount() const {return mUniformCount;}
- const String8 & getAttribName(uint32_t i) const {return mAttribNames[i];}
- const String8 & getUniformName(uint32_t i) const {return mUniformNames[i];}
- uint32_t getUniformArraySize(uint32_t i) const {return mUniformArraySizes[i];}
-
- String8 getGLSLInputString() const;
- String8 getGLSLOutputString() const;
- String8 getGLSLConstantString() const;
-
- bool isValid() const {return mIsValid;}
void forceDirty() const {mDirty = true;}
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ // The difference between Textures and Constants is how they are accessed
+ // Texture lookups go though a sampler which in effect converts normalized
+ // coordinates into type specific. Multiple samples may also be taken
+ // and filtered.
+ //
+ // Constants are strictly accessed by the shader code
+ ObjectBaseRef<Allocation> *textures;
+ RsTextureTarget *textureTargets;
+ uint32_t texturesCount;
+
+ ObjectBaseRef<Sampler> *samplers;
+ uint32_t samplersCount;
+
+ ObjectBaseRef<Allocation> *constants;
+ ObjectBaseRef<Type> *constantTypes;
+ uint32_t constantsCount;
+
+ ObjectBaseRef<Element> *inputElements;
+ uint32_t inputElementsCount;
+ };
+ State state;
+ };
+ Hal mHal;
+
protected:
- // Components not listed in "in" will be passed though
- // unless overwritten by components in out.
- ObjectBaseRef<Element> *mInputElements;
- ObjectBaseRef<Element> *mOutputElements;
- ObjectBaseRef<Type> *mConstantTypes;
- ObjectBaseRef<Allocation> *mConstants;
- uint32_t mInputCount;
- uint32_t mOutputCount;
- uint32_t mConstantCount;
- bool mIsValid;
bool mIsInternal;
- // Applies to vertex and fragment shaders only
- void appendUserConstants();
- void setupUserConstants(Context *rsc, ShaderCache *sc, bool isFragment);
- void initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
-
- void initAttribAndUniformArray();
-
mutable bool mDirty;
- String8 mShader;
String8 mUserShader;
- uint32_t mShaderID;
-
- uint32_t mTextureCount;
- uint32_t mAttribCount;
- uint32_t mUniformCount;
- String8 *mAttribNames;
- String8 *mUniformNames;
- uint32_t *mUniformArraySizes;
void logUniform(const Element *field, const float *fd, uint32_t arraySize );
void setUniform(Context *rsc, const Element *field, const float *fd, int32_t slot, uint32_t arraySize );
void initMemberVars();
-
- // The difference between Textures and Constants is how they are accessed
- // Texture lookups go though a sampler which in effect converts normalized
- // coordinates into type specific. Multiple samples may also be taken
- // and filtered.
- //
- // Constants are strictly accessed by programetic loads.
- ObjectBaseRef<Allocation> *mTextures;
- ObjectBaseRef<Sampler> *mSamplers;
- RsTextureTarget *mTextureTargets;
- bool loadShader(Context *, uint32_t type);
};
}
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index ff314b7f6429..39887ca3f43b 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -15,13 +15,6 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
#include "rsProgramFragment.h"
using namespace android;
@@ -31,19 +24,16 @@ ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText,
uint32_t shaderLength, const uint32_t * params,
uint32_t paramLength)
: Program(rsc, shaderText, shaderLength, params, paramLength) {
-
mConstantColor[0] = 1.f;
mConstantColor[1] = 1.f;
mConstantColor[2] = 1.f;
mConstantColor[3] = 1.f;
- init(rsc);
+ mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length());
}
ProgramFragment::~ProgramFragment() {
- if (mShaderID) {
- mRSC->mShaderCache.cleanupFragment(mShaderID);
- }
+ mRSC->mHal.funcs.fragment.destroy(mRSC, this);
}
void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b, float a) {
@@ -52,7 +42,7 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b,
rsc->setError(RS_ERROR_BAD_SHADER, "Cannot set fixed function emulation color on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
LOGE("Unable to set fixed function emulation color because allocation is missing");
rsc->setError(RS_ERROR_BAD_SHADER, "Unable to set fixed function emulation color because allocation is missing");
return;
@@ -61,11 +51,11 @@ void ProgramFragment::setConstantColor(Context *rsc, float r, float g, float b,
mConstantColor[1] = g;
mConstantColor[2] = b;
mConstantColor[3] = a;
- memcpy(mConstants[0]->getPtr(), mConstantColor, 4*sizeof(float));
+ memcpy(mHal.state.constants[0]->getPtr(), mConstantColor, 4*sizeof(float));
mDirty = true;
}
-void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, ShaderCache *sc) {
+void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state) {
//LOGE("sgl2 frag1 %x", glGetError());
if ((state->mLast.get() == this) && !mDirty) {
return;
@@ -74,94 +64,16 @@ void ProgramFragment::setupGL2(Context *rsc, ProgramFragmentState *state, Shader
rsc->checkError("ProgramFragment::setupGL2 start");
- rsc->checkError("ProgramFragment::setupGL2 begin uniforms");
- setupUserConstants(rsc, sc, true);
-
- uint32_t numTexturesToBind = mTextureCount;
- uint32_t numTexturesAvailable = rsc->getMaxFragmentTextures();
- if (numTexturesToBind >= numTexturesAvailable) {
- LOGE("Attempting to bind %u textures on shader id %u, but only %u are available",
- mTextureCount, (uint32_t)this, numTexturesAvailable);
- rsc->setError(RS_ERROR_BAD_SHADER, "Cannot bind more textuers than available");
- numTexturesToBind = numTexturesAvailable;
- }
-
- for (uint32_t ct=0; ct < numTexturesToBind; ct++) {
- glActiveTexture(GL_TEXTURE0 + ct);
- if (!mTextures[ct].get()) {
+ for (uint32_t ct=0; ct < mHal.state.texturesCount; ct++) {
+ if (!mHal.state.textures[ct].get()) {
LOGE("No texture bound for shader id %u, texture unit %u", (uint)this, ct);
rsc->setError(RS_ERROR_BAD_SHADER, "No texture bound");
continue;
}
-
- mTextures[ct]->uploadCheck(rsc);
- GLenum target = (GLenum)mTextures[ct]->getGLTarget();
- if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
- LOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
- rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
- }
- glBindTexture(target, mTextures[ct]->getTextureID());
- rsc->checkError("ProgramFragment::setupGL2 tex bind");
- if (mSamplers[ct].get()) {
- mSamplers[ct]->setupGL(rsc, mTextures[ct].get());
- } else {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- rsc->checkError("ProgramFragment::setupGL2 tex env");
- }
-
- glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
- rsc->checkError("ProgramFragment::setupGL2 uniforms");
- }
-
- glActiveTexture(GL_TEXTURE0);
- mDirty = false;
- rsc->checkError("ProgramFragment::setupGL2");
-}
-
-void ProgramFragment::loadShader(Context *rsc) {
- Program::loadShader(rsc, GL_FRAGMENT_SHADER);
-}
-
-void ProgramFragment::createShader() {
- if (mUserShader.length() > 1) {
- mShader.append("precision mediump float;\n");
- appendUserConstants();
- char buf[256];
- for (uint32_t ct=0; ct < mTextureCount; ct++) {
- if (mTextureTargets[ct] == RS_TEXTURE_2D) {
- snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
- } else {
- snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
- }
- mShader.append(buf);
- }
- mShader.append(mUserShader);
- } else {
- LOGE("ProgramFragment::createShader cannot create program, shader code not defined");
- rsAssert(0);
- }
-}
-
-void ProgramFragment::init(Context *rsc) {
- uint32_t uniformIndex = 0;
- if (mUserShader.size() > 0) {
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformIndex, RS_SHADER_UNI);
- }
- }
- mTextureUniformIndexStart = uniformIndex;
- char buf[256];
- for (uint32_t ct=0; ct < mTextureCount; ct++) {
- snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
- mUniformNames[uniformIndex].setTo(buf);
- mUniformArraySizes[uniformIndex] = 1;
- uniformIndex++;
+ mHal.state.textures[ct]->uploadCheck(rsc);
}
- createShader();
+ rsc->mHal.funcs.fragment.setActive(rsc, this);
}
void ProgramFragment::serialize(OStream *stream) const {
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index 3d2894690cb2..7520af0b6510 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -32,11 +32,8 @@ public:
uint32_t paramLength);
virtual ~ProgramFragment();
- virtual void setupGL2(Context *, ProgramFragmentState *, ShaderCache *sc);
+ virtual void setupGL2(Context *, ProgramFragmentState *);
- virtual void createShader();
- virtual void loadShader(Context *rsc);
- virtual void init(Context *rsc);
virtual void serialize(OStream *stream) const;
virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_FRAGMENT; }
static ProgramFragment *createFromStream(Context *rsc, IStream *stream);
diff --git a/libs/rs/rsProgramStore.h b/libs/rs/rsProgramStore.h
index bfe276d95748..88a06a8b0024 100644
--- a/libs/rs/rsProgramStore.h
+++ b/libs/rs/rsProgramStore.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -62,8 +62,6 @@ public:
RsDepthFunc depthFunc;
};
State state;
-
-
};
Hal mHal;
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index e407d3ac4781..dfd732f39def 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -15,13 +15,6 @@
*/
#include "rsContext.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#endif //ANDROID_RS_SERIALIZE
-
#include "rsProgramVertex.h"
using namespace android;
@@ -32,57 +25,14 @@ ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText,
uint32_t shaderLength, const uint32_t * params,
uint32_t paramLength)
: Program(rsc, shaderText, shaderLength, params, paramLength) {
- init(rsc);
+ mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length());
}
ProgramVertex::~ProgramVertex() {
- if (mShaderID) {
- mRSC->mShaderCache.cleanupVertex(mShaderID);
- }
-}
-
-void ProgramVertex::loadShader(Context *rsc) {
- Program::loadShader(rsc, GL_VERTEX_SHADER);
-}
-
-void ProgramVertex::createShader(Context *rsc) {
- if (mUserShader.length() > 1) {
-
- appendUserConstants();
-
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- const Element *e = mInputElements[ct].get();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
-
- // Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
- case 1: mShader.append("attribute float ATTRIB_"); break;
- case 2: mShader.append("attribute vec2 ATTRIB_"); break;
- case 3: mShader.append("attribute vec3 ATTRIB_"); break;
- case 4: mShader.append("attribute vec4 ATTRIB_"); break;
- default:
- rsAssert(0);
- }
-
- mShader.append(fn);
- mShader.append(";\n");
- }
- }
- mShader.append(mUserShader);
- } else {
- rsc->setError(RS_ERROR_FATAL_UNKNOWN,
- "ProgramFragment::createShader cannot create program, shader code not defined");
- }
+ mRSC->mHal.funcs.vertex.destroy(mRSC, this);
}
-void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc) {
+void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state) {
if ((state->mLast.get() == this) && !mDirty) {
return;
}
@@ -90,12 +40,12 @@ void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCach
rsc->checkError("ProgramVertex::setupGL2 start");
if (!isUserProgram()) {
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrices because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
Matrix4x4 mvp;
mvp.load(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
Matrix4x4 t;
@@ -106,10 +56,10 @@ void ProgramVertex::setupGL2(Context *rsc, ProgramVertexState *state, ShaderCach
}
}
- rsc->checkError("ProgramVertex::setupGL2 begin uniforms");
- setupUserConstants(rsc, sc, false);
-
state->mLast.set(this);
+
+ rsc->mHal.funcs.vertex.setActive(rsc, this);
+
rsc->checkError("ProgramVertex::setupGL2");
}
@@ -119,12 +69,12 @@ void ProgramVertex::setProjectionMatrix(Context *rsc, const rsc_Matrix *m) const
"Attempting to set fixed function emulation matrix projection on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrix projection because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
@@ -135,12 +85,12 @@ void ProgramVertex::setModelviewMatrix(Context *rsc, const rsc_Matrix *m) const
"Attempting to set fixed function emulation matrix modelview on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrix modelview because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
@@ -151,12 +101,12 @@ void ProgramVertex::setTextureMatrix(Context *rsc, const rsc_Matrix *m) const {
"Attempting to set fixed function emulation matrix texture on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to set fixed function emulation matrix texture because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(&f[RS_PROGRAM_VERTEX_TEXTURE_OFFSET], m, sizeof(rsc_Matrix));
mDirty = true;
}
@@ -167,12 +117,12 @@ void ProgramVertex::getProjectionMatrix(Context *rsc, rsc_Matrix *m) const {
"Attempting to get fixed function emulation matrix projection on user program");
return;
}
- if (mConstants[0].get() == NULL) {
+ if (mHal.state.constants[0].get() == NULL) {
rsc->setError(RS_ERROR_FATAL_UNKNOWN,
"Unable to get fixed function emulation matrix projection because allocation is missing");
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
memcpy(m, &f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET], sizeof(rsc_Matrix));
}
@@ -180,27 +130,13 @@ void ProgramVertex::transformToScreen(Context *rsc, float *v4out, const float *v
if (isUserProgram()) {
return;
}
- float *f = static_cast<float *>(mConstants[0]->getPtr());
+ float *f = static_cast<float *>(mHal.state.constants[0]->getPtr());
Matrix4x4 mvp;
mvp.loadMultiply((Matrix4x4 *)&f[RS_PROGRAM_VERTEX_MODELVIEW_OFFSET],
(Matrix4x4 *)&f[RS_PROGRAM_VERTEX_PROJECTION_OFFSET]);
mvp.vectorMultiply(v4out, v3in);
}
-void ProgramVertex::init(Context *rsc) {
- uint32_t attribCount = 0;
- uint32_t uniformCount = 0;
- if (mUserShader.size() > 0) {
- for (uint32_t ct=0; ct < mInputCount; ct++) {
- initAddUserElement(mInputElements[ct].get(), mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
- }
- for (uint32_t ct=0; ct < mConstantCount; ct++) {
- initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
- }
- }
- createShader(rsc);
-}
-
void ProgramVertex::serialize(OStream *stream) const {
}
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 2a5c863cd2e9..04224a7502f2 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -31,7 +31,7 @@ public:
const uint32_t * params, uint32_t paramLength);
virtual ~ProgramVertex();
- virtual void setupGL2(Context *rsc, ProgramVertexState *state, ShaderCache *sc);
+ virtual void setupGL2(Context *rsc, ProgramVertexState *state);
void setProjectionMatrix(Context *, const rsc_Matrix *) const;
void getProjectionMatrix(Context *, rsc_Matrix *) const;
@@ -40,10 +40,6 @@ public:
void transformToScreen(Context *, float *v4out, const float *v3in) const;
- virtual void createShader(Context *);
- virtual void loadShader(Context *);
- virtual void init(Context *);
-
virtual void serialize(OStream *stream) const;
virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_PROGRAM_VERTEX; }
static ProgramVertex *createFromStream(Context *rsc, IStream *stream);
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 71f1312d564a..ecda485442c2 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -21,6 +21,9 @@
#include "rsMatrix2x2.h"
#include "utils/Timers.h"
+#include "driver/rsdVertexArray.h"
+#include "driver/rsdShaderCache.h"
+#include "driver/rsdCore.h"
#define GL_GLEXT_PROTOTYPES
@@ -134,6 +137,11 @@ void rsrDrawQuadTexCoords(Context *rsc, Script *sc,
return;
}
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ if (!dc->gl.shaderCache->setup(rsc)) {
+ return;
+ }
+
//LOGE("Quad");
//LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
//LOGE("%4.2f, %4.2f, %4.2f", x2, y2, z2);
@@ -143,12 +151,12 @@ void rsrDrawQuadTexCoords(Context *rsc, Script *sc,
float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
- VertexArray::Attrib attribs[2];
+ RsdVertexArray::Attrib attribs[2];
attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position");
attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0");
- VertexArray va(attribs, 2);
- va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
+ RsdVertexArray va(attribs, 2);
+ va.setupGL2(rsc);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 90ae039da3e3..086db337093b 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -18,7 +18,6 @@
#define ANDROID_STRUCTURED_TYPE_H
#include "rsElement.h"
-#include "rsVertexArray.h"
// ---------------------------------------------------------------------------
namespace android {
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 4283d4a6ae00..d2f273bc3b41 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -32,6 +32,9 @@ class Script;
class ScriptC;
class ProgramStore;
class ProgramRaster;
+class ProgramVertex;
+class ProgramFragment;
+class Mesh;
typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName);
@@ -98,6 +101,25 @@ typedef struct {
void (*destroy)(const Context *rsc, const ProgramRaster *ps);
} raster;
+ struct {
+ bool (*init)(const Context *rsc, const ProgramVertex *pv,
+ const char* shader, uint32_t shaderLen);
+ void (*setActive)(const Context *rsc, const ProgramVertex *pv);
+ void (*destroy)(const Context *rsc, const ProgramVertex *pv);
+ } vertex;
+
+ struct {
+ bool (*init)(const Context *rsc, const ProgramFragment *pf,
+ const char* shader, uint32_t shaderLen);
+ void (*setActive)(const Context *rsc, const ProgramFragment *pf);
+ void (*destroy)(const Context *rsc, const ProgramFragment *pf);
+ } fragment;
+
+ struct {
+ bool (*init)(const Context *rsc, const Mesh *m);
+ void (*draw)(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len);
+ void (*destroy)(const Context *rsc, const Mesh *m);
+ } mesh;
} RsdHalFunctions;
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 239795d52055..1d8b9b571213 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -228,7 +228,7 @@ void printApiCpp(FILE *f) {
fprintf(f, ");\n");
} else {
fprintf(f, " ThreadIO *io = &((Context *)rsc)->mIO;\n");
- fprintf(f, " uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
+ fprintf(f, " const uint32_t size = sizeof(RS_CMD_%s);\n", api->name);
if (hasInlineDataPointers(api)) {
fprintf(f, " uint32_t dataSize = 0;\n");
for (ct2=0; ct2 < api->paramCount; ct2++) {
@@ -241,10 +241,15 @@ void printApiCpp(FILE *f) {
//fprintf(f, " LOGE(\"add command %s\\n\");\n", api->name);
if (hasInlineDataPointers(api)) {
- fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(dataSize + sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
+ fprintf(f, " RS_CMD_%s *cmd = NULL;\n", api->name);
+ fprintf(f, " if (dataSize < 1024) {;\n");
+ fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(dataSize + size));\n", api->name);
+ fprintf(f, " } else {\n");
+ fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(size));\n", api->name);
+ fprintf(f, " }\n");
fprintf(f, " uint8_t *payload = (uint8_t *)&cmd[1];\n");
} else {
- fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(sizeof(RS_CMD_%s)));\n", api->name, api->name, api->name);
+ fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(size));\n", api->name, api->name);
}
for (ct2=0; ct2 < api->paramCount; ct2++) {
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index dc223f96453a..4393504236e5 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -47,16 +47,16 @@ namespace android {
class NativeBuffer
: public EGLNativeBase<
- android_native_buffer_t,
+ ANativeWindowBuffer,
NativeBuffer,
LightRefBase<NativeBuffer> >
{
public:
NativeBuffer(int w, int h, int f, int u) : BASE() {
- android_native_buffer_t::width = w;
- android_native_buffer_t::height = h;
- android_native_buffer_t::format = f;
- android_native_buffer_t::usage = u;
+ ANativeWindowBuffer::width = w;
+ ANativeWindowBuffer::height = h;
+ ANativeWindowBuffer::format = f;
+ ANativeWindowBuffer::usage = u;
}
private:
friend class LightRefBase<NativeBuffer>;
@@ -201,7 +201,7 @@ int FramebufferNativeWindow::getCurrentBufferIndex() const
}
int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
- android_native_buffer_t** buffer)
+ ANativeWindowBuffer** buffer)
{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
@@ -229,7 +229,7 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
}
int FramebufferNativeWindow::lockBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer)
+ ANativeWindowBuffer* buffer)
{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
@@ -249,7 +249,7 @@ int FramebufferNativeWindow::lockBuffer(ANativeWindow* window,
}
int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
- android_native_buffer_t* buffer)
+ ANativeWindowBuffer* buffer)
{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
@@ -270,10 +270,10 @@ int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
return res;
}
-int FramebufferNativeWindow::query(ANativeWindow* window,
+int FramebufferNativeWindow::query(const ANativeWindow* window,
int what, int* value)
{
- FramebufferNativeWindow* self = getSelf(window);
+ const FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
switch (what) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 97312a6d4b29..54a3ffa5663c 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -33,7 +33,7 @@
namespace android {
// ===========================================================================
-// Buffer and implementation of android_native_buffer_t
+// Buffer and implementation of ANativeWindowBuffer
// ===========================================================================
GraphicBuffer::GraphicBuffer()
@@ -77,7 +77,7 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
handle = inHandle;
}
-GraphicBuffer::GraphicBuffer(android_native_buffer_t* buffer, bool keepOwnership)
+GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)
: BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mIndex(-1), mWrappedBuffer(buffer)
@@ -119,9 +119,9 @@ void GraphicBuffer::dumpAllocationsToSystemLog()
GraphicBufferAllocator::dumpToSystemLog();
}
-android_native_buffer_t* GraphicBuffer::getNativeBuffer() const
+ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
{
- return static_cast<android_native_buffer_t*>(
+ return static_cast<ANativeWindowBuffer*>(
const_cast<GraphicBuffer*>(this));
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 60085b5de83c..5f7f36fb1925 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -432,5 +432,12 @@ public class MediaMetadataRetriever
* This key retrieves the average bitrate (in bits/sec), if available.
*/
public static final int METADATA_KEY_BITRATE = 20;
+ /**
+ * This key retrieves the language code of text tracks, if available.
+ * If multiple text tracks present, the return value will look like:
+ * "eng:chi"
+ * @hide
+ */
+ public static final int METADATA_KEY_TIMED_TEXT_LANGUAGES = 21;
// Add more here...
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index b9141696d5e5..3f799cf4bed9 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1227,6 +1227,15 @@ public class MediaPlayer
*/
public native void attachAuxEffect(int effectId);
+ /* Do not change these values without updating their counterparts
+ * in include/media/mediaplayer.h!
+ */
+ /**
+ * Key used in setParameter method.
+ * Indicates the index of the timed text track to be enabled/disabled
+ */
+ private static final int KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX = 1000;
+
/**
* Sets the parameter indicated by key.
* @param key key indicates the parameter to be set.
@@ -1360,6 +1369,36 @@ public class MediaPlayer
private native final void native_finalize();
/**
+ * @param index The index of the text track to be turned on.
+ * @return true if the text track is enabled successfully.
+ * {@hide}
+ */
+ public boolean enableTimedTextTrackIndex(int index) {
+ if (index < 0) {
+ return false;
+ }
+ return setParameter(KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX, index);
+ }
+
+ /**
+ * Enables the first timed text track if any.
+ * @return true if the text track is enabled successfully
+ * {@hide}
+ */
+ public boolean enableTimedText() {
+ return enableTimedTextTrackIndex(0);
+ }
+
+ /**
+ * Disables timed text display.
+ * @return true if the text track is disabled successfully.
+ * {@hide}
+ */
+ public boolean disableTimedText() {
+ return setParameter(KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX, -1);
+ }
+
+ /**
* @param reply Parcel with audio/video duration info for battery
tracking usage
* @return The status code.
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 80cc94e758fa..790eaa3889d5 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -431,34 +431,8 @@ public class MediaScanner
mFileSize = fileSize;
if (!isDirectory) {
- // special case certain file names
- // I use regionMatches() instead of substring() below
- // to avoid memory allocation
- int lastSlash = path.lastIndexOf('/');
- if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
- if (!noMedia) {
- // ignore those ._* files created by MacOS
- if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
- noMedia = true;
- }
-
- // ignore album art files created by Windows Media Player:
- // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
- // and AlbumArt_{...}_Small.jpg
- if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
- if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
- path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
- noMedia = true;
- }
- int length = path.length() - lastSlash - 1;
- if ((length == 17 && path.regionMatches(
- true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
- (length == 10
- && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
- noMedia = true;
- }
- }
- }
+ if (!noMedia && isNoMediaFile(path)) {
+ noMedia = true;
}
mNoMedia = noMedia;
@@ -1231,6 +1205,40 @@ public class MediaScanner
}
}
+ private static boolean isNoMediaFile(String path) {
+ File file = new File(path);
+ if (file.isDirectory()) return false;
+
+ // special case certain file names
+ // I use regionMatches() instead of substring() below
+ // to avoid memory allocation
+ int lastSlash = path.lastIndexOf('/');
+ if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
+ // ignore those ._* files created by MacOS
+ if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
+ return true;
+ }
+
+ // ignore album art files created by Windows Media Player:
+ // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
+ // and AlbumArt_{...}_Small.jpg
+ if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
+ if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
+ path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
+ return true;
+ }
+ int length = path.length() - lastSlash - 1;
+ if ((length == 17 && path.regionMatches(
+ true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
+ (length == 10
+ && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public static boolean isNoMediaPath(String path) {
if (path == null) return false;
@@ -1252,7 +1260,7 @@ public class MediaScanner
}
offset = slashIndex;
}
- return false;
+ return isNoMediaFile(path);
}
public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 4e2217588f35..28c8642687d9 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -135,20 +135,21 @@ status_t MediaScanner::doProcessDirectory(
}
if (type == DT_REG || type == DT_DIR) {
if (type == DT_DIR) {
+ bool childNoMedia = noMedia;
// set noMedia flag on directories with a name that starts with '.'
// for example, the Mac ".Trashes" directory
if (name[0] == '.')
- noMedia = true;
+ childNoMedia = true;
// report the directory to the client
if (stat(path, &statbuf) == 0) {
- client.scanFile(path, statbuf.st_mtime, 0, true, noMedia);
+ client.scanFile(path, statbuf.st_mtime, 0, true, childNoMedia);
}
// and now process its contents
strcat(fileSpot, "/");
int err = doProcessDirectory(path, pathRemaining - nameLength - 1, client,
- noMedia, exceptionCheck, exceptionEnv);
+ childNoMedia, exceptionCheck, exceptionEnv);
if (err) {
// pass exceptions up - ignore other errors
if (exceptionCheck && exceptionCheck(exceptionEnv)) goto failure;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 01fbea13f538..c1687c4f95f9 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -26,6 +26,7 @@
#include <media/IMediaPlayerService.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
+#include <media/stagefright/AACWriter.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/VideoSourceDownSampler.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
@@ -872,15 +873,21 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
}
status_t StagefrightRecorder::startAACRecording() {
- CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADIF ||
- mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+ // FIXME:
+ // Add support for OUTPUT_FORMAT_AAC_ADIF
+ CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
CHECK(mAudioSource != AUDIO_SOURCE_CNT);
- CHECK(0 == "AACWriter is not implemented yet");
+ mWriter = new AACWriter(mOutputFd);
+ status_t status = startRawAudioRecording();
+ if (status != OK) {
+ mWriter.clear();
+ mWriter = NULL;
+ }
- return OK;
+ return status;
}
status_t StagefrightRecorder::startAMRRecording() {
@@ -902,6 +909,16 @@ status_t StagefrightRecorder::startAMRRecording() {
}
}
+ mWriter = new AMRWriter(mOutputFd);
+ status_t status = startRawAudioRecording();
+ if (status != OK) {
+ mWriter.clear();
+ mWriter = NULL;
+ }
+ return status;
+}
+
+status_t StagefrightRecorder::startRawAudioRecording() {
if (mAudioSource >= AUDIO_SOURCE_CNT) {
LOGE("Invalid audio source: %d", mAudioSource);
return BAD_VALUE;
@@ -917,7 +934,7 @@ status_t StagefrightRecorder::startAMRRecording() {
return UNKNOWN_ERROR;
}
- mWriter = new AMRWriter(mOutputFd);
+ CHECK(mWriter != 0);
mWriter->addSource(audioEncoder);
if (mMaxFileDurationUs != 0) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 3d463ea0a163..c3e6d65406c6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -69,6 +69,7 @@ private:
sp<Surface> mPreviewSurface;
sp<IMediaRecorderClient> mListener;
sp<MediaWriter> mWriter, mWriterAux;
+ int mOutputFd, mOutputFdAux;
sp<AudioSource> mAudioSourceNode;
audio_source_t mAudioSource;
@@ -104,7 +105,6 @@ private:
sp<CameraSourceTimeLapse> mCameraSourceTimeLapse;
String8 mParams;
- int mOutputFd, mOutputFdAux;
bool mIsMetaDataStoredInVideoBuffers;
MediaProfiles *mEncoderProfiles;
@@ -123,6 +123,7 @@ private:
status_t startMPEG4Recording();
status_t startAMRRecording();
status_t startAACRecording();
+ status_t startRawAudioRecording();
status_t startRTPRecording();
status_t startMPEG2TSRecording();
sp<MediaSource> createAudioSource();
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
new file mode 100644
index 000000000000..8413208b1ebe
--- /dev/null
+++ b/media/libstagefright/AACWriter.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2011 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_NDEBUG 0
+#define LOG_TAG "AACWriter"
+#include <utils/Log.h>
+
+#include <media/stagefright/AACWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+
+namespace android {
+
+AACWriter::AACWriter(const char *filename)
+ : mFd(-1),
+ mInitCheck(NO_INIT),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mChannelCount(-1),
+ mSampleRate(-1) {
+
+ LOGV("AACWriter Constructor");
+
+ mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
+ if (mFd >= 0) {
+ mInitCheck = OK;
+ }
+}
+
+AACWriter::AACWriter(int fd)
+ : mFd(dup(fd)),
+ mInitCheck(mFd < 0? NO_INIT: OK),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mChannelCount(-1),
+ mSampleRate(-1) {
+}
+
+AACWriter::~AACWriter() {
+ if (mStarted) {
+ stop();
+ }
+
+ if (mFd != -1) {
+ close(mFd);
+ mFd = -1;
+ }
+}
+
+status_t AACWriter::initCheck() const {
+ return mInitCheck;
+}
+
+static int writeInt8(int fd, uint8_t x) {
+ return ::write(fd, &x, 1);
+}
+
+
+status_t AACWriter::addSource(const sp<MediaSource> &source) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mSource != NULL) {
+ LOGE("AAC files only support a single track of audio.");
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC));
+ CHECK(meta->findInt32(kKeyChannelCount, &mChannelCount));
+ CHECK(meta->findInt32(kKeySampleRate, &mSampleRate));
+ CHECK(mChannelCount >= 1 && mChannelCount <= 2);
+
+ mSource = source;
+ return OK;
+}
+
+status_t AACWriter::start(MetaData *params) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mSource == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mStarted && mPaused) {
+ mPaused = false;
+ mResumed = true;
+ return OK;
+ } else if (mStarted) {
+ // Already started, does nothing
+ return OK;
+ }
+
+ mFrameDurationUs = (kSamplesPerFrame * 1000000LL + (mSampleRate >> 1))
+ / mSampleRate;
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mReachedEOS = false;
+ mDone = false;
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+ pthread_attr_destroy(&attr);
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t AACWriter::pause() {
+ if (!mStarted) {
+ return OK;
+ }
+ mPaused = true;
+ return OK;
+}
+
+status_t AACWriter::stop() {
+ if (!mStarted) {
+ return OK;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ status_t err = (status_t) dummy;
+ {
+ status_t status = mSource->stop();
+ if (err == OK &&
+ (status != OK && status != ERROR_END_OF_STREAM)) {
+ err = status;
+ }
+ }
+
+ mStarted = false;
+ return err;
+}
+
+bool AACWriter::exceedsFileSizeLimit() {
+ if (mMaxFileSizeLimitBytes == 0) {
+ return false;
+ }
+ return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool AACWriter::exceedsFileDurationLimit() {
+ if (mMaxFileDurationLimitUs == 0) {
+ return false;
+ }
+ return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *AACWriter::ThreadWrapper(void *me) {
+ return (void *) static_cast<AACWriter *>(me)->threadFunc();
+}
+
+/*
+* Returns an index into the sample rate table if the
+* given sample rate is found; otherwise, returns -1.
+*/
+static bool getSampleRateTableIndex(int sampleRate, uint8_t* tableIndex) {
+ static const int kSampleRateTable[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000, 11025, 8000
+ };
+ const int tableSize =
+ sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
+
+ *tableIndex = 0;
+ for (int index = 0; index < tableSize; ++index) {
+ if (sampleRate == kSampleRateTable[index]) {
+ LOGV("Sample rate: %d and index: %d",
+ sampleRate, index);
+ *tableIndex = index;
+ return true;
+ }
+ }
+
+ LOGE("Sampling rate %d bps is not supported", sampleRate);
+ return false;
+}
+
+/*
+ * ADTS (Audio data transport stream) header structure.
+ * It consists of 7 or 9 bytes (with or without CRC):
+ * 12 bits of syncword 0xFFF, all bits must be 1
+ * 1 bit of field ID. 0 for MPEG-4, and 1 for MPEG-2
+ * 2 bits of MPEG layer. If in MPEG-TS, set to 0
+ * 1 bit of protection absense. Set to 1 if no CRC.
+ * 2 bits of profile code. Set to 1 (The MPEG-4 Audio
+ * object type minus 1. We are using AAC-LC = 2)
+ * 4 bits of sampling frequency index code (15 is not allowed)
+ * 1 bit of private stream. Set to 0.
+ * 3 bits of channel configuration code. 0 resevered for inband PCM
+ * 1 bit of originality. Set to 0.
+ * 1 bit of home. Set to 0.
+ * 1 bit of copyrighted steam. Set to 0.
+ * 1 bit of copyright start. Set to 0.
+ * 13 bits of frame length. It included 7 ot 9 bytes header length.
+ * it is set to (protection absense? 7: 9) + size(AAC frame)
+ * 11 bits of buffer fullness. 0x7FF for VBR.
+ * 2 bits of frames count in one packet. Set to 0.
+ */
+status_t AACWriter::writeAdtsHeader(uint32_t frameLength) {
+ uint8_t data = 0xFF;
+ write(mFd, &data, 1);
+
+ const uint8_t kFieldId = 0;
+ const uint8_t kMpegLayer = 0;
+ const uint8_t kProtectionAbsense = 1; // 1: kAdtsHeaderLength = 7
+ data = 0xF0;
+ data |= (kFieldId << 3);
+ data |= (kMpegLayer << 1);
+ data |= kProtectionAbsense;
+ write(mFd, &data, 1);
+
+ const uint8_t kProfileCode = 1; // AAC-LC
+ uint8_t kSampleFreqIndex;
+ CHECK(getSampleRateTableIndex(mSampleRate, &kSampleFreqIndex));
+ const uint8_t kPrivateStream = 0;
+ const uint8_t kChannelConfigCode = mChannelCount;
+ data = (kProfileCode << 6);
+ data |= (kSampleFreqIndex << 2);
+ data |= (kPrivateStream << 1);
+ data |= (kChannelConfigCode >> 2);
+ write(mFd, &data, 1);
+
+ // 4 bits from originality to copyright start
+ const uint8_t kCopyright = 0;
+ const uint32_t kFrameLength = frameLength;
+ data = ((kChannelConfigCode & 3) << 6);
+ data |= (kCopyright << 2);
+ data |= ((kFrameLength & 0x1800) >> 11);
+ write(mFd, &data, 1);
+
+ data = ((kFrameLength & 0x07F8) >> 3);
+ write(mFd, &data, 1);
+
+ const uint32_t kBufferFullness = 0x7FF; // VBR
+ data = ((kFrameLength & 0x07) << 5);
+ data |= ((kBufferFullness & 0x07C0) >> 6);
+ write(mFd, &data, 1);
+
+ const uint8_t kFrameCount = 0;
+ data = ((kBufferFullness & 0x03F) << 2);
+ data |= kFrameCount;
+ write(mFd, &data, 1);
+
+ return OK;
+}
+
+status_t AACWriter::threadFunc() {
+ mEstimatedDurationUs = 0;
+ mEstimatedSizeBytes = 0;
+ int64_t previousPausedDurationUs = 0;
+ int64_t maxTimestampUs = 0;
+ status_t err = OK;
+
+ prctl(PR_SET_NAME, (unsigned long)"AACWriterThread", 0, 0, 0);
+
+ while (!mDone && err == OK) {
+ MediaBuffer *buffer;
+ err = mSource->read(&buffer);
+
+ if (err != OK) {
+ break;
+ }
+
+ if (mPaused) {
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+
+ mEstimatedSizeBytes += kAdtsHeaderLength + buffer->range_length();
+ if (exceedsFileSizeLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ break;
+ }
+
+ int32_t isCodecSpecific = 0;
+ if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecSpecific) && isCodecSpecific) {
+ LOGV("Drop codec specific info buffer");
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+
+ int64_t timestampUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
+ if (timestampUs > mEstimatedDurationUs) {
+ mEstimatedDurationUs = timestampUs;
+ }
+ if (mResumed) {
+ previousPausedDurationUs += (timestampUs - maxTimestampUs - mFrameDurationUs);
+ mResumed = false;
+ }
+ timestampUs -= previousPausedDurationUs;
+ LOGV("time stamp: %lld, previous paused duration: %lld",
+ timestampUs, previousPausedDurationUs);
+ if (timestampUs > maxTimestampUs) {
+ maxTimestampUs = timestampUs;
+ }
+
+ if (exceedsFileDurationLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+ break;
+ }
+
+ // Each output AAC audio frame to the file contains
+ // 1. an ADTS header, followed by
+ // 2. the compressed audio data.
+ ssize_t dataLength = buffer->range_length();
+ uint8_t *data = (uint8_t *)buffer->data() + buffer->range_offset();
+ if (writeAdtsHeader(kAdtsHeaderLength + dataLength) != OK ||
+ dataLength != write(mFd, data, dataLength)) {
+ err = ERROR_IO;
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ close(mFd);
+ mFd = -1;
+ mReachedEOS = true;
+ if (err == ERROR_END_OF_STREAM) {
+ return OK;
+ }
+ return err;
+}
+
+bool AACWriter::reachedEOS() {
+ return mReachedEOS;
+}
+
+} // namespace android
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9928f44459c2..e52f6d12cbfe 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -505,7 +505,7 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() {
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
- android_native_buffer_t *buf;
+ ANativeWindowBuffer *buf;
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
if (err != 0) {
LOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
@@ -574,7 +574,7 @@ status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) {
}
ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() {
- android_native_buffer_t *buf;
+ ANativeWindowBuffer *buf;
CHECK_EQ(mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf), 0);
for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 2f3e14109eaf..10ce00c97612 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -6,6 +6,7 @@ include frameworks/base/media/libstagefright/codecs/common/Config.mk
LOCAL_SRC_FILES:= \
ACodec.cpp \
AACExtractor.cpp \
+ AACWriter.cpp \
AMRExtractor.cpp \
AMRWriter.cpp \
AVIExtractor.cpp \
@@ -48,6 +49,7 @@ LOCAL_SRC_FILES:= \
ThrottledSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
+ TimedTextPlayer.cpp \
Utils.cpp \
VBRISeeker.cpp \
WAVExtractor.cpp \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 974efa7449fc..cccd0b7a5e5b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -28,6 +28,7 @@
#include "include/NuCachedSource2.h"
#include "include/ThrottledSource.h"
#include "include/MPEG2TSExtractor.h"
+#include "include/TimedTextPlayer.h"
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -185,7 +186,8 @@ AwesomePlayer::AwesomePlayer()
mExtractorFlags(0),
mVideoBuffer(NULL),
mDecryptHandle(NULL),
- mLastVideoTimeUs(-1) {
+ mLastVideoTimeUs(-1),
+ mTextPlayer(NULL) {
CHECK_EQ(mClient.connect(), (status_t)OK);
DataSource::RegisterDefaultSniffers();
@@ -381,10 +383,8 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
mFlags |= AUTO_LOOPING;
}
}
- }
-
- if (haveAudio && haveVideo) {
- break;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ addTextSource(extractor->getTrack(i));
}
}
@@ -469,6 +469,11 @@ void AwesomePlayer::reset_l() {
delete mAudioPlayer;
mAudioPlayer = NULL;
+ if (mTextPlayer != NULL) {
+ delete mTextPlayer;
+ mTextPlayer = NULL;
+ }
+
mVideoRenderer.clear();
if (mRTSPController != NULL) {
@@ -971,6 +976,11 @@ status_t AwesomePlayer::pause_l(bool at_eos) {
mFlags &= ~AUDIO_RUNNING;
}
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mTextPlayer->pause();
+ mFlags &= ~TEXT_RUNNING;
+ }
+
mFlags &= ~PLAYING;
if (mDecryptHandle != NULL) {
@@ -1119,6 +1129,32 @@ status_t AwesomePlayer::seekTo(int64_t timeUs) {
return OK;
}
+status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
+ if (mTextPlayer != NULL) {
+ if (index >= 0) { // to turn on a text track
+ status_t err = mTextPlayer->setTimedTextTrackIndex(index);
+ if (err != OK) {
+ return err;
+ }
+
+ mFlags |= TEXT_RUNNING;
+ mFlags |= TEXTPLAYER_STARTED;
+ return OK;
+ } else { // to turn off the text track display
+ if (mFlags & TEXT_RUNNING) {
+ mFlags &= ~TEXT_RUNNING;
+ }
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mFlags &= ~TEXTPLAYER_STARTED;
+ }
+
+ return mTextPlayer->setTimedTextTrackIndex(index);
+ }
+ } else {
+ return INVALID_OPERATION;
+ }
+}
+
// static
void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
@@ -1155,6 +1191,10 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
seekAudioIfNecessary_l();
+ if (mFlags & TEXTPLAYER_STARTED) {
+ mTextPlayer->seekTo(mSeekTimeUs);
+ }
+
if (!(mFlags & PLAYING)) {
LOGV("seeking while paused, sending SEEK_COMPLETE notification"
" immediately.");
@@ -1193,6 +1233,16 @@ void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
mAudioTrack = source;
}
+void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+ CHECK(source != NULL);
+
+ if (mTextPlayer == NULL) {
+ mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+ }
+
+ mTextPlayer->addTextSource(source);
+}
+
status_t AwesomePlayer::initAudioDecoder() {
sp<MetaData> meta = mAudioTrack->getFormat();
@@ -1472,6 +1522,11 @@ void AwesomePlayer::onVideoEvent() {
}
}
+ if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
+ mTextPlayer->resume();
+ mFlags |= TEXT_RUNNING;
+ }
+
TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
if (mFlags & FIRST_FRAME) {
@@ -1906,7 +1961,10 @@ void AwesomePlayer::postAudioSeekComplete() {
}
status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
- return OK;
+ if (key == KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX) {
+ return setTimedTextTrackIndex(request.readInt32());
+ }
+ return ERROR_UNSUPPORTED;
}
status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 8787214f2525..c79d02e6fc0c 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -19,6 +19,8 @@
#include "include/MPEG4Extractor.h"
#include "include/SampleTable.h"
+#include "include/ESDS.h"
+#include "include/TimedTextPlayer.h"
#include <arpa/inet.h>
@@ -29,7 +31,6 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include "include/ESDS.h"
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -832,6 +833,33 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
mLastTrack->meta->setInt64(
kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
+ uint8_t lang[2];
+ off64_t lang_offset;
+ if (version == 1) {
+ lang_offset = timescale_offset + 4 + 8;
+ } else if (version == 0) {
+ lang_offset = timescale_offset + 4 + 4;
+ } else {
+ return ERROR_IO;
+ }
+
+ if (mDataSource->readAt(lang_offset, &lang, sizeof(lang))
+ < (ssize_t)sizeof(lang)) {
+ return ERROR_IO;
+ }
+
+ // To get the ISO-639-2/T three character language code
+ // 1 bit pad followed by 3 5-bits characters. Each character
+ // is packed as the difference between its ASCII value and 0x60.
+ char lang_code[4];
+ lang_code[0] = ((lang[0] >> 2) & 0x1f) + 0x60;
+ lang_code[1] = ((lang[0] & 0x3) << 3 | (lang[1] >> 5)) + 0x60;
+ lang_code[2] = (lang[1] & 0x1f) + 0x60;
+ lang_code[3] = '\0';
+
+ mLastTrack->meta->setCString(
+ kKeyMediaLanguage, lang_code);
+
*offset += chunk_size;
break;
}
@@ -1295,6 +1323,14 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return parseDrmSINF(offset, data_offset);
}
+ case FOURCC('t', 'x', '3', 'g'):
+ {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
+
+ *offset += chunk_size;
+ break;
+ }
+
default:
{
*offset += chunk_size;
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 8ca6ee888b17..8cd08bc86a14 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -47,4 +47,6 @@ const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
+const char *MEDIA_MIMETYPE_TEXT_3GPP = "text/3gpp-tt";
+
} // namespace android
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index dc868852568a..81f2e47cab5c 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -450,6 +450,11 @@ ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) {
}
size_t avail = mCache->totalSize() - delta;
+
+ if (avail > size) {
+ avail = size;
+ }
+
mCache->copy(delta, data, avail);
return avail;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 06352f40ac77..78d13b210022 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1830,7 +1830,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
if (err != 0) {
LOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
@@ -1900,7 +1900,7 @@ status_t OMXCodec::cancelBufferToNativeWindow(BufferInfo *info) {
OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
// Dequeue the next buffer from the native window.
- android_native_buffer_t* buf;
+ ANativeWindowBuffer* buf;
int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);
if (err != 0) {
CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 7621f2ce8a42..4c3dc47f8f80 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -27,6 +27,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/MediaDefs.h>
namespace android {
@@ -429,6 +430,7 @@ void StagefrightMetadataRetriever::parseMetaData() {
// The overall duration is the duration of the longest track.
int64_t maxDurationUs = 0;
+ String8 timedTextLang;
for (size_t i = 0; i < numTracks; ++i) {
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
@@ -452,10 +454,22 @@ void StagefrightMetadataRetriever::parseMetaData() {
CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
+ const char *lang;
+ trackMeta->findCString(kKeyMediaLanguage, &lang);
+ timedTextLang.append(String8(lang));
+ timedTextLang.append(String8(":"));
}
}
}
+ // To save the language codes for all timed text tracks
+ // If multiple text tracks present, the format will look
+ // like "eng:chi"
+ if (!timedTextLang.isEmpty()) {
+ mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
+ }
+
// The duration value is a string representing the duration in ms.
sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
diff --git a/media/libstagefright/TimedTextPlayer.cpp b/media/libstagefright/TimedTextPlayer.cpp
new file mode 100644
index 000000000000..1ac22cb52215
--- /dev/null
+++ b/media/libstagefright/TimedTextPlayer.cpp
@@ -0,0 +1,252 @@
+ /*
+ * Copyright (C) 2011 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_NDEBUG 0
+#define LOG_TAG "TimedTextPlayer"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/Utils.h>
+#include "include/AwesomePlayer.h"
+#include "include/TimedTextPlayer.h"
+
+namespace android {
+
+struct TimedTextEvent : public TimedEventQueue::Event {
+ TimedTextEvent(
+ TimedTextPlayer *player,
+ void (TimedTextPlayer::*method)())
+ : mPlayer(player),
+ mMethod(method) {
+ }
+
+protected:
+ virtual ~TimedTextEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ (mPlayer->*mMethod)();
+ }
+
+private:
+ TimedTextPlayer *mPlayer;
+ void (TimedTextPlayer::*mMethod)();
+
+ TimedTextEvent(const TimedTextEvent &);
+ TimedTextEvent &operator=(const TimedTextEvent &);
+};
+
+TimedTextPlayer::TimedTextPlayer(
+ AwesomePlayer *observer,
+ const wp<MediaPlayerBase> &listener,
+ TimedEventQueue *queue)
+ : mSource(NULL),
+ mSeekTimeUs(0),
+ mStarted(false),
+ mTextEventPending(false),
+ mQueue(queue),
+ mListener(listener),
+ mObserver(observer),
+ mTextBuffer(NULL) {
+ mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent);
+}
+
+TimedTextPlayer::~TimedTextPlayer() {
+ if (mStarted) {
+ reset();
+ }
+
+ mTextTrackVector.clear();
+}
+
+status_t TimedTextPlayer::start(uint8_t index) {
+ CHECK(!mStarted);
+
+ if (index >= mTextTrackVector.size()) {
+ LOGE("Incorrect text track index");
+ return BAD_VALUE;
+ }
+
+ mSource = mTextTrackVector.itemAt(index);
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ int64_t positionUs;
+ mObserver->getPosition(&positionUs);
+ seekTo(positionUs);
+
+ postTextEvent();
+
+ mStarted = true;
+
+ return OK;
+}
+
+void TimedTextPlayer::pause() {
+ CHECK(mStarted);
+
+ cancelTextEvent();
+}
+
+void TimedTextPlayer::resume() {
+ CHECK(mStarted);
+
+ postTextEvent();
+}
+
+void TimedTextPlayer::reset() {
+ CHECK(mStarted);
+
+ // send an empty text to clear the screen
+ notifyListener(MEDIA_TIMED_TEXT);
+
+ cancelTextEvent();
+
+ mSeeking = false;
+ mStarted = false;
+
+ if (mTextBuffer != NULL) {
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+ }
+
+ if (mSource != NULL) {
+ mSource->stop();
+ mSource.clear();
+ mSource = NULL;
+ }
+}
+
+status_t TimedTextPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+
+ return OK;
+}
+
+status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) {
+ if (index >= (int)(mTextTrackVector.size())) {
+ return BAD_VALUE;
+ }
+
+ if (mStarted) {
+ reset();
+ }
+
+ if (index >= 0) {
+ return start(index);
+ }
+ return OK;
+}
+
+void TimedTextPlayer::onTextEvent() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (!mTextEventPending) {
+ return;
+ }
+ mTextEventPending = false;
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ mSeeking = false;
+
+ if (mTextBuffer != NULL) {
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+ }
+
+ notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
+ }
+
+ if (mTextBuffer != NULL) {
+ uint8_t *tmp = (uint8_t *)(mTextBuffer->data());
+ size_t len = (*tmp) << 8 | (*(tmp + 1));
+
+ notifyListener(MEDIA_TIMED_TEXT,
+ tmp + 2,
+ len);
+
+ mTextBuffer->release();
+ mTextBuffer = NULL;
+
+ }
+
+ if (mSource->read(&mTextBuffer, &options) != OK) {
+ return;
+ }
+
+ int64_t positionUs, timeUs;
+ mObserver->getPosition(&positionUs);
+ mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
+
+ //send the text now
+ if (timeUs <= positionUs + 100000ll) {
+ postTextEvent();
+ } else {
+ postTextEvent(timeUs - positionUs - 100000ll);
+ }
+}
+
+void TimedTextPlayer::postTextEvent(int64_t delayUs) {
+ if (mTextEventPending) {
+ return;
+ }
+
+ mTextEventPending = true;
+ mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void TimedTextPlayer::cancelTextEvent() {
+ mQueue->cancelEvent(mTextEvent->eventID());
+ mTextEventPending = false;
+}
+
+void TimedTextPlayer::addTextSource(sp<MediaSource> source) {
+ mTextTrackVector.add(source);
+}
+
+void TimedTextPlayer::notifyListener(
+ int msg, const void *data, size_t size) {
+ if (mListener != NULL) {
+ sp<MediaPlayerBase> listener = mListener.promote();
+
+ if (listener != NULL) {
+ if (size > 0) {
+ mData.freeData();
+ mData.write(data, size);
+
+ listener->sendEvent(msg, 0, 0, &mData);
+ } else { // send an empty timed text to clear the screen
+ listener->sendEvent(msg);
+ }
+ }
+ }
+}
+}
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 208431c670e3..d2e3eaaac373 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -234,6 +234,23 @@ status_t AACDecoder::read(
mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
CHECK(mNumDecodedBuffers > 0);
+
+ if (decoderErr != MP4AUDEC_SUCCESS) {
+ // If decoding fails this early, the fields in mConfig may
+ // not be valid and we cannot recover.
+
+ LOGE("Unable to decode aac content, decoder returned error %d",
+ decoderErr);
+
+ buffer->release();
+ buffer = NULL;
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ return ERROR_UNSUPPORTED;
+ }
+
if (mNumDecodedBuffers == 1) {
mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
// Check on the sampling rate to see whether it is changed.
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index e4ff128a507e..0bff52de9058 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -84,7 +84,7 @@ status_t AACEncoder::initCheck() {
params.sampleRate = mSampleRate;
params.bitRate = mBitRate;
params.nChannels = mChannels;
- params.adtsUsed = 0; // For MP4 file, don't use adts format$
+ params.adtsUsed = 0; // We add adts header in the file writer if needed.
if (VO_ERR_NONE != mApiHandle->SetParam(mEncoderHandle, VO_PID_AAC_ENCPARAM, &params)) {
LOGE("Failed to set AAC encoder parameters");
return UNKNOWN_ERROR;
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 31afc43fe86d..3b1347682ec4 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -108,7 +108,7 @@ SoftwareRenderer::~SoftwareRenderer() {
void SoftwareRenderer::render(
const void *data, size_t size, void *platformPrivate) {
- android_native_buffer_t *buf;
+ ANativeWindowBuffer *buf;
int err;
if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
LOGW("Surface::dequeueBuffer returned error %d", err);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 2c17d9216187..fd3ddf724c40 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -44,6 +44,8 @@ struct ARTSPController;
class DrmManagerClinet;
class DecryptHandle;
+class TimedTextPlayer;
+
struct AwesomeRenderer : public RefBase {
AwesomeRenderer() {}
@@ -99,36 +101,41 @@ struct AwesomePlayer {
void postAudioEOS(int64_t delayUs = 0ll);
void postAudioSeekComplete();
+ status_t setTimedTextTrackIndex(int32_t index);
+
private:
friend struct AwesomeEvent;
friend struct PreviewPlayer;
enum {
- PLAYING = 1,
- LOOPING = 2,
- FIRST_FRAME = 4,
- PREPARING = 8,
- PREPARED = 16,
- AT_EOS = 32,
- PREPARE_CANCELLED = 64,
- CACHE_UNDERRUN = 128,
- AUDIO_AT_EOS = 256,
- VIDEO_AT_EOS = 512,
- AUTO_LOOPING = 1024,
+ PLAYING = 0x01,
+ LOOPING = 0x02,
+ FIRST_FRAME = 0x04,
+ PREPARING = 0x08,
+ PREPARED = 0x10,
+ AT_EOS = 0x20,
+ PREPARE_CANCELLED = 0x40,
+ CACHE_UNDERRUN = 0x80,
+ AUDIO_AT_EOS = 0x0100,
+ VIDEO_AT_EOS = 0x0200,
+ AUTO_LOOPING = 0x0400,
// We are basically done preparing but are currently buffering
// sufficient data to begin playback and finish the preparation phase
// for good.
- PREPARING_CONNECTED = 2048,
+ PREPARING_CONNECTED = 0x0800,
// We're triggering a single video event to display the first frame
// after the seekpoint.
- SEEK_PREVIEW = 4096,
+ SEEK_PREVIEW = 0x1000,
- AUDIO_RUNNING = 8192,
- AUDIOPLAYER_STARTED = 16384,
+ AUDIO_RUNNING = 0x2000,
+ AUDIOPLAYER_STARTED = 0x4000,
- INCOGNITO = 32768,
+ INCOGNITO = 0x8000,
+
+ TEXT_RUNNING = 0x10000,
+ TEXTPLAYER_STARTED = 0x20000,
};
mutable Mutex mLock;
@@ -222,6 +229,7 @@ private:
sp<DecryptHandle> mDecryptHandle;
int64_t mLastVideoTimeUs;
+ TimedTextPlayer *mTextPlayer;
status_t setDataSource_l(
const char *uri,
@@ -244,6 +252,8 @@ private:
void setVideoSource(sp<MediaSource> source);
status_t initVideoDecoder(uint32_t flags = 0);
+ void addTextSource(sp<MediaSource> source);
+
void onStreamDone();
void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
diff --git a/media/libstagefright/include/TimedTextPlayer.h b/media/libstagefright/include/TimedTextPlayer.h
new file mode 100644
index 000000000000..ac41b4f06754
--- /dev/null
+++ b/media/libstagefright/include/TimedTextPlayer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 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 TIMEDTEXT_PLAYER_H_
+
+#define TIMEDTEXT_PLAYER_H_
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#include "include/TimedEventQueue.h"
+
+namespace android {
+
+class MediaSource;
+class AwesomePlayer;
+class MediaBuffer;
+
+class TimedTextPlayer {
+public:
+ TimedTextPlayer(AwesomePlayer *observer,
+ const wp<MediaPlayerBase> &listener,
+ TimedEventQueue *queue);
+
+ virtual ~TimedTextPlayer();
+
+ // index: the index of the text track which will
+ // be turned on
+ status_t start(uint8_t index);
+
+ void pause();
+
+ void resume();
+
+ status_t seekTo(int64_t time_us);
+
+ void addTextSource(sp<MediaSource> source);
+
+ status_t setTimedTextTrackIndex(int32_t index);
+
+private:
+ Mutex mLock;
+
+ sp<MediaSource> mSource;
+
+ bool mSeeking;
+ int64_t mSeekTimeUs;
+
+ bool mStarted;
+
+ sp<TimedEventQueue::Event> mTextEvent;
+ bool mTextEventPending;
+
+ TimedEventQueue *mQueue;
+
+ wp<MediaPlayerBase> mListener;
+ AwesomePlayer *mObserver;
+
+ MediaBuffer *mTextBuffer;
+ Parcel mData;
+
+ Vector<sp<MediaSource> > mTextTrackVector;
+
+ void reset();
+
+ void onTextEvent();
+ void postTextEvent(int64_t delayUs = -1);
+ void cancelTextEvent();
+
+ void notifyListener(
+ int msg, const void *data = NULL, size_t size = 0);
+
+ DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
+};
+
+} // namespace android
+
+#endif // TIMEDTEXT_PLAYER_H_
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 64266b8212ea..e1b9991983a5 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -591,7 +591,8 @@ static void addESDSFromAudioSpecificInfo(
// AudioSpecificInfo (with size prefix) follows
};
- CHECK(asiSize < 128);
+ // Make sure all sizes can be coded in a single byte.
+ CHECK(asiSize + 22 - 2 < 128);
size_t esdsSize = sizeof(kStaticESDS) + asiSize + 1;
uint8_t *esds = new uint8_t[esdsSize];
memcpy(esds, kStaticESDS, sizeof(kStaticESDS));
@@ -599,6 +600,11 @@ static void addESDSFromAudioSpecificInfo(
*ptr++ = asiSize;
memcpy(ptr, asi, asiSize);
+ // Increment by codecPrivateSize less 2 bytes that are accounted for
+ // already in lengths of 22/17
+ esds[1] += asiSize - 2;
+ esds[6] += asiSize - 2;
+
meta->setData(kKeyESDS, 0, esds, esdsSize);
delete[] esds;
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1ffcd563ff6e..1123e1673b64 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -225,7 +225,7 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGL
#ifndef EGL_ANDROID_image_native_buffer
#define EGL_ANDROID_image_native_buffer 1
-struct android_native_buffer_t;
+struct ANativeWindowBuffer;
#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
#endif
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index 8a7124d10304..f162d403403a 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -18,10 +18,10 @@ package com.google.android.gles_jni;
import javax.microedition.khronos.egl.*;
+import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
-import android.view.View;
public class EGLImpl implements EGL10 {
private EGLContextImpl mContext = new EGLContextImpl(-1);
@@ -71,19 +71,28 @@ public class EGLImpl implements EGL10 {
}
public EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list) {
- Surface sur;
+ Surface sur = null;
if (native_window instanceof SurfaceView) {
SurfaceView surfaceView = (SurfaceView)native_window;
sur = surfaceView.getHolder().getSurface();
} else if (native_window instanceof SurfaceHolder) {
SurfaceHolder holder = (SurfaceHolder)native_window;
sur = holder.getSurface();
+ }
+
+ int eglSurfaceId;
+ if (sur != null) {
+ eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
+ } else if (native_window instanceof SurfaceTexture) {
+ eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
+ ((SurfaceTexture) native_window).mSurfaceTexture, attrib_list);
} else {
throw new java.lang.UnsupportedOperationException(
"eglCreateWindowSurface() can only be called with an instance of " +
- "SurfaceView or SurfaceHolder at the moment, this will be fixed later.");
+ "SurfaceView, SurfaceHolder or SurfaceTexture at the moment, " +
+ "this will be fixed later.");
}
- int eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
+
if (eglSurfaceId == 0) {
return EGL10.EGL_NO_SURFACE;
}
@@ -134,6 +143,7 @@ public class EGLImpl implements EGL10 {
private native int _eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
private native void _eglCreatePixmapSurface(EGLSurface sur, EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
private native int _eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
+ private native int _eglCreateWindowSurfaceTexture(EGLDisplay display, EGLConfig config, int native_window, int[] attrib_list);
private native int _eglGetDisplay(Object native_display);
private native int _eglGetCurrentContext();
private native int _eglGetCurrentDisplay();
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
index bbb82fc48a9c..022de09ddc7c 100644
--- a/opengl/libagl/TextureObjectManager.cpp
+++ b/opengl/libagl/TextureObjectManager.cpp
@@ -145,7 +145,7 @@ status_t EGLTextureObject::setSurface(GGLSurface const* s)
return NO_ERROR;
}
-status_t EGLTextureObject::setImage(android_native_buffer_t* native_buffer)
+status_t EGLTextureObject::setImage(ANativeWindowBuffer* native_buffer)
{
GGLSurface sur;
sur.version = sizeof(GGLSurface);
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
index 70e3bef6e774..de9e03eab852 100644
--- a/opengl/libagl/TextureObjectManager.h
+++ b/opengl/libagl/TextureObjectManager.h
@@ -48,7 +48,7 @@ public:
~EGLTextureObject();
status_t setSurface(GGLSurface const* s);
- status_t setImage(android_native_buffer_t* buffer);
+ status_t setImage(ANativeWindowBuffer* buffer);
void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; }
status_t reallocate(GLint level,
@@ -80,7 +80,7 @@ public:
GLint crop_rect[4];
GLint generate_mipmap;
GLint direct;
- android_native_buffer_t* buffer;
+ ANativeWindowBuffer* buffer;
};
// ----------------------------------------------------------------------------
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 40fa1481494f..0d03361b0002 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -230,11 +230,11 @@ struct egl_window_surface_v2_t : public egl_surface_t
virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
private:
- status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
- status_t unlock(android_native_buffer_t* buf);
+ status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
+ status_t unlock(ANativeWindowBuffer* buf);
ANativeWindow* nativeWindow;
- android_native_buffer_t* buffer;
- android_native_buffer_t* previousBuffer;
+ ANativeWindowBuffer* buffer;
+ ANativeWindowBuffer* previousBuffer;
gralloc_module_t const* module;
int width;
int height;
@@ -322,8 +322,8 @@ private:
};
void copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
const Region& clip);
Rect dirtyRegion;
@@ -415,7 +415,7 @@ void egl_window_surface_v2_t::disconnect()
}
status_t egl_window_surface_v2_t::lock(
- android_native_buffer_t* buf, int usage, void** vaddr)
+ ANativeWindowBuffer* buf, int usage, void** vaddr)
{
int err;
@@ -425,7 +425,7 @@ status_t egl_window_surface_v2_t::lock(
return err;
}
-status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
{
if (!buf) return BAD_VALUE;
int err = NO_ERROR;
@@ -436,11 +436,10 @@ status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
}
void egl_window_surface_v2_t::copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
const Region& clip)
{
- // FIXME: use copybit if possible
// NOTE: dst and src must be the same format
Region::const_iterator cur = clip.begin();
@@ -2004,12 +2003,12 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
switch (native_buffer->format) {
@@ -2035,12 +2034,12 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
native_buffer->common.decRef(&native_buffer->common);
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index eb9689551fec..8eb17c4355a8 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -126,7 +126,7 @@ void ogles_lock_textures(ogles_context_t* c)
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
if (c->rasterizer.state.texture[i].enable) {
texture_unit_t& u(c->textures.tmu[i]);
- android_native_buffer_t* native_buffer = u.texture->buffer;
+ ANativeWindowBuffer* native_buffer = u.texture->buffer;
if (native_buffer) {
c->rasterizer.procs.activeTexture(c, i);
hw_module_t const* pModule;
@@ -154,7 +154,7 @@ void ogles_unlock_textures(ogles_context_t* c)
for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
if (c->rasterizer.state.texture[i].enable) {
texture_unit_t& u(c->textures.tmu[i]);
- android_native_buffer_t* native_buffer = u.texture->buffer;
+ ANativeWindowBuffer* native_buffer = u.texture->buffer;
if (native_buffer) {
c->rasterizer.procs.activeTexture(c, i);
hw_module_t const* pModule;
@@ -1615,12 +1615,12 @@ void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
return;
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
- if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
@@ -1643,12 +1643,12 @@ void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
return;
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)image;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
- if (native_buffer->common.version != sizeof(android_native_buffer_t)) {
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
ogles_error(c, GL_INVALID_VALUE);
return;
}
diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp
index ba771c3fba33..0d02ce66bbc5 100644
--- a/opengl/libagl2/src/egl.cpp
+++ b/opengl/libagl2/src/egl.cpp
@@ -211,11 +211,11 @@ struct egl_window_surface_v2_t : public egl_surface_t {
virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
private:
- status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
- status_t unlock(android_native_buffer_t* buf);
+ status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
+ status_t unlock(ANativeWindowBuffer* buf);
ANativeWindow* nativeWindow;
- android_native_buffer_t* buffer;
- android_native_buffer_t* previousBuffer;
+ ANativeWindowBuffer* buffer;
+ ANativeWindowBuffer* previousBuffer;
gralloc_module_t const* module;
int width;
int height;
@@ -307,8 +307,8 @@ private:
};
void copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
const Region& clip);
Rect dirtyRegion;
@@ -407,7 +407,7 @@ void egl_window_surface_v2_t::disconnect()
}
status_t egl_window_surface_v2_t::lock(
- android_native_buffer_t* buf, int usage, void** vaddr)
+ ANativeWindowBuffer* buf, int usage, void** vaddr)
{
int err;
@@ -417,7 +417,7 @@ status_t egl_window_surface_v2_t::lock(
return err;
}
-status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
+status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
{
if (!buf) return BAD_VALUE;
int err = NO_ERROR;
@@ -428,11 +428,10 @@ status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
}
void egl_window_surface_v2_t::copyBlt(
- android_native_buffer_t* dst, void* dst_vaddr,
- android_native_buffer_t* src, void const* src_vaddr,
+ ANativeWindowBuffer* dst, void* dst_vaddr,
+ ANativeWindowBuffer* src, void const* src_vaddr,
const Region& clip)
{
- // FIXME: use copybit if possible
// NOTE: dst and src must be the same format
Region::const_iterator cur = clip.begin();
@@ -2106,12 +2105,12 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
switch (native_buffer->format) {
@@ -2137,12 +2136,12 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
}
- android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
+ ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- if (native_buffer->common.version != sizeof(android_native_buffer_t))
+ if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
native_buffer->common.decRef(&native_buffer->common);
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
deleted file mode 100644
index a4be29879663..000000000000
--- a/packages/SystemUI/res/drawable-hdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
new file mode 100644
index 000000000000..87d194408536
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_close_on.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
new file mode 100644
index 000000000000..3b7c9c7c9da5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
new file mode 100644
index 000000000000..653acbbe0c13
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/status_bar_veto_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
new file mode 100644
index 000000000000..a93383326758
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png b/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
deleted file mode 100644
index eb7c1a4d7819..000000000000
--- a/packages/SystemUI/res/drawable-mdpi/status_bar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
new file mode 100644
index 000000000000..6c588f792569
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/statusbar_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
new file mode 100644
index 000000000000..eba44802440c
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<com.android.systemui.statusbar.phone.NavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ >
+
+ <LinearLayout android:id="@+id/rot0"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:paddingLeft="8dip"
+ android:paddingRight="8dip"
+ android:background="#FF000000"
+ android:orientation="horizontal"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/rot90"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/rot270"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:orientation="vertical"
+ android:visibility="gone"
+ >
+
+ <!-- navigation controls -->
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_back"
+ systemui:keyCode="4"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_home"
+ systemui:keyCode="3"
+ android:layout_weight="1"
+ />
+ <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_sysbar_menu"
+ systemui:keyCode="82"
+ android:layout_weight="1"
+ />
+ </LinearLayout>
+</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 88d973985d71..8e456b2d701f 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,24 +1,45 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="65sp"
- android:orientation="vertical"
+ android:layout_height="65dp"
>
+ <ImageButton
+ android:id="@+id/veto"
+ android:layout_width="48dp"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_alignParentRight="true"
+ android:src="@drawable/status_bar_veto"
+ android:scaleType="center"
+ android:background="@null"
+ android:paddingRight="8dp"
+ android:paddingLeft="8dp"
+ />
+
+ <ImageView
+ android:id="@+id/large_icon"
+ android:layout_width="@android:dimen/notification_large_icon_width"
+ android:layout_height="@android:dimen/notification_large_icon_height"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:scaleType="center"
+ />
+
<com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="64sp"
- android:background="@android:drawable/status_bar_item_background"
- android:focusable="true"
- android:clickable="true"
- android:paddingRight="6sp"
- >
- </com.android.systemui.statusbar.LatestItemView>
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/large_icon"
+ android:layout_toLeftOf="@id/veto"
+ android:focusable="true"
+ android:clickable="true"
+ />
<View
android:layout_width="match_parent"
- android:layout_height="1sp"
- android:background="@android:drawable/divider_horizontal_bright"
+ android:layout_height="1dp"
+ android:layout_alignParentBottom="true"
+ android:background="@android:drawable/divider_horizontal_dark"
/>
-</LinearLayout>
-
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_tracking.xml b/packages/SystemUI/res/layout/status_bar_tracking.xml
index a0ddab56bb0c..baa45c542ca1 100644
--- a/packages/SystemUI/res/layout/status_bar_tracking.xml
+++ b/packages/SystemUI/res/layout/status_bar_tracking.xml
@@ -26,11 +26,12 @@
android:paddingRight="0px"
>
- <com.android.systemui.statusbar.phone.TrackingPatternView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:background="#ff000000"
+ />
<com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
android:layout_width="match_parent"
@@ -42,7 +43,7 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:scaleType="fitXY"
- android:src="@drawable/shade_handlebar"
+ android:src="@drawable/status_bar_close_on"
/>
</com.android.systemui.statusbar.phone.CloseDragHandle>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
new file mode 100644
index 000000000000..bcc8da1f8595
--- /dev/null
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2011, 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.
+*/
+-->
+<resources>
+ <!-- thickness (width) of the navigation bar on phones that require it -->
+ <dimen name="navigation_bar_size">42dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 964e69b025a6..934169307755 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -20,4 +20,5 @@
<drawable name="notification_number_text_color">#ffffffff</drawable>
<drawable name="notification_item_background_color">#ff000000</drawable>
<drawable name="ticker_background_color">#ff1d1d1d</drawable>
+ <drawable name="status_bar_background">#000000</drawable>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 88cd43c74da0..a2577cb738c1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -31,5 +31,7 @@
<!-- Width of scrollable area in recents -->
<dimen name="status_bar_recents_width">356dp</dimen>
+ <!-- thickness (height) of the navigation bar on phones that require it -->
+ <dimen name="navigation_bar_size">42dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
new file mode 100644
index 000000000000..ec169e558306
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 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.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Display;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.content.res.Configuration;
+
+import com.android.systemui.R;
+
+public class NavigationBarView extends LinearLayout {
+ final Display mDisplay;
+ View[] mRotatedViews = new View[4];
+
+ public NavigationBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mDisplay = ((WindowManager)context.getSystemService(
+ Context.WINDOW_SERVICE)).getDefaultDisplay();
+ }
+
+ public void onFinishInflate() {
+ mRotatedViews[Surface.ROTATION_0] =
+ mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
+
+ mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
+
+ mRotatedViews[Surface.ROTATION_270] = findViewById(R.id.rot270);
+ }
+
+ public void reorient() {
+ final int rot = mDisplay.getRotation();
+ for (int i=0; i<4; i++) {
+ mRotatedViews[i].setVisibility(View.GONE);
+ }
+ mRotatedViews[rot].setVisibility(View.VISIBLE);
+
+ android.util.Log.d("NavigationBarView", "reorient(): rot=" + mDisplay.getRotation());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 1e46246ab61b..b4adde6e8060 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -45,6 +45,7 @@ import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewGroup;
@@ -141,6 +142,9 @@ public class PhoneStatusBar extends StatusBar {
// for immersive activities
private View mIntruderAlertView;
+ // on-screen navigation buttons
+ private NavigationBarView mNavigationBarView;
+
// the tracker view
TrackingView mTrackingView;
WindowManager.LayoutParams mTrackingParams;
@@ -199,7 +203,9 @@ public class PhoneStatusBar extends StatusBar {
super.start();
- addIntruderView();
+ addNavigationBar();
+
+ //addIntruderView();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
@@ -223,6 +229,9 @@ public class PhoneStatusBar extends StatusBar {
mIntruderAlertView.setVisibility(View.GONE);
mIntruderAlertView.setClickable(true);
+ mNavigationBarView =
+ (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
+
PhoneStatusBarView sb = (PhoneStatusBarView)View.inflate(context,
R.layout.status_bar, null);
sb.mService = this;
@@ -292,6 +301,58 @@ public class PhoneStatusBar extends StatusBar {
return res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
}
+ // For small-screen devices (read: phones) that lack hardware navigation buttons
+ private void addNavigationBar() {
+ mNavigationBarView.reorient();
+ WindowManagerImpl.getDefault().addView(
+ mNavigationBarView, getNavigationBarLayoutParams());
+ }
+
+ private void repositionNavigationBar() {
+ mNavigationBarView.reorient();
+ WindowManagerImpl.getDefault().updateViewLayout(
+ mNavigationBarView, getNavigationBarLayoutParams());
+ }
+
+ private WindowManager.LayoutParams getNavigationBarLayoutParams() {
+ final int rotation = mDisplay.getRotation();
+ final boolean sideways =
+ (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
+
+ final Resources res = mContext.getResources();
+ final int size = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
+
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ sideways ? size : ViewGroup.LayoutParams.MATCH_PARENT,
+ sideways ? ViewGroup.LayoutParams.MATCH_PARENT : size,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ 0
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+
+ lp.setTitle("NavigationBar");
+ switch (rotation) {
+ case Surface.ROTATION_90:
+ // device has been turned 90deg counter-clockwise
+ lp.gravity = Gravity.RIGHT | Gravity.FILL_VERTICAL;
+ break;
+ case Surface.ROTATION_270:
+ // device has been turned 90deg clockwise
+ lp.gravity = Gravity.LEFT | Gravity.FILL_VERTICAL;
+ break;
+ default:
+ lp.gravity = Gravity.BOTTOM | Gravity.FILL_HORIZONTAL;
+ break;
+ }
+ lp.windowAnimations = 0;
+
+ return lp;
+ }
+
private void addIntruderView() {
final int height = getStatusBarHeight();
@@ -511,6 +572,38 @@ public class PhoneStatusBar extends StatusBar {
Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
+ // wire up the veto button
+ View vetoButton = row.findViewById(R.id.veto);
+ if (notification.isClearable()) {
+ final String _pkg = notification.pkg;
+ final String _tag = notification.tag;
+ final int _id = notification.id;
+ vetoButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ try {
+ mBarService.onNotificationClear(_pkg, _tag, _id);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+ }
+ });
+ } else {
+ if ((notification.notification.flags & Notification.FLAG_ONGOING_EVENT) == 0) {
+ vetoButton.setVisibility(View.INVISIBLE);
+ } else {
+ vetoButton.setVisibility(View.GONE);
+ }
+ }
+
+ // the large icon
+ ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
+ if (notification.notification.largeIcon != null) {
+ largeIcon.setImageBitmap(notification.notification.largeIcon);
+ } else {
+ largeIcon.getLayoutParams().width = 0;
+ largeIcon.setVisibility(View.INVISIBLE);
+ }
+
// bind the click event to the content area
ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
@@ -1497,6 +1590,7 @@ public class PhoneStatusBar extends StatusBar {
animateCollapse();
}
else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+ repositionNavigationBar();
updateResources();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
index 90c95685ecd9..9924faa0c8de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
@@ -77,7 +77,9 @@ public class HeightReceiver extends BroadcastReceiver {
if (plugged) {
final DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
- height = metrics.heightPixels - 720;
+ //Slog.i(TAG, "setPlugged: display metrics=" + metrics);
+ final int shortSide = Math.min(metrics.widthPixels, metrics.heightPixels);
+ height = shortSide - 720;
}
final int minHeight
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 27b7e1c87419..d9971093a78d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -28,17 +28,15 @@ import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
-import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.ListMenuPresenter;
import com.android.internal.view.menu.IconMenuPresenter;
+import com.android.internal.view.menu.ListMenuPresenter;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuDialogHelper;
-import com.android.internal.view.menu.MenuItemImpl;
-import com.android.internal.view.menu.MenuPopupHelper;
-import com.android.internal.view.menu.MenuView;
import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.MenuView;
import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
@@ -625,7 +623,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- private void checkCloseActionMenu(Menu menu) {
+ void checkCloseActionMenu(Menu menu) {
if (mClosingActionMenu) {
return;
}
@@ -882,7 +880,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
- mActionBar.openOverflowMenu();
+ mActionBar.showOverflowMenu();
}
}
} else {
@@ -1526,6 +1524,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
st.onRestoreInstanceState(icicles.get(curFeatureId));
+ invalidatePanelMenu(curFeatureId);
}
/*
@@ -1964,8 +1963,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
mContextMenu.clearAll();
}
- mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken());
- return mContextMenuHelper != null;
+ final MenuDialogHelper helper = mContextMenu.show(originalView,
+ originalView.getWindowToken());
+ if (helper != null) {
+ helper.setPresenterCallback(mContextMenuCallback);
+ }
+ mContextMenuHelper = helper;
+ return helper != null;
}
@Override
@@ -2591,11 +2595,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
final boolean splitActionBar = getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowSplitActionBar, false);
if (splitActionBar) {
- final ViewGroup splitView = (ViewGroup) findViewById(
- com.android.internal.R.id.lower_action_context_bar);
+ final ActionBarContainer splitView = (ActionBarContainer) findViewById(
+ com.android.internal.R.id.split_action_bar);
if (splitView != null) {
+ splitView.setVisibility(View.VISIBLE);
mActionBar.setSplitActionBar(splitActionBar);
mActionBar.setSplitView(splitView);
+
+ final ActionBarContextView cab = (ActionBarContextView) findViewById(
+ com.android.internal.R.id.action_context_bar);
+ cab.setSplitView(splitView);
} else {
Log.e(TAG, "Window style requested split action bar with " +
"incompatible window decor! Ignoring request.");
@@ -3107,9 +3116,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* The first time the menu is being shown after restoring, the
* Activity.onCreateOptionsMenu should be called. But, if it is the
* same instance then menu != null and we won't call that method.
- * So, clear this. Also clear any cached views.
+ * We clear any cached views here. The caller should invalidatePanelMenu.
*/
- menu = null;
createdPanelView = null;
shownPanelView = null;
decorView = null;
@@ -3168,7 +3176,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* <li> Calls back to the callback's onMenuItemSelected when an item is
* selected.
*/
- private final class DialogMenuCallback implements MenuBuilder.Callback {
+ private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback {
private int mFeatureId;
private MenuDialogHelper mSubMenuHelper;
@@ -3177,6 +3185,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ if (menu.getRootMenu() != menu) {
+ onCloseSubMenu(menu);
+ }
+
if (allMenusAreClosing) {
Callback callback = getCallback();
if (callback != null && !isDestroyed()) {
@@ -3195,7 +3207,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- public void onCloseSubMenu(SubMenuBuilder menu) {
+ public void onCloseSubMenu(MenuBuilder menu) {
Callback callback = getCallback();
if (callback != null && !isDestroyed()) {
callback.onPanelClosed(mFeatureId, menu.getRootMenu());
@@ -3211,7 +3223,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public void onMenuModeChange(MenuBuilder menu) {
}
- public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
// Set a simple callback for the submenu
subMenu.setCallback(this);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a37ccc7d0a7e..6632f3411540 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -111,6 +111,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_POINTER;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
import android.view.KeyCharacterMap.FallbackAction;
@@ -175,14 +176,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// responsible for power management when displayed.
static final int KEYGUARD_LAYER = 15;
static final int KEYGUARD_DIALOG_LAYER = 16;
+ // the navigation bar, if available, shows atop most things
+ static final int NAVIGATION_BAR_LAYER = 17;
// the drag layer: input for drag-and-drop is associated with this window,
// which sits above all other focusable windows
- static final int DRAG_LAYER = 17;
+ static final int DRAG_LAYER = 18;
// things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 18;
- static final int SECURE_SYSTEM_OVERLAY_LAYER = 19;
+ static final int SYSTEM_OVERLAY_LAYER = 19;
+ static final int SECURE_SYSTEM_OVERLAY_LAYER = 20;
// the (mouse) pointer layer
- static final int POINTER_LAYER = 20;
+ static final int POINTER_LAYER = 21;
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -228,6 +231,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mStatusBar = null;
boolean mStatusBarCanHide;
final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>();
+ WindowState mNavigationBar = null;
+
WindowState mKeyguard = null;
KeyguardViewMediator mKeyguardMediator;
GlobalActions mGlobalActions;
@@ -1037,6 +1042,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return DRAG_LAYER;
case TYPE_POINTER:
return POINTER_LAYER;
+ case TYPE_NAVIGATION_BAR:
+ return NAVIGATION_BAR_LAYER;
}
Log.e(TAG, "Unknown window type: " + type);
return APPLICATION_LAYER;
@@ -1214,6 +1221,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.bool.config_statusBarCanHide);
break;
+ case TYPE_NAVIGATION_BAR:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "PhoneWindowManager");
+ mNavigationBar = win;
+ if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
+ break;
case TYPE_STATUS_BAR_PANEL:
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR_SERVICE,
@@ -1240,9 +1254,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void removeWindowLw(WindowState win) {
if (mStatusBar == win) {
mStatusBar = null;
- }
- else if (mKeyguard == win) {
+ } else if (mKeyguard == win) {
mKeyguard = null;
+ } else if (mNavigationBar == win) {
+ mNavigationBar = null;
} else {
mStatusBarPanels.remove(win);
}
@@ -1609,17 +1624,48 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mDockBottom = mContentBottom = mCurBottom = displayHeight;
mDockLayer = 0x10000000;
+ // start with the current dock rect, which will be (0,0,displayWidth,displayHeight)
+ final Rect pf = mTmpParentFrame;
+ final Rect df = mTmpDisplayFrame;
+ final Rect vf = mTmpVisibleFrame;
+ pf.left = df.left = vf.left = mDockLeft;
+ pf.top = df.top = vf.top = mDockTop;
+ pf.right = df.right = vf.right = mDockRight;
+ pf.bottom = df.bottom = vf.bottom = mDockBottom;
+
// decide where the status bar goes ahead of time
if (mStatusBar != null) {
- final Rect pf = mTmpParentFrame;
- final Rect df = mTmpDisplayFrame;
- final Rect vf = mTmpVisibleFrame;
- pf.left = df.left = vf.left = 0;
- pf.top = df.top = vf.top = 0;
- pf.right = df.right = vf.right = displayWidth;
- pf.bottom = df.bottom = vf.bottom = displayHeight;
-
+ Rect navr = null;
+ if (mNavigationBar != null) {
+ mNavigationBar.computeFrameLw(pf, df, vf, vf);
+ if (mNavigationBar.isVisibleLw()) {
+ navr = mNavigationBar.getFrameLw();
+
+ if (navr.top == 0) {
+ // Navigation bar is vertical
+ if (mDockLeft == navr.left) {
+ mDockLeft = navr.right;
+ } else if (mDockRight == navr.right) {
+ mDockRight = navr.left;
+ }
+ } else {
+ // Navigation bar horizontal, at bottom
+ if (mDockBottom == navr.bottom) {
+ mDockBottom = navr.top;
+ }
+ }
+ }
+ }
+ if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr);
+
+ // apply navigation bar insets
+ pf.left = df.left = vf.left = mDockLeft;
+ pf.top = df.top = vf.top = mDockTop;
+ pf.right = df.right = vf.right = mDockRight;
+ pf.bottom = df.bottom = vf.bottom = mDockBottom;
+
mStatusBar.computeFrameLw(pf, df, vf, vf);
+
if (mStatusBar.isVisibleLw()) {
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
@@ -1630,14 +1676,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// status bar is visible.
if (mDockTop == r.top) mDockTop = r.bottom;
else if (mDockBottom == r.bottom) mDockBottom = r.top;
+
mContentTop = mCurTop = mDockTop;
mContentBottom = mCurBottom = mDockBottom;
- if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockTop=" + mDockTop
- + " mContentTop=" + mContentTop
- + " mCurTop=" + mCurTop
- + " mDockBottom=" + mDockBottom
- + " mContentBottom=" + mContentBottom
- + " mCurBottom=" + mCurBottom);
+ mContentLeft = mCurLeft = mDockLeft;
+ mContentRight = mCurRight = mDockRight;
+
+ if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
+ String.format(
+ "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
+ mDockLeft, mDockTop, mDockRight, mDockBottom,
+ mContentLeft, mContentTop, mContentRight, mContentBottom,
+ mCurLeft, mCurTop, mCurRight, mCurBottom));
} else {
// Status bar can't go away; the part of the screen it
// covers does not exist for anything behind it.
@@ -1647,12 +1697,32 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
mRestrictedScreenHeight -= (r.bottom-r.top);
}
+
+ if (navr != null) {
+ if (navr.top == 0) {
+ // Navigation bar is vertical
+ if (mRestrictedScreenLeft == navr.left) {
+ mRestrictedScreenLeft = navr.right;
+ mRestrictedScreenWidth -= (navr.right - navr.left);
+ } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) {
+ mRestrictedScreenWidth -= (navr.right - navr.left);
+ }
+ } else {
+ // Navigation bar horizontal, at bottom
+ if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) {
+ mRestrictedScreenHeight -= (navr.bottom-navr.top);
+ }
+ }
+ }
+
mContentTop = mCurTop = mDockTop = mRestrictedScreenTop;
mContentBottom = mCurBottom = mDockBottom
= mRestrictedScreenTop + mRestrictedScreenHeight;
- if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mRestrictedScreenTop="
- + mRestrictedScreenTop
- + " mRestrictedScreenHeight=" + mRestrictedScreenHeight);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: ("
+ + mRestrictedScreenLeft + ","
+ + mRestrictedScreenTop + ","
+ + (mRestrictedScreenLeft + mRestrictedScreenWidth) + ","
+ + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")");
}
}
}
@@ -1722,6 +1792,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final Rect cf = mTmpContentFrame;
final Rect vf = mTmpVisibleFrame;
+ final boolean hasNavBar = (mNavigationBar != null && mNavigationBar.isVisibleLw());
+
if (attrs.type == TYPE_INPUT_METHOD) {
pf.left = df.left = cf.left = vf.left = mDockLeft;
pf.top = df.top = cf.top = vf.top = mDockTop;
@@ -1735,6 +1807,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN");
// This is the case for a normal activity window: we want it
// to cover all of the screen space, and it can take care of
// moving its contents to account for screen decorations that
@@ -1744,15 +1819,26 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// frame is the same as the one we are attached to.
setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
} else {
- if (attrs.type == TYPE_STATUS_BAR_PANEL) {
+ if (attrs.type == TYPE_STATUS_BAR_PANEL
+ || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
// Status bar panels are the only windows who can go on top of
// the status bar. They are protected by the STATUS_BAR_SERVICE
// permission, so they have the same privileges as the status
// bar itself.
- pf.left = df.left = mUnrestrictedScreenLeft;
+ //
+ // However, they should still dodge the navigation bar if it exists. A
+ // straightforward way to do this is to only allow the status bar panels to
+ // extend to the extrema of the allowable region for the IME dock.
+
+ pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = mUnrestrictedScreenTop;
- pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.right = df.right = hasNavBar
+ ? mDockRight
+ : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = hasNavBar
+ ? mDockBottom
+ : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+
} else {
pf.left = df.left = mRestrictedScreenLeft;
pf.top = df.top = mRestrictedScreenTop;
@@ -1780,15 +1866,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
} else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN");
// A window that has requested to fill the entire screen just
// gets everything, period.
- if (attrs.type == TYPE_STATUS_BAR_PANEL) {
- pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
+ if (attrs.type == TYPE_STATUS_BAR_PANEL
+ || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
+ pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = cf.right
- = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = cf.bottom
- = mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+ pf.right = df.right = cf.right = hasNavBar
+ ? mDockRight
+ : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth;
+ pf.bottom = df.bottom = cf.bottom = hasNavBar
+ ? mDockBottom
+ : mUnrestrictedScreenTop+mUnrestrictedScreenHeight;
+
} else {
pf.left = df.left = cf.left = mRestrictedScreenLeft;
pf.top = df.top = cf.top = mRestrictedScreenTop;
@@ -1805,10 +1897,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
vf.set(cf);
}
} else if (attached != null) {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached);
// A child window should be placed inside of the same visible
// frame that its parent had.
setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
} else {
+ if (DEBUG_LAYOUT)
+ Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window");
// Otherwise, a normal window must be placed inside the content
// of all screen decorations.
pf.left = mContentLeft;
@@ -1844,6 +1940,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
+ ": sim=#" + Integer.toHexString(sim)
+ + " attach=" + attached + " type=" + attrs.type
+ + String.format(" flags=0x%08x", fl)
+ " pf=" + pf.toShortString() + " df=" + df.toShortString()
+ " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
@@ -2119,11 +2217,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
void initializeHdmiState() {
+ boolean plugged = false;
// watch for HDMI plug messages if the hdmi switch exists
if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi");
- boolean plugged = false;
final String filename = "/sys/class/switch/hdmi/state";
FileReader reader = null;
try {
@@ -2145,11 +2243,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
}
-
- // This dance forces the code in setHdmiPlugged to run.
- mHdmiPlugged = !plugged;
- setHdmiPlugged(!mHdmiPlugged);
}
+ // This dance forces the code in setHdmiPlugged to run.
+ // Always do this so the sticky intent is stuck (to false) if there is no hdmi.
+ mHdmiPlugged = !plugged;
+ setHdmiPlugged(!mHdmiPlugged);
}
/**
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 14f1e8b1dfc3..e35435ef5400 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -1,38 +1,5 @@
LOCAL_PATH:= $(call my-dir)
-# Set USE_CAMERA_STUB if you don't want to use the hardware camera.
-
-# force these builds to use camera stub only
-ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
- USE_CAMERA_STUB:=true
-endif
-
-ifeq ($(USE_CAMERA_STUB),)
- USE_CAMERA_STUB:=false
-endif
-
-ifeq ($(USE_CAMERA_STUB),true)
-#
-# libcamerastub
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- CameraHardwareStub.cpp \
- FakeCamera.cpp
-
-LOCAL_MODULE:= libcamerastub
-
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_CFLAGS += -DSINGLE_PROCESS
-endif
-
-LOCAL_SHARED_LIBRARIES:= libui
-
-include $(BUILD_STATIC_LIBRARY)
-endif # USE_CAMERA_STUB
-
#
# libcameraservice
#
@@ -49,18 +16,9 @@ LOCAL_SHARED_LIBRARIES:= \
libcutils \
libmedia \
libcamera_client \
- libgui
+ libgui \
+ libhardware
LOCAL_MODULE:= libcameraservice
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_CFLAGS += -DSINGLE_PROCESS
-endif
-
-ifeq ($(USE_CAMERA_STUB), true)
-LOCAL_STATIC_LIBRARIES += libcamerastub
-else
-LOCAL_SHARED_LIBRARIES += libcamera
-endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/CameraHardwareInterface.h
new file mode 100644
index 000000000000..f9fa30e47ddb
--- /dev/null
+++ b/services/camera/libcameraservice/CameraHardwareInterface.h
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2008 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_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_INTERFACE_H
+
+#include <binder/IMemory.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <utils/RefBase.h>
+#include <surfaceflinger/ISurface.h>
+#include <ui/android_native_buffer.h>
+#include <ui/GraphicBuffer.h>
+#include <camera/Camera.h>
+#include <camera/CameraParameters.h>
+#include <system/window.h>
+#include <hardware/camera.h>
+
+namespace android {
+
+typedef void (*notify_callback)(int32_t msgType,
+ int32_t ext1,
+ int32_t ext2,
+ void* user);
+
+typedef void (*data_callback)(int32_t msgType,
+ const sp<IMemory> &dataPtr,
+ void* user);
+
+typedef void (*data_callback_timestamp)(nsecs_t timestamp,
+ int32_t msgType,
+ const sp<IMemory> &dataPtr,
+ void *user);
+
+/**
+ * CameraHardwareInterface.h defines the interface to the
+ * camera hardware abstraction layer, used for setting and getting
+ * parameters, live previewing, and taking pictures.
+ *
+ * It is a referenced counted interface with RefBase as its base class.
+ * CameraService calls openCameraHardware() to retrieve a strong pointer to the
+ * instance of this interface and may be called multiple times. The
+ * following steps describe a typical sequence:
+ *
+ * -# After CameraService calls openCameraHardware(), getParameters() and
+ * setParameters() are used to initialize the camera instance.
+ * CameraService calls getPreviewHeap() to establish access to the
+ * preview heap so it can be registered with SurfaceFlinger for
+ * efficient display updating while in preview mode.
+ * -# startPreview() is called. The camera instance then periodically
+ * sends the message CAMERA_MSG_PREVIEW_FRAME (if enabled) each time
+ * a new preview frame is available. If data callback code needs to use
+ * this memory after returning, it must copy the data.
+ *
+ * Prior to taking a picture, CameraService calls autofocus(). When auto
+ * focusing has completed, the camera instance sends a CAMERA_MSG_FOCUS notification,
+ * which informs the application whether focusing was successful. The camera instance
+ * only sends this message once and it is up to the application to call autoFocus()
+ * again if refocusing is desired.
+ *
+ * CameraService calls takePicture() to request the camera instance take a
+ * picture. At this point, if a shutter, postview, raw, and/or compressed callback
+ * is desired, the corresponding message must be enabled. As with CAMERA_MSG_PREVIEW_FRAME,
+ * any memory provided in a data callback must be copied if it's needed after returning.
+ */
+
+class CameraHardwareInterface : public virtual RefBase {
+public:
+ CameraHardwareInterface(hw_module_t *module, const char *name)
+ {
+ mDevice = 0;
+ mName = name;
+ LOGI("Opening camera %s, this %p", name, this);
+ int rc = module->methods->open(module, name,
+ (hw_device_t **)&mDevice);
+ if (rc != OK)
+ LOGE("Could not open camera %s: %d", name, rc);
+ initHalPreviewWindow();
+ }
+
+ ~CameraHardwareInterface()
+ {
+ LOGI("Destroying camera %s", mName.string());
+ int rc = mDevice->common.close(&mDevice->common);
+ if (rc != OK)
+ LOGE("Could not close camera %s: %d", mName.string(), rc);
+ }
+
+ /** Set the ANativeWindow to which preview frames are sent */
+ status_t setPreviewWindow(const sp<ANativeWindow>& buf)
+ {
+ LOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
+
+ if (mDevice->ops->set_preview_window) {
+ mPreviewWindow = buf;
+ mHalPreviewWindow.user = this;
+ LOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
+ &mHalPreviewWindow, mHalPreviewWindow.user);
+ return mDevice->ops->set_preview_window(mDevice,
+ buf.get() ? &mHalPreviewWindow.nw : 0);
+ }
+ return INVALID_OPERATION;
+ }
+
+ /** Set the notification and data callbacks */
+ void setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user)
+ {
+ mNotifyCb = notify_cb;
+ mDataCb = data_cb;
+ mDataCbTimestamp = data_cb_timestamp;
+ mCbUser = user;
+
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+
+ if (mDevice->ops->set_callbacks) {
+ mDevice->ops->set_callbacks(mDevice,
+ __notify_cb,
+ __data_cb,
+ __data_cb_timestamp,
+ __get_memory,
+ this);
+ }
+ }
+
+ /**
+ * The following three functions all take a msgtype,
+ * which is a bitmask of the messages defined in
+ * include/ui/Camera.h
+ */
+
+ /**
+ * Enable a message, or set of messages.
+ */
+ void enableMsgType(int32_t msgType)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->enable_msg_type)
+ mDevice->ops->enable_msg_type(mDevice, msgType);
+ }
+
+ /**
+ * Disable a message, or a set of messages.
+ *
+ * Once received a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), camera hal
+ * should not rely on its client to call releaseRecordingFrame() to release
+ * video recording frames sent out by the cameral hal before and after the
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME) call. Camera hal clients must not
+ * modify/access any video recording frame after calling
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME).
+ */
+ void disableMsgType(int32_t msgType)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->disable_msg_type)
+ mDevice->ops->disable_msg_type(mDevice, msgType);
+ }
+
+ /**
+ * Query whether a message, or a set of messages, is enabled.
+ * Note that this is operates as an AND, if any of the messages
+ * queried are off, this will return false.
+ */
+ int msgTypeEnabled(int32_t msgType)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->msg_type_enabled)
+ return mDevice->ops->msg_type_enabled(mDevice, msgType);
+ return false;
+ }
+
+ /**
+ * Start preview mode.
+ */
+ status_t startPreview()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->start_preview)
+ return mDevice->ops->start_preview(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Stop a previously started preview.
+ */
+ void stopPreview()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->stop_preview)
+ mDevice->ops->stop_preview(mDevice);
+ }
+
+ /**
+ * Returns true if preview is enabled.
+ */
+ int previewEnabled()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->preview_enabled)
+ return mDevice->ops->preview_enabled(mDevice);
+ return false;
+ }
+
+ /**
+ * Request the camera hal to store meta data or real YUV data in
+ * the video buffers send out via CAMERA_MSG_VIDEO_FRRAME for a
+ * recording session. If it is not called, the default camera
+ * hal behavior is to store real YUV data in the video buffers.
+ *
+ * This method should be called before startRecording() in order
+ * to be effective.
+ *
+ * If meta data is stored in the video buffers, it is up to the
+ * receiver of the video buffers to interpret the contents and
+ * to find the actual frame data with the help of the meta data
+ * in the buffer. How this is done is outside of the scope of
+ * this method.
+ *
+ * Some camera hal may not support storing meta data in the video
+ * buffers, but all camera hal should support storing real YUV data
+ * in the video buffers. If the camera hal does not support storing
+ * the meta data in the video buffers when it is requested to do
+ * do, INVALID_OPERATION must be returned. It is very useful for
+ * the camera hal to pass meta data rather than the actual frame
+ * data directly to the video encoder, since the amount of the
+ * uncompressed frame data can be very large if video size is large.
+ *
+ * @param enable if true to instruct the camera hal to store
+ * meta data in the video buffers; false to instruct
+ * the camera hal to store real YUV data in the video
+ * buffers.
+ *
+ * @return OK on success.
+ */
+
+ status_t storeMetaDataInBuffers(int enable)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->store_meta_data_in_buffers)
+ return mDevice->ops->store_meta_data_in_buffers(mDevice, enable);
+ return enable ? INVALID_OPERATION: OK;
+ }
+
+ /**
+ * Start record mode. When a record image is available a CAMERA_MSG_VIDEO_FRAME
+ * message is sent with the corresponding frame. Every record frame must be released
+ * by a cameral hal client via releaseRecordingFrame() before the client calls
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME). After the client calls
+ * disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's responsibility
+ * to manage the life-cycle of the video recording frames, and the client must
+ * not modify/access any video recording frames.
+ */
+ status_t startRecording()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->start_recording)
+ return mDevice->ops->start_recording(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Stop a previously started recording.
+ */
+ void stopRecording()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->stop_recording)
+ mDevice->ops->stop_recording(mDevice);
+ }
+
+ /**
+ * Returns true if recording is enabled.
+ */
+ int recordingEnabled()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->recording_enabled)
+ return mDevice->ops->recording_enabled(mDevice);
+ return false;
+ }
+
+ /**
+ * Release a record frame previously returned by CAMERA_MSG_VIDEO_FRAME.
+ *
+ * It is camera hal client's responsibility to release video recording
+ * frames sent out by the camera hal before the camera hal receives
+ * a call to disableMsgType(CAMERA_MSG_VIDEO_FRAME). After it receives
+ * the call to disableMsgType(CAMERA_MSG_VIDEO_FRAME), it is camera hal's
+ * responsibility of managing the life-cycle of the video recording
+ * frames.
+ */
+ void releaseRecordingFrame(const sp<IMemory>& mem)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->release_recording_frame) {
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+ void *data = ((uint8_t *)heap->base()) + offset;
+ return mDevice->ops->release_recording_frame(mDevice, data);
+ }
+ }
+
+ /**
+ * Start auto focus, the notification callback routine is called
+ * with CAMERA_MSG_FOCUS once when focusing is complete. autoFocus()
+ * will be called again if another auto focus is needed.
+ */
+ status_t autoFocus()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->auto_focus)
+ return mDevice->ops->auto_focus(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Cancels auto-focus function. If the auto-focus is still in progress,
+ * this function will cancel it. Whether the auto-focus is in progress
+ * or not, this function will return the focus position to the default.
+ * If the camera does not support auto-focus, this is a no-op.
+ */
+ status_t cancelAutoFocus()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->cancel_auto_focus)
+ return mDevice->ops->cancel_auto_focus(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Take a picture.
+ */
+ status_t takePicture()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->take_picture)
+ return mDevice->ops->take_picture(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Cancel a picture that was started with takePicture. Calling this
+ * method when no picture is being taken is a no-op.
+ */
+ status_t cancelPicture()
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->cancel_picture)
+ return mDevice->ops->cancel_picture(mDevice);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Set the camera parameters. This returns BAD_VALUE if any parameter is
+ * invalid or not supported. */
+ status_t setParameters(const CameraParameters &params)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->set_parameters)
+ return mDevice->ops->set_parameters(mDevice,
+ params.flatten().string());
+ return INVALID_OPERATION;
+ }
+
+ /** Return the camera parameters. */
+ CameraParameters getParameters() const
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ CameraParameters parms;
+ if (mDevice->ops->get_parameters) {
+ char *temp = mDevice->ops->get_parameters(mDevice);
+ String8 str_parms(temp);
+ free(temp);
+ parms.unflatten(str_parms);
+ }
+ return parms;
+ }
+
+ /**
+ * Send command to camera driver.
+ */
+ status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->send_command)
+ return mDevice->ops->send_command(mDevice, cmd, arg1, arg2);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * Release the hardware resources owned by this object. Note that this is
+ * *not* done in the destructor.
+ */
+ void release() {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->release)
+ mDevice->ops->release(mDevice);
+ }
+
+ /**
+ * Dump state of the camera hardware
+ */
+ status_t dump(int fd, const Vector<String16>& args) const
+ {
+ LOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mDevice->ops->dump)
+ return mDevice->ops->dump(mDevice, fd);
+ return OK; // It's fine if the HAL doesn't implement dump()
+ }
+
+private:
+ camera_device_t *mDevice;
+ String8 mName;
+
+ static void __notify_cb(int32_t msg_type, int32_t ext1,
+ int32_t ext2, void *user)
+ {
+ LOGV("%s", __FUNCTION__);
+ CameraHardwareInterface *__this =
+ static_cast<CameraHardwareInterface *>(user);
+ __this->mNotifyCb(msg_type, ext1, ext2, __this->mCbUser);
+ }
+
+ static void __data_cb(int32_t msg_type,
+ const camera_memory_t *data,
+ void *user)
+ {
+ LOGV("%s", __FUNCTION__);
+ CameraHardwareInterface *__this =
+ static_cast<CameraHardwareInterface *>(user);
+ sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+ __this->mDataCb(msg_type, mem, __this->mCbUser);
+ }
+
+ static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type,
+ const camera_memory_t *data,
+ void *user)
+ {
+ LOGV("%s", __FUNCTION__);
+ CameraHardwareInterface *__this =
+ static_cast<CameraHardwareInterface *>(user);
+ // Start refcounting the heap object from here on. When the clients
+ // drop all references, it will be destroyed (as well as the enclosed
+ // MemoryHeapBase.
+ sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+ __this->mDataCbTimestamp(timestamp, msg_type, mem, __this->mCbUser);
+ }
+
+ // This is a utility class that combines a MemoryHeapBase and a MemoryBase
+ // in one. Since we tend to use them in a one-to-one relationship, this is
+ // handy.
+
+ class CameraHeapMemory : public MemoryBase {
+ public:
+ CameraHeapMemory(size_t size) :
+ MemoryBase(new MemoryHeapBase(size), 0, size)
+ {
+ handle.data = getHeap()->base();
+ handle.size = size;
+ handle.handle = this;
+ }
+
+ camera_memory_t handle;
+ };
+
+ static camera_memory_t* __get_memory(size_t size,
+ void *user __attribute__((unused)))
+ {
+ // We allocate the object here, but we do not assign it to a strong
+ // pointer yet. The HAL will pass it back to us via the data callback
+ // or the data-timestamp callback, and from there on we will wrap it
+ // within a strong pointer.
+
+ CameraHeapMemory *mem = new CameraHeapMemory(size);
+ return &mem->handle;
+ }
+
+ static ANativeWindow *__to_anw(void *user)
+ {
+ CameraHardwareInterface *__this =
+ reinterpret_cast<CameraHardwareInterface *>(user);
+ return __this->mPreviewWindow.get();
+ }
+#define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
+
+ static int __dequeue_buffer(struct preview_stream_ops* w,
+ buffer_handle_t** buffer)
+ {
+ int rc;
+ ANativeWindow *a = anw(w);
+ ANativeWindowBuffer* anb;
+ rc = a->dequeueBuffer(a, &anb);
+ if (!rc) {
+ rc = a->lockBuffer(a, anb);
+ if (!rc)
+ *buffer = &anb->handle;
+ else
+ a->cancelBuffer(a, anb);
+ }
+ return rc;
+ }
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *) 0)->member) *__mptr = (ptr); \
+ (type *) ((char *) __mptr - (char *)(&((type *)0)->member)); })
+#endif
+
+ static int __enqueue_buffer(struct preview_stream_ops* w,
+ buffer_handle_t* buffer)
+ {
+ ANativeWindow *a = anw(w);
+ return a->queueBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle));
+ }
+
+ static int __cancel_buffer(struct preview_stream_ops* w,
+ buffer_handle_t* buffer)
+ {
+ ANativeWindow *a = anw(w);
+ return a->cancelBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle));
+ }
+
+ static int __set_buffer_count(struct preview_stream_ops* w, int count)
+ {
+ ANativeWindow *a = anw(w);
+ return native_window_set_buffer_count(a, count);
+ }
+
+ static int __set_buffers_geometry(struct preview_stream_ops* w,
+ int width, int height, int format)
+ {
+ ANativeWindow *a = anw(w);
+ return native_window_set_buffers_geometry(a,
+ width, height, format);
+ }
+
+ static int __set_crop(struct preview_stream_ops *w,
+ int left, int top, int right, int bottom)
+ {
+ ANativeWindow *a = anw(w);
+ android_native_rect_t crop;
+ crop.left = left;
+ crop.top = top;
+ crop.right = right;
+ crop.bottom = bottom;
+ return native_window_set_crop(a, &crop);
+ }
+
+ static int __set_usage(struct preview_stream_ops* w, int usage)
+ {
+ ANativeWindow *a = anw(w);
+ return native_window_set_usage(a, usage);
+ }
+
+ static int __set_swap_interval(struct preview_stream_ops *w, int interval)
+ {
+ ANativeWindow *a = anw(w);
+ return a->setSwapInterval(a, interval);
+ }
+
+ static int __get_min_undequeued_buffer_count(
+ const struct preview_stream_ops *w,
+ int *count)
+ {
+ ANativeWindow *a = anw(w);
+ return a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, count);
+ }
+
+ void initHalPreviewWindow()
+ {
+ mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer;
+ mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer;
+ mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer;
+ mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count;
+ mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry;
+ mHalPreviewWindow.nw.set_crop = __set_crop;
+ mHalPreviewWindow.nw.set_usage = __set_usage;
+ mHalPreviewWindow.nw.set_swap_interval = __set_swap_interval;
+
+ mHalPreviewWindow.nw.get_min_undequeued_buffer_count =
+ __get_min_undequeued_buffer_count;
+ }
+
+ sp<ANativeWindow> mPreviewWindow;
+
+ struct camera_preview_window {
+ struct preview_stream_ops nw;
+ void *user;
+ };
+
+ struct camera_preview_window mHalPreviewWindow;
+
+ notify_callback mNotifyCb;
+ data_callback mDataCb;
+ data_callback_timestamp mDataCbTimestamp;
+ void *mCbUser;
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f4859ec5b1c7..1e8c30b727db 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -16,6 +16,7 @@
*/
#define LOG_TAG "CameraService"
+//#define LOG_NDEBUG 0
#include <stdio.h>
#include <sys/types.h>
@@ -37,6 +38,7 @@
#include <utils/String16.h>
#include "CameraService.h"
+#include "CameraHardwareInterface.h"
namespace android {
@@ -69,22 +71,32 @@ static int getCallingUid() {
static CameraService *gCameraService;
CameraService::CameraService()
-:mSoundRef(0)
+:mSoundRef(0), mModule(0)
{
LOGI("CameraService started (pid=%d)", getpid());
+ gCameraService = this;
+}
- mNumberOfCameras = HAL_getNumberOfCameras();
- if (mNumberOfCameras > MAX_CAMERAS) {
- LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
- mNumberOfCameras, MAX_CAMERAS);
- mNumberOfCameras = MAX_CAMERAS;
- }
-
- for (int i = 0; i < mNumberOfCameras; i++) {
- setCameraFree(i);
+void CameraService::onFirstRef()
+{
+ BnCameraService::onFirstRef();
+
+ if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&mModule) < 0) {
+ LOGE("Could not load camera HAL module");
+ mNumberOfCameras = 0;
+ }
+ else {
+ mNumberOfCameras = mModule->get_number_of_cameras();
+ if (mNumberOfCameras > MAX_CAMERAS) {
+ LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
+ mNumberOfCameras, MAX_CAMERAS);
+ mNumberOfCameras = MAX_CAMERAS;
+ }
+ for (int i = 0; i < mNumberOfCameras; i++) {
+ setCameraFree(i);
+ }
}
-
- gCameraService = this;
}
CameraService::~CameraService() {
@@ -103,12 +115,19 @@ int32_t CameraService::getNumberOfCameras() {
status_t CameraService::getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo) {
+ if (!mModule) {
+ return NO_INIT;
+ }
+
if (cameraId < 0 || cameraId >= mNumberOfCameras) {
return BAD_VALUE;
}
- HAL_getCameraInfo(cameraId, cameraInfo);
- return OK;
+ struct camera_info info;
+ status_t rc = mModule->get_camera_info(cameraId, &info);
+ cameraInfo->facing = info.facing;
+ cameraInfo->orientation = info.orientation;
+ return rc;
}
sp<ICamera> CameraService::connect(
@@ -116,6 +135,11 @@ sp<ICamera> CameraService::connect(
int callingPid = getCallingPid();
LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
+ if (!mModule) {
+ LOGE("Camera HAL module not loaded");
+ return NULL;
+ }
+
sp<Client> client;
if (cameraId < 0 || cameraId >= mNumberOfCameras) {
LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
@@ -146,15 +170,19 @@ sp<ICamera> CameraService::connect(
return NULL;
}
- sp<CameraHardwareInterface> hardware = HAL_openCameraHardware(cameraId);
- if (hardware == NULL) {
- LOGE("Fail to open camera hardware (id=%d)", cameraId);
+ struct camera_info info;
+ if (mModule->get_camera_info(cameraId, &info) != OK) {
+ LOGE("Invalid camera id %d", cameraId);
return NULL;
}
- CameraInfo info;
- HAL_getCameraInfo(cameraId, &info);
- client = new Client(this, cameraClient, hardware, cameraId, info.facing,
- callingPid);
+
+ char camera_device_name[10];
+ snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
+
+ client = new Client(this, cameraClient,
+ new CameraHardwareInterface(&mModule->common,
+ camera_device_name),
+ cameraId, info.facing, callingPid);
mClient[cameraId] = client;
LOG1("CameraService::connect X");
return client;
@@ -320,7 +348,7 @@ CameraService::Client::Client(const sp<CameraService>& cameraService,
CAMERA_MSG_FOCUS);
// Callback is disabled by default
- mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
mPlayShutterSound = true;
cameraService->setCameraBusy(cameraId);
@@ -410,7 +438,7 @@ status_t CameraService::Client::connect(const sp<ICameraClient>& client) {
return NO_ERROR;
}
- mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
+ mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mClientPid = callingPid;
mCameraClient = client;
@@ -543,7 +571,7 @@ void CameraService::Client::setPreviewCallbackFlag(int callback_flag) {
if (checkPidAndHardware() != NO_ERROR) return;
mPreviewCallbackFlag = callback_flag;
- if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK) {
+ if (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) {
enableMsgType(CAMERA_MSG_PREVIEW_FRAME);
} else {
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
@@ -1009,7 +1037,7 @@ void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
int flags = mPreviewCallbackFlag;
// is callback enabled?
- if (!(flags & FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
+ if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
// If the enable bit is off, the copy-out and one-shot bits are ignored
LOG2("frame callback is disabled");
mLock.unlock();
@@ -1020,17 +1048,17 @@ void CameraService::Client::handlePreviewData(const sp<IMemory>& mem) {
sp<ICameraClient> c = mCameraClient;
// clear callback flags if no client or one-shot mode
- if (c == 0 || (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
+ if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
LOG2("Disable preview callback");
- mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
- FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
- FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
+ CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
}
if (c != 0) {
// Is the received frame copied out or not?
- if (flags & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
+ if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
LOG2("frame is copied");
copyFrameAndPostCopiedFrame(c, heap, offset, size);
} else {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 9a9ab0ee5dfe..5e2d57151271 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -19,9 +19,8 @@
#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
#include <binder/BinderService.h>
-
#include <camera/ICameraService.h>
-#include <camera/CameraHardwareInterface.h>
+#include <hardware/camera.h>
/* This needs to be increased if we can have more cameras */
#define MAX_CAMERAS 2
@@ -30,6 +29,7 @@ namespace android {
class MemoryHeapBase;
class MediaPlayer;
+class CameraHardwareInterface;
class CameraService :
public BinderService<CameraService>,
@@ -53,6 +53,7 @@ public:
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
+ virtual void onFirstRef();
enum sound_kind {
SOUND_SHUTTER = 0,
@@ -199,6 +200,8 @@ private:
// is found to be disabled. It returns true if mLock is grabbed.
bool lockIfMessageWanted(int32_t msgType);
};
+
+ camera_module_t *mModule;
};
} // namespace android
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index 8a228fd7b6c4..f86ca475b678 100644
--- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -830,10 +830,10 @@ public:
ASSERT(c->previewEnabled() == true);
sleep(2);
c->stopPreview();
- if ((v & FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
+ if ((v & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
} else {
- if ((v & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
+ if ((v & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
} else {
cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
@@ -849,7 +849,7 @@ public:
ASSERT(c->recordingEnabled() == false);
sp<MSurface> surface = new MSurface();
ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
- c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
cc->setReleaser(c.get());
c->startRecording();
ASSERT(c->recordingEnabled() == true);
@@ -870,7 +870,7 @@ public:
CameraParameters param(c->getParameters());
param.setPreviewSize(w, h);
- c->setPreviewCallbackFlag(FRAME_CALLBACK_FLAG_ENABLE_MASK);
+ c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
c->setParameters(param.flatten());
c->startPreview();
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index f04fb020fff7..208353d22f2f 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -119,6 +119,7 @@ struct InputWindow {
TYPE_DRAG = FIRST_SYSTEM_WINDOW+16,
TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17,
TYPE_POINTER = FIRST_SYSTEM_WINDOW+18,
+ TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
LAST_SYSTEM_WINDOW = 2999,
};
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6c3b3d38678e..7272e769e915 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -34,6 +34,7 @@ import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.net.Proxy;
import android.net.ProxyProperties;
+import android.net.RouteInfo;
import android.net.vpn.VpnManager;
import android.net.wifi.WifiStateTracker;
import android.os.Binder;
@@ -708,9 +709,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetRequestersPids[usedNetworkType].add(currentPid);
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK,
- f), getRestoreDefaultNetworkDelay());
+ int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType);
+
+ if (restoreTimer >= 0) {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer);
+ }
if ((ni.isConnectedOrConnecting() == true) &&
!network.isTeardownRequested()) {
@@ -1417,14 +1422,19 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (p == null) return;
String interfaceName = p.getInterfaceName();
if (TextUtils.isEmpty(interfaceName)) return;
- for (InetAddress gateway : p.getGateways()) {
+ for (RouteInfo route : p.getRoutes()) {
- if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
- NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
- if (DBG) {
- NetworkInfo networkInfo = nt.getNetworkInfo();
- log("addDefaultRoute for " + networkInfo.getTypeName() +
- " (" + interfaceName + "), GatewayAddr=" + gateway.getHostAddress());
+ //TODO - handle non-default routes
+ if (route.isDefaultRoute()) {
+ InetAddress gateway = route.getGateway();
+ if (NetworkUtils.addHostRoute(interfaceName, gateway, null) &&
+ NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
+ if (DBG) {
+ NetworkInfo networkInfo = nt.getNetworkInfo();
+ log("addDefaultRoute for " + networkInfo.getTypeName() +
+ " (" + interfaceName + "), GatewayAddr=" +
+ gateway.getHostAddress());
+ }
}
}
}
@@ -1656,7 +1666,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- private int getRestoreDefaultNetworkDelay() {
+ private int getRestoreDefaultNetworkDelay(int networkType) {
String restoreDefaultNetworkDelayStr = SystemProperties.get(
NETWORK_RESTORE_DELAY_PROP_NAME);
if(restoreDefaultNetworkDelayStr != null &&
@@ -1666,7 +1676,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
} catch (NumberFormatException e) {
}
}
- return RESTORE_DEFAULT_NETWORK_DELAY;
+ // if the system property isn't set, use the value for the apn type
+ int ret = RESTORE_DEFAULT_NETWORK_DELAY;
+
+ if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) &&
+ (mNetConfigs[networkType] != null)) {
+ ret = mNetConfigs[networkType].restoreTime;
+ }
+ return ret;
}
@Override
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 44f5df2cf1bc..d931350047ce 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.pm.PackageManager;
+import android.net.NetworkStats;
import android.net.Uri;
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
@@ -32,6 +33,8 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.INetworkManagementService;
import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -44,13 +47,21 @@ import android.content.ContentResolver;
import android.database.ContentObserver;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.RandomAccessFile;
+import java.io.Reader;
import java.lang.IllegalStateException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;
+import libcore.io.IoUtils;
+
/**
* @hide
*/
@@ -716,12 +727,47 @@ class NetworkManagementService extends INetworkManagementService.Stub {
return -1;
}
- public long getInterfaceRxCounter(String iface) {
- return getInterfaceCounter(iface, true);
+ /** {@inheritDoc} */
+ public NetworkStats getNetworkStatsSummary() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ final String[] ifaces = listInterfaces();
+ final NetworkStats.Builder stats = new NetworkStats.Builder(
+ SystemClock.elapsedRealtime(), ifaces.length);
+
+ for (String iface : ifaces) {
+ final long rx = getInterfaceCounter(iface, true);
+ final long tx = getInterfaceCounter(iface, false);
+ stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
+ }
+
+ return stats.build();
}
- public long getInterfaceTxCounter(String iface) {
- return getInterfaceCounter(iface, false);
+ /** {@inheritDoc} */
+ public NetworkStats getNetworkStatsDetail() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+ final File procPath = new File("/proc/uid_stat");
+ final String[] knownUids = procPath.list();
+ final NetworkStats.Builder stats = new NetworkStats.Builder(
+ SystemClock.elapsedRealtime(), knownUids.length);
+
+ // TODO: kernel module will provide interface-level stats in future
+ // TODO: migrate these stats to come across netd in bulk, instead of all
+ // these individual file reads.
+ for (String uid : knownUids) {
+ final File uidPath = new File(procPath, uid);
+ final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
+ final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));
+
+ final int uidInt = Integer.parseInt(uid);
+ stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
+ }
+
+ return stats.build();
}
public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
@@ -782,4 +828,24 @@ class NetworkManagementService extends INetworkManagementService.Stub {
public int getInterfaceTxThrottle(String iface) {
return getInterfaceThrottle(iface, false);
}
+
+ /**
+ * Utility method to read a single plain-text {@link Integer} from the given
+ * {@link File}, usually from a {@code /proc/} filesystem.
+ */
+ private static int readSingleIntFromFile(File file) {
+ RandomAccessFile f = null;
+ try {
+ f = new RandomAccessFile(file, "r");
+ byte[] buffer = new byte[(int) f.length()];
+ f.readFully(buffer);
+ return Integer.parseInt(new String(buffer).trim());
+ } catch (NumberFormatException e) {
+ return -1;
+ } catch (IOException e) {
+ return -1;
+ } finally {
+ IoUtils.closeQuietly(f);
+ }
+ }
}
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 02332b7aa918..510ff62ed514 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -33,6 +33,7 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.INetworkManagementEventObserver;
import android.net.IThrottleManager;
+import android.net.NetworkStats;
import android.net.ThrottleManager;
import android.os.Binder;
import android.os.Environment;
@@ -531,8 +532,17 @@ public class ThrottleService extends IThrottleManager.Stub {
long incRead = 0;
long incWrite = 0;
try {
- incRead = mNMService.getInterfaceRxCounter(mIface) - mLastRead;
- incWrite = mNMService.getInterfaceTxCounter(mIface) - mLastWrite;
+ final NetworkStats stats = mNMService.getNetworkStatsSummary();
+ final int index = stats.findIndex(mIface, NetworkStats.UID_ALL);
+
+ if (index != -1) {
+ incRead = stats.rx[index] - mLastRead;
+ incWrite = stats.tx[index] - mLastWrite;
+ } else {
+ // missing iface, assume stats are 0
+ Slog.w(TAG, "unable to find stats for iface " + mIface);
+ }
+
// handle iface resets - on some device the 3g iface comes and goes and gets
// totals reset to 0. Deal with it
if ((incRead < 0) || (incWrite < 0)) {
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index bf1b6e65c8f6..6ef6963c8a69 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -28,6 +28,7 @@ import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -508,6 +509,7 @@ public class WifiWatchdogService {
// This access point does not require a watchdog, so queue idle on the main thread
mHandler.idle();
}
+ mHandler.checkWalledGarden(ssid);
}
/**
@@ -1002,6 +1004,8 @@ public class WifiWatchdogService {
* The object will be an {@link AccessPoint}.
*/
static final int ACTION_BACKGROUND_CHECK_AP = 3;
+ /** Check whether the connection is a walled garden */
+ static final int ACTION_CHECK_WALLED_GARDEN = 4;
/**
* Go to sleep for the current network. We are conservative with making
@@ -1022,7 +1026,16 @@ public class WifiWatchdogService {
static final int MESSAGE_DISCONNECTED = 104;
/** Performs a hard-reset on the watchdog state. */
static final int MESSAGE_RESET = 105;
-
+
+ /* Walled garden detection */
+ private String mLastSsid;
+ private long mLastTime;
+ private final long MIN_WALLED_GARDEN_TEST_INTERVAL = 15 * 60 * 1000; //15 minutes
+
+ void checkWalledGarden(String ssid) {
+ sendMessage(obtainMessage(ACTION_CHECK_WALLED_GARDEN, ssid));
+ }
+
void checkAp(AccessPoint ap) {
removeAllActions();
sendMessage(obtainMessage(ACTION_CHECK_AP, ap));
@@ -1084,6 +1097,9 @@ public class WifiWatchdogService {
case ACTION_BACKGROUND_CHECK_AP:
handleBackgroundCheckAp((AccessPoint) msg.obj);
break;
+ case ACTION_CHECK_WALLED_GARDEN:
+ handleWalledGardenCheck((String) msg.obj);
+ break;
case MESSAGE_SLEEP:
handleSleep((String) msg.obj);
break;
@@ -1101,6 +1117,43 @@ public class WifiWatchdogService {
break;
}
}
+
+ private boolean isWalledGardenConnection() {
+ //One way to detect a walled garden is to see if multiple DNS queries
+ //resolve to the same IP address
+ try {
+ String host1 = "www.google.com";
+ String host2 = "www.android.com";
+ String address1 = InetAddress.getByName(host1).getHostAddress();
+ String address2 = InetAddress.getByName(host2).getHostAddress();
+ if (address1.equals(address2)) return true;
+ } catch (UnknownHostException e) {
+ return false;
+ }
+ return false;
+ }
+
+ private void handleWalledGardenCheck(String ssid) {
+ long currentTime = System.currentTimeMillis();
+ //Avoid a walled garden test on the same network if one was already done
+ //within MIN_WALLED_GARDEN_TEST_INTERVAL. This will handle scenarios where
+ //there are frequent network disconnections
+ if (ssid.equals(mLastSsid) &&
+ (currentTime - mLastTime) < MIN_WALLED_GARDEN_TEST_INTERVAL) {
+ return;
+ }
+
+ mLastTime = currentTime;
+ mLastSsid = ssid;
+
+ if (isWalledGardenConnection()) {
+ Uri uri = Uri.parse("http://www.google.com");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+ Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+ }
}
/**
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/java/com/android/server/wm/ViewServer.java
index cebd5e70e8a8..9fb35b966bfa 100644
--- a/services/java/com/android/server/wm/ViewServer.java
+++ b/services/java/com/android/server/wm/ViewServer.java
@@ -49,7 +49,7 @@ class ViewServer implements Runnable {
// Debug facility
private static final String LOG_TAG = "ViewServer";
- private static final String VALUE_PROTOCOL_VERSION = "3";
+ private static final String VALUE_PROTOCOL_VERSION = "4";
private static final String VALUE_SERVER_VERSION = "4";
// Protocol commands
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7506f298f2aa..e8f0328b3a45 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -395,7 +395,7 @@ bool SurfaceFlinger::threadLoop()
if (LIKELY(mTransactionCount == 0)) {
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
- uint32_t transactionFlags = getTransactionFlags(mask);
+ uint32_t transactionFlags = peekTransactionFlags(mask);
if (LIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
@@ -490,7 +490,17 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
+
+ // Here we're guaranteed that some transaction flags are set
+ // so we can call handleTransactionLocked() unconditionally.
+ // We call getTransactionFlags(), which will also clear the flags,
+ // with mStateLock held to guarantee that mCurrentState won't change
+ // until the transaction is commited.
+
+ const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+ transactionFlags = getTransactionFlags(mask);
handleTransactionLocked(transactionFlags, ditchedLayers);
+
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
@@ -1094,15 +1104,15 @@ status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
const sp<LayerBaseClient>& lbc)
{
- Mutex::Autolock _l(mStateLock);
-
// attach this layer to the client
- ssize_t name = client->attachLayer(lbc);
+ size_t name = client->attachLayer(lbc);
+
+ Mutex::Autolock _l(mStateLock);
// add this layer to the current state list
addLayer_l(lbc);
- return name;
+ return ssize_t(name);
}
status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer)
@@ -1153,6 +1163,11 @@ status_t SurfaceFlinger::invalidateLayerVisibility(const sp<LayerBase>& layer)
return NO_ERROR;
}
+uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags)
+{
+ return android_atomic_release_load(&mTransactionFlags);
+}
+
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags)
{
return android_atomic_and(~flags, &mTransactionFlags) & flags;
@@ -2381,15 +2396,17 @@ status_t Client::initCheck() const {
return NO_ERROR;
}
-ssize_t Client::attachLayer(const sp<LayerBaseClient>& layer)
+size_t Client::attachLayer(const sp<LayerBaseClient>& layer)
{
- int32_t name = android_atomic_inc(&mNameGenerator);
+ Mutex::Autolock _l(mLock);
+ size_t name = mNameGenerator++;
mLayers.add(name, layer);
return name;
}
void Client::detachLayer(const LayerBaseClient* layer)
{
+ Mutex::Autolock _l(mLock);
// we do a linear search here, because this doesn't happen often
const size_t count = mLayers.size();
for (size_t i=0 ; i<count ; i++) {
@@ -2399,9 +2416,11 @@ void Client::detachLayer(const LayerBaseClient* layer)
}
}
}
-sp<LayerBaseClient> Client::getLayerUser(int32_t i) const {
+sp<LayerBaseClient> Client::getLayerUser(int32_t i) const
+{
+ Mutex::Autolock _l(mLock);
sp<LayerBaseClient> lbc;
- const wp<LayerBaseClient>& layer(mLayers.valueFor(i));
+ wp<LayerBaseClient> layer(mLayers.valueFor(i));
if (layer != 0) {
lbc = layer.promote();
LOGE_IF(lbc==0, "getLayerUser(name=%d) is dead", int(i));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1b36d1cd67be..1e16943243be 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -65,7 +65,7 @@ public:
status_t initCheck() const;
// protected by SurfaceFlinger::mStateLock
- ssize_t attachLayer(const sp<LayerBaseClient>& layer);
+ size_t attachLayer(const sp<LayerBaseClient>& layer);
void detachLayer(const LayerBaseClient* layer);
sp<LayerBaseClient> getLayerUser(int32_t i) const;
@@ -81,9 +81,15 @@ private:
virtual status_t destroySurface(SurfaceID surfaceId);
virtual status_t setState(int32_t count, const layer_state_t* states);
- DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+ // constant
sp<SurfaceFlinger> mFlinger;
- int32_t mNameGenerator;
+
+ // protected by mLock
+ DefaultKeyedVector< size_t, wp<LayerBaseClient> > mLayers;
+ size_t mNameGenerator;
+
+ // thread-safe
+ mutable Mutex mLock;
};
class UserClient : public BnSurfaceComposerClient
@@ -319,6 +325,7 @@ private:
status_t purgatorizeLayer_l(const sp<LayerBase>& layer);
uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t peekTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
void commitTransaction();
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index 9e24f90d550b..bb63c379851d 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -144,7 +144,7 @@ status_t TextureManager::initEglImage(Image* pImage,
}
// construct an EGL_NATIVE_BUFFER_ANDROID
- android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+ ANativeWindowBuffer* clientBuf = buffer->getNativeBuffer();
// create the new EGLImageKHR
const EGLint attrs[] = {
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 67ecf7e1000d..5265f919536b 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -53,7 +53,7 @@ int main(int argc, char** argv)
printf("window=%p\n", window);
int err = native_window_set_buffer_count(window, 8);
- android_native_buffer_t* buffer;
+ ANativeWindowBuffer* buffer;
for (int i=0 ; i<8 ; i++) {
window->dequeueBuffer(window, &buffer);
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index 6f55f4600dcd..f20d5e5e2ef9 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -34,11 +34,17 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.INetworkManagementEventObserver;
+import android.net.NetworkStats;
import android.net.ThrottleManager;
+import android.os.IBinder;
import android.os.INetworkManagementService;
+import android.os.ServiceManager;
+import android.os.SystemClock;
import android.provider.Settings;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
import android.text.format.DateUtils;
+import android.util.Log;
import android.util.TrustedTime;
import java.util.Iterator;
@@ -222,6 +228,16 @@ public class ThrottleServiceTest extends AndroidTestCase {
verify(mMockTime, mMockNMService);
}
+ @Suppress
+ public void testReturnStats() throws Exception {
+ final IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ final INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);
+
+ // test is currently no-op, just exercises stats apis
+ Log.d(TAG, nmService.getNetworkStatsSummary().toString());
+ Log.d(TAG, nmService.getNetworkStatsDetail().toString());
+ }
+
/**
* Persist the given {@link ThrottleService} policy into {@link Settings}.
*/
@@ -272,12 +288,16 @@ public class ThrottleServiceTest extends AndroidTestCase {
}
/**
- * Expect {@link NetworkManagementService#getInterfaceRxCounter} mock calls,
- * responding with the given counter values.
+ * Expect {@link NetworkManagementService#getNetworkStatsSummary()} mock
+ * calls, responding with the given counter values.
*/
public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
- expect(mMockNMService.getInterfaceRxCounter(isA(String.class))).andReturn(rx).atLeastOnce();
- expect(mMockNMService.getInterfaceTxCounter(isA(String.class))).andReturn(tx).atLeastOnce();
+ // TODO: provide elapsedRealtime mock to match TimeAuthority
+ final NetworkStats.Builder stats = new NetworkStats.Builder(
+ SystemClock.elapsedRealtime(), 1);
+ stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, rx, tx);
+
+ expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats.build()).atLeastOnce();
}
/**
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java
index 3f1ca9e9b9fb..010d61d59cbe 100644
--- a/telephony/java/com/android/internal/telephony/ApnContext.java
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -51,6 +51,8 @@ public class ApnContext {
DataConnection mDataConnection;
+ DataConnectionAc mDataConnectionAc;
+
String mReason;
PendingIntent mReconnectIntent;
@@ -96,6 +98,17 @@ public class ApnContext {
mDataConnection = dataConnection;
}
+
+ public synchronized DataConnectionAc getDataConnectionAc() {
+ log("getDataConnectionAc dcac=" + mDataConnectionAc);
+ return mDataConnectionAc;
+ }
+
+ public synchronized void setDataConnectionAc(DataConnectionAc dcac) {
+ log("setDataConnectionAc dcac=" + dcac);
+ mDataConnectionAc = dcac;
+ }
+
public synchronized ApnSetting getApnSetting() {
return mApnSetting;
}
@@ -206,6 +219,11 @@ public class ApnContext {
return mDependencyMet.get();
}
+ @Override
+ public String toString() {
+ return "state=" + getState() + " apnType=" + mApnType;
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, "[ApnContext] " + s);
}
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index a883e8efc36f..1d67d454b3fb 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -20,6 +20,7 @@ package com.android.internal.telephony;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
+import android.net.RouteInfo;
import android.os.SystemProperties;
import android.util.Log;
@@ -196,7 +197,7 @@ public class DataCallState {
} catch (IllegalArgumentException e) {
throw new UnknownHostException("Non-numeric gateway addr=" + addr);
}
- linkProperties.addGateway(ia);
+ linkProperties.addRoute(new RouteInfo(ia));
}
result = SetupResult.SUCCESS;
@@ -223,5 +224,3 @@ public class DataCallState {
return result;
}
}
-
-
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 791fbfdd08a3..6a5b82c2aed7 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,22 +17,24 @@
package com.android.internal.telephony;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
-import android.net.LinkAddress;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
-import android.net.NetworkUtils;
+import android.net.ProxyProperties;
import android.os.AsyncResult;
+import android.os.Bundle;
import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.SystemProperties;
import android.text.TextUtils;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* {@hide}
@@ -60,6 +62,8 @@ public abstract class DataConnection extends StateMachine {
protected static Object mCountLock = new Object();
protected static int mCount;
+ protected AsyncChannel mAc;
+
/**
* Used internally for saving connecting parameters.
@@ -76,13 +80,6 @@ public abstract class DataConnection extends StateMachine {
}
/**
- * An instance used for notification of blockingReset.
- * TODO: Remove when blockingReset is removed.
- */
- class ResetSynchronouslyLock {
- }
-
- /**
* Used internally for saving disconnecting parameters.
*/
protected static class DisconnectParams {
@@ -90,15 +87,9 @@ public abstract class DataConnection extends StateMachine {
this.reason = reason;
this.onCompletedMsg = onCompletedMsg;
}
- public DisconnectParams(ResetSynchronouslyLock lockObj) {
- this.reason = null;
- this.lockObj = lockObj;
- }
-
public int tag;
public String reason;
public Message onCompletedMsg;
- public ResetSynchronouslyLock lockObj;
}
/**
@@ -188,13 +179,13 @@ public abstract class DataConnection extends StateMachine {
}
// ***** Event codes for driving the state machine
- protected static final int EVENT_RESET = 1;
- protected static final int EVENT_CONNECT = 2;
- protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 3;
- protected static final int EVENT_GET_LAST_FAIL_DONE = 4;
- protected static final int EVENT_DEACTIVATE_DONE = 5;
- protected static final int EVENT_DISCONNECT = 6;
- protected static final int EVENT_RIL_CONNECTED = 7;
+ protected static final int BASE = Protocol.BASE_DATA_CONNECTION;
+ protected static final int EVENT_CONNECT = BASE + 0;
+ protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1;
+ protected static final int EVENT_GET_LAST_FAIL_DONE = BASE + 2;
+ protected static final int EVENT_DEACTIVATE_DONE = BASE + 3;
+ protected static final int EVENT_DISCONNECT = BASE + 4;
+ protected static final int EVENT_RIL_CONNECTED = BASE + 5;
//***** Tag IDs for EventLog
protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
@@ -313,13 +304,8 @@ public abstract class DataConnection extends StateMachine {
AsyncResult.forMessage(msg);
msg.sendToTarget();
}
- if (dp.lockObj != null) {
- synchronized(dp.lockObj) {
- dp.lockObj.notify();
- }
- }
-
clearSettings();
+ if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp);
}
protected int getRadioTechnology(int defaultRadioTechnology) {
@@ -408,6 +394,49 @@ public abstract class DataConnection extends StateMachine {
return mRetryMgr.isRetryForever();
}
+ private AtomicInteger mRefCount = new AtomicInteger(0);
+
+ /**
+ * Set refCount.
+ *
+ * @param val is new refCount
+ */
+ public void setRefCount(int val) {
+ mRefCount.set(val);
+ }
+
+ /**
+ * Get refCount
+ *
+ * @return refCount
+ */
+ public int getRefCount() {
+ return mRefCount.get();
+ }
+
+ /**
+ * @return decrement and return refCount
+ *
+ * TODO: Consider using the refCount for defining the
+ * life time of a connection. When this goes zero the
+ * DataConnection could tear itself down.
+ */
+ public int decAndGetRefCount() {
+ int v = mRefCount.decrementAndGet();
+ if (v < 0) {
+ log("BUG: decAndGetRefCount caused refCount to be < 0");
+ mRefCount.set(0);
+ }
+ return v;
+ }
+
+ /**
+ * @return increment and return refCount
+ */
+ public int incAndGetRefCount() {
+ return mRefCount.incrementAndGet();
+ }
+
/*
* **************************************************************************
* End members owned by DataConnectionTracker
@@ -498,12 +527,74 @@ public abstract class DataConnection extends StateMachine {
AsyncResult ar;
switch (msg.what) {
- case EVENT_RESET:
- if (DBG) log("DcDefaultState: msg.what=EVENT_RESET");
- clearSettings();
- if (msg.obj != null) {
- notifyDisconnectCompleted((DisconnectParams) msg.obj);
+ case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+ if (mAc != null) {
+ log("Disconnecting to previous connection mAc=" + mAc);
+ mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
+ } else {
+ mAc = new AsyncChannel();
+ mAc.connected(null, getHandler(), msg.replyTo);
+ log("DcDefaultState: FULL_CONNECTION reply connected");
+ mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
}
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+ log("CMD_CHANNEL_DISCONNECT");
+ mAc.disconnect();
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ log("CMD_CHANNEL_DISCONNECTED");
+ mAc = null;
+ break;
+ }
+ case DataConnectionAc.REQ_IS_INACTIVE: {
+ boolean val = getCurrentState() == mInactiveState;
+ log("REQ_IS_INACTIVE isInactive=" + val);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_IS_INACTIVE, val ? 1 : 0);
+ break;
+ }
+ case DataConnectionAc.REQ_GET_CID: {
+ log("REQ_GET_CID cid=" + cid);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_CID, cid);
+ break;
+ }
+ case DataConnectionAc.REQ_GET_APNSETTING: {
+ log("REQ_GET_APNSETTING apnSetting=" + mApn);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNSETTING, mApn);
+ break;
+ }
+ case DataConnectionAc.REQ_GET_LINK_PROPERTIES: {
+ LinkProperties lp = new LinkProperties(mLinkProperties);
+ log("REQ_GET_LINK_PROPERTIES linkProperties" + lp);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_PROPERTIES, lp);
+ break;
+ }
+ case DataConnectionAc.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: {
+ ProxyProperties proxy = (ProxyProperties) msg.obj;
+ log("REQ_SET_LINK_PROPERTIES_HTTP_PROXY proxy=" + proxy);
+ mLinkProperties.setHttpProxy(proxy);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
+ break;
+ }
+ case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
+ LinkCapabilities lc = new LinkCapabilities(mCapabilities);
+ log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc);
+ break;
+ }
+ case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
+ Bundle data = msg.getData();
+ mLinkProperties = (LinkProperties) data.get("linkProperties");
+ break;
+ }
+ case DataConnectionAc.REQ_RESET:
+ if (DBG) log("DcDefaultState: msg.what=REQ_RESET");
+ clearSettings();
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
transitionTo(mInactiveState);
break;
@@ -539,7 +630,7 @@ public abstract class DataConnection extends StateMachine {
break;
}
- return true;
+ return HANDLED;
}
}
private DcDefaultState mDefaultState = new DcDefaultState();
@@ -597,14 +688,12 @@ public abstract class DataConnection extends StateMachine {
boolean retVal;
switch (msg.what) {
- case EVENT_RESET:
+ case DataConnectionAc.REQ_RESET:
if (DBG) {
- log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset");
+ log("DcInactiveState: msg.what=RSP_RESET, ignore we're already reset");
}
- if (msg.obj != null) {
- notifyDisconnectCompleted((DisconnectParams) msg.obj);
- }
- retVal = true;
+ mAc.replyToMessage(msg, DataConnectionAc.RSP_RESET);
+ retVal = HANDLED;
break;
case EVENT_CONNECT:
@@ -613,12 +702,12 @@ public abstract class DataConnection extends StateMachine {
cp.tag = mTag;
onConnect(cp);
transitionTo(mActivatingState);
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcInactiveState nothandled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -640,7 +729,7 @@ public abstract class DataConnection extends StateMachine {
case EVENT_DISCONNECT:
if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
deferMessage(msg);
- retVal = true;
+ retVal = HANDLED;
break;
case EVENT_SETUP_DATA_CONNECTION_DONE:
@@ -685,7 +774,7 @@ public abstract class DataConnection extends StateMachine {
default:
throw new RuntimeException("Unknown SetupResult, should not happen");
}
- retVal = true;
+ retVal = HANDLED;
break;
case EVENT_GET_LAST_FAIL_DONE:
@@ -710,12 +799,12 @@ public abstract class DataConnection extends StateMachine {
}
}
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcActivatingState not handled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -768,12 +857,12 @@ public abstract class DataConnection extends StateMachine {
dp.tag = mTag;
tearDownData(dp);
transitionTo(mDisconnectingState);
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcActiveState nothandled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -803,12 +892,12 @@ public abstract class DataConnection extends StateMachine {
if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
+ dp.tag + " mTag=" + mTag);
}
- retVal = true;
+ retVal = HANDLED;
break;
default:
if (DBG) log("DcDisconnectingState not handled msg.what=" + msg.what);
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -845,7 +934,7 @@ public abstract class DataConnection extends StateMachine {
" stale dp.tag=" + cp.tag + ", mTag=" + mTag);
}
}
- retVal = true;
+ retVal = HANDLED;
break;
default:
@@ -853,7 +942,7 @@ public abstract class DataConnection extends StateMachine {
log("DcDisconnectionErrorCreatingConnection not handled msg.what="
+ msg.what);
}
- retVal = false;
+ retVal = NOT_HANDLED;
break;
}
return retVal;
@@ -865,147 +954,26 @@ public abstract class DataConnection extends StateMachine {
// ******* public interface
/**
- * Disconnect from the network.
- *
- * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
- * With AsyncResult.userObj set to the original msg.obj.
- */
- public void reset(Message onCompletedMsg) {
- sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(null, onCompletedMsg)));
- }
-
- /**
- * Reset the connection and wait for it to complete.
- * TODO: Remove when all callers only need the asynchronous
- * reset defined above.
- */
- public void resetSynchronously() {
- ResetSynchronouslyLock lockObj = new ResetSynchronouslyLock();
- synchronized(lockObj) {
- sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(lockObj)));
- try {
- lockObj.wait();
- } catch (InterruptedException e) {
- log("blockingReset: unexpected interrupted of wait()");
- }
- }
- }
-
- /**
- * Connect to the apn and return an AsyncResult in onCompletedMsg.
+ * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
* Used for cellular networks that use Acesss Point Names (APN) such
* as GSM networks.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj,
* AsyncResult.result = FailCause and AsyncResult.exception = Exception().
- * @param apn is the Access Point Name to connect to
+ * @param apn is the Access Point Name to bring up a connection to
*/
- public void connect(Message onCompletedMsg, ApnSetting apn) {
+ public void bringUp(Message onCompletedMsg, ApnSetting apn) {
sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
}
/**
- * Connect to the apn and return an AsyncResult in onCompletedMsg.
- *
- * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
- * With AsyncResult.userObj set to the original msg.obj,
- * AsyncResult.result = FailCause and AsyncResult.exception = Exception().
- */
- public void connect(Message onCompletedMsg) {
- sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(null, onCompletedMsg)));
- }
-
- /**
- * Disconnect from the network.
+ * Tear down the connection through the apn on the network.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj.
*/
- public void disconnect(String reason, Message onCompletedMsg) {
+ public void tearDown(String reason, Message onCompletedMsg) {
sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg)));
}
-
- // ****** The following are used for debugging.
-
- /**
- * TODO: This should be an asynchronous call and we wouldn't
- * have to use handle the notification in the DcInactiveState.enter.
- *
- * @return true if the state machine is in the inactive state.
- */
- public boolean isInactive() {
- boolean retVal = getCurrentState() == mInactiveState;
- return retVal;
- }
-
- /**
- * TODO: This should be an asynchronous call and we wouldn't
- * have to use handle the notification in the DcActiveState.enter.
- *
- * @return true if the state machine is in the active state.
- */
- public boolean isActive() {
- boolean retVal = getCurrentState() == mActiveState;
- return retVal;
- }
-
- /**
- * Return the LinkProperties for the connection.
- *
- * @return a copy of the LinkProperties, is never null.
- */
- public LinkProperties getLinkProperties() {
- return new LinkProperties(mLinkProperties);
- }
-
- /**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
- * @return a copy of this connections capabilities, may be empty but never null.
- */
- public LinkCapabilities getLinkCapabilities() {
- return new LinkCapabilities(mCapabilities);
- }
-
- /**
- * @return the current state as a string.
- */
- public String getStateAsString() {
- String retVal = getCurrentState().getName();
- return retVal;
- }
-
- /**
- * @return the time of when this connection was created.
- */
- public long getConnectionTime() {
- return createTime;
- }
-
- /**
- * @return the time of the last failure.
- */
- public long getLastFailTime() {
- return lastFailTime;
- }
-
- /**
- * @return the last cause of failure.
- */
- public FailCause getLastFailCause() {
- return lastFailCause;
- }
-
- /**
- * @return the current ApnSetting
- */
- public ApnSetting getApn() {
- return mApn;
- }
-
- public int getCid() {
- return cid;
- }
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
new file mode 100644
index 000000000000..a9796dde26ab
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
+import android.net.ProxyProperties;
+import android.os.Message;
+
+/**
+ * AsyncChannel to a DataConnection
+ */
+public class DataConnectionAc extends AsyncChannel {
+ private static final boolean DBG = true;
+ private String mLogTag;
+
+ public DataConnection dataConnection;
+
+ public static final int BASE = Protocol.BASE_DATA_CONNECTION_AC;
+
+ public static final int REQ_IS_INACTIVE = BASE + 0;
+ public static final int RSP_IS_INACTIVE = BASE + 1;
+
+ public static final int REQ_GET_CID = BASE + 2;
+ public static final int RSP_GET_CID = BASE + 3;
+
+ public static final int REQ_GET_APNSETTING = BASE + 4;
+ public static final int RSP_GET_APNSETTING = BASE + 5;
+
+ public static final int REQ_GET_LINK_PROPERTIES = BASE + 6;
+ public static final int RSP_GET_LINK_PROPERTIES = BASE + 7;
+
+ public static final int REQ_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 8;
+ public static final int RSP_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 9;
+
+ public static final int REQ_GET_LINK_CAPABILITIES = BASE + 10;
+ public static final int RSP_GET_LINK_CAPABILITIES = BASE + 11;
+
+ public static final int REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 12;
+ public static final int RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE = BASE + 13;
+
+ public static final int REQ_RESET = BASE + 14;
+ public static final int RSP_RESET = BASE + 15;
+
+ public DataConnectionAc(DataConnection dc, String logTag) {
+ dataConnection = dc;
+ mLogTag = logTag;
+ }
+
+ /**
+ * Request if the state machine is in the inactive state.
+ * Response {@link #rspIsInactive}
+ */
+ public void reqIsInactive() {
+ sendMessage(REQ_IS_INACTIVE);
+ if (DBG) log("reqIsInactive");
+ }
+
+ /**
+ * Evaluate RSP_IS_INACTIVE.
+ *
+ * @return true if the state machine is in the inactive state.
+ */
+ public boolean rspIsInactive(Message response) {
+ boolean retVal = response.arg1 == 1;
+ if (DBG) log("rspIsInactive=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * @return true if the state machine is in the inactive state.
+ */
+ public boolean isInactiveSync() {
+ Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
+ if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
+ return rspIsInactive(response);
+ } else {
+ log("rspIsInactive error response=" + response);
+ return false;
+ }
+ }
+
+ /**
+ * Request the Connection ID.
+ * Response {@link #rspCid}
+ */
+ public void reqCid() {
+ sendMessage(REQ_GET_CID);
+ if (DBG) log("reqCid");
+ }
+
+ /**
+ * Evaluate a RSP_GET_CID message and return the cid.
+ *
+ * @param response Message
+ * @return connection id or -1 if an error
+ */
+ public int rspCid(Message response) {
+ int retVal = response.arg1;
+ if (DBG) log("rspCid=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * @return connection id or -1 if an error
+ */
+ public int getCidSync() {
+ Message response = sendMessageSynchronously(REQ_GET_CID);
+ if ((response != null) && (response.what == RSP_GET_CID)) {
+ return rspCid(response);
+ } else {
+ log("rspCid error response=" + response);
+ return -1;
+ }
+ }
+
+ /**
+ * Request the connections ApnSetting.
+ * Response {@link #rspApnSetting}
+ */
+ public void reqApnSetting() {
+ sendMessage(REQ_GET_APNSETTING);
+ if (DBG) log("reqApnSetting");
+ }
+
+ /**
+ * Evaluate a RSP_APN_SETTING message and return the ApnSetting.
+ *
+ * @param response Message
+ * @return ApnSetting, maybe null
+ */
+ public ApnSetting rspApnSetting(Message response) {
+ ApnSetting retVal = (ApnSetting) response.obj;
+ if (DBG) log("rspApnSetting=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * Get the connections ApnSetting.
+ *
+ * @return ApnSetting or null if an error
+ */
+ public ApnSetting getApnSettingSync() {
+ Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
+ if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
+ return rspApnSetting(response);
+ } else {
+ log("getApnSetting error response=" + response);
+ return null;
+ }
+ }
+
+ /**
+ * Request the connections LinkProperties.
+ * Response {@link #rspLinkProperties}
+ */
+ public void reqLinkProperties() {
+ sendMessage(REQ_GET_LINK_PROPERTIES);
+ if (DBG) log("reqLinkProperties");
+ }
+
+ /**
+ * Evaluate RSP_GET_LINK_PROPERTIES
+ *
+ * @param response
+ * @return LinkProperties, maybe null.
+ */
+ public LinkProperties rspLinkProperties(Message response) {
+ LinkProperties retVal = (LinkProperties) response.obj;
+ if (DBG) log("rspLinkProperties=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * Get the connections LinkProperties.
+ *
+ * @return LinkProperties or null if an error
+ */
+ public LinkProperties getLinkPropertiesSync() {
+ Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
+ if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
+ return rspLinkProperties(response);
+ } else {
+ log("getLinkProperties error response=" + response);
+ return null;
+ }
+ }
+
+ /**
+ * Request setting the connections LinkProperties.HttpProxy.
+ * Response RSP_SET_LINK_PROPERTIES when complete.
+ */
+ public void reqSetLinkPropertiesHttpProxy(ProxyProperties proxy) {
+ sendMessage(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
+ if (DBG) log("reqSetLinkPropertiesHttpProxy proxy=" + proxy);
+ }
+
+ /**
+ * Set the connections LinkProperties.HttpProxy
+ */
+ public void setLinkPropertiesHttpProxySync(ProxyProperties proxy) {
+ Message response =
+ sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
+ if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
+ if (DBG) log("setLinkPropertiesHttpPoxy ok");
+ } else {
+ log("setLinkPropertiesHttpPoxy error response=" + response);
+ }
+ }
+
+ /**
+ * Request the connections LinkCapabilities.
+ * Response {@link #rspLinkCapabilities}
+ */
+ public void reqLinkCapabilities() {
+ sendMessage(REQ_GET_LINK_CAPABILITIES);
+ if (DBG) log("reqLinkCapabilities");
+ }
+
+ /**
+ * Evaluate RSP_GET_LINK_CAPABILITIES
+ *
+ * @param response
+ * @return LinkCapabilites, maybe null.
+ */
+ public LinkCapabilities rspLinkCapabilities(Message response) {
+ LinkCapabilities retVal = (LinkCapabilities) response.obj;
+ if (DBG) log("rspLinkCapabilities=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * Get the connections LinkCapabilities.
+ *
+ * @return LinkCapabilities or null if an error
+ */
+ public LinkCapabilities getLinkCapabilitiesSync() {
+ Message response = sendMessageSynchronously(REQ_GET_LINK_CAPABILITIES);
+ if ((response != null) && (response.what == RSP_GET_LINK_CAPABILITIES)) {
+ return rspLinkCapabilities(response);
+ } else {
+ log("getLinkCapabilities error response=" + response);
+ return null;
+ }
+ }
+
+ /**
+ * Request the connections LinkCapabilities.
+ * Response RSP_RESET when complete
+ */
+ public void reqReset() {
+ sendMessage(REQ_RESET);
+ if (DBG) log("reqReset");
+ }
+
+ /**
+ * Reset the connection and wait for it to complete.
+ */
+ public void resetSync() {
+ Message response = sendMessageSynchronously(REQ_RESET);
+ if ((response != null) && (response.what == RSP_RESET)) {
+ if (DBG) log("restSync ok");
+ } else {
+ if (DBG) log("restSync error response=" + response);
+ }
+ }
+
+ private void log(String s) {
+ android.util.Log.d(mLogTag, "DataConnectionAc " + s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 01ac95fdf8f0..ad39b272ac64 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -22,7 +22,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.net.IConnectivityManager;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.net.NetworkInfo;
@@ -32,7 +31,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
-import android.os.ServiceManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
@@ -40,6 +38,9 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.telephony.DataConnection.FailCause;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
import java.util.ArrayList;
import java.util.HashMap;
@@ -91,38 +92,39 @@ public abstract class DataConnectionTracker extends Handler {
public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
/***** Event Codes *****/
- protected static final int EVENT_DATA_SETUP_COMPLETE = 1;
- protected static final int EVENT_RADIO_AVAILABLE = 3;
- protected static final int EVENT_RECORDS_LOADED = 4;
- protected static final int EVENT_TRY_SETUP_DATA = 5;
- protected static final int EVENT_DATA_STATE_CHANGED = 6;
- protected static final int EVENT_POLL_PDP = 7;
- protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
- protected static final int EVENT_VOICE_CALL_STARTED = 14;
- protected static final int EVENT_VOICE_CALL_ENDED = 15;
- protected static final int EVENT_DATA_CONNECTION_DETACHED = 19;
- protected static final int EVENT_LINK_STATE_CHANGED = 20;
- protected static final int EVENT_ROAMING_ON = 21;
- protected static final int EVENT_ROAMING_OFF = 22;
- protected static final int EVENT_ENABLE_NEW_APN = 23;
- protected static final int EVENT_RESTORE_DEFAULT_APN = 24;
- protected static final int EVENT_DISCONNECT_DONE = 25;
- protected static final int EVENT_DATA_CONNECTION_ATTACHED = 26;
- protected static final int EVENT_START_NETSTAT_POLL = 27;
- protected static final int EVENT_START_RECOVERY = 28;
- protected static final int EVENT_APN_CHANGED = 29;
- protected static final int EVENT_CDMA_DATA_DETACHED = 30;
- protected static final int EVENT_NV_READY = 31;
- protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
- protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
- public static final int EVENT_CLEAN_UP_CONNECTION = 34;
- protected static final int EVENT_CDMA_OTA_PROVISION = 35;
- protected static final int EVENT_RESTART_RADIO = 36;
- protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = 37;
- protected static final int EVENT_RESET_DONE = 38;
- public static final int CMD_SET_DATA_ENABLE = 39;
- public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = 40;
- public static final int CMD_SET_DEPENDENCY_MET = 41;
+ protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER;
+ protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0;
+ protected static final int EVENT_RADIO_AVAILABLE = BASE + 1;
+ protected static final int EVENT_RECORDS_LOADED = BASE + 2;
+ protected static final int EVENT_TRY_SETUP_DATA = BASE + 3;
+ protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
+ protected static final int EVENT_POLL_PDP = BASE + 5;
+ protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
+ protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
+ protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
+ protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
+ protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
+ protected static final int EVENT_ROAMING_ON = BASE + 11;
+ protected static final int EVENT_ROAMING_OFF = BASE + 12;
+ protected static final int EVENT_ENABLE_NEW_APN = BASE + 13;
+ protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
+ protected static final int EVENT_DISCONNECT_DONE = BASE + 15;
+ protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
+ protected static final int EVENT_START_NETSTAT_POLL = BASE + 17;
+ protected static final int EVENT_START_RECOVERY = BASE + 18;
+ protected static final int EVENT_APN_CHANGED = BASE + 19;
+ protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
+ protected static final int EVENT_NV_READY = BASE + 21;
+ protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
+ protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
+ public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
+ protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
+ protected static final int EVENT_RESTART_RADIO = BASE + 26;
+ protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
+ protected static final int EVENT_RESET_DONE = BASE + 28;
+ public static final int CMD_SET_DATA_ENABLE = BASE + 29;
+ public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
+ public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
/***** Constants *****/
@@ -201,6 +203,19 @@ public abstract class DataConnectionTracker extends Handler {
// getActionIntentReconnectAlarm.
protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
+ // Used for debugging. Send the INTENT with an optional counter value with the number
+ // of times the setup is to fail before succeeding. If the counter isn't passed the
+ // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
+ // adb shell am broadcast \
+ // -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
+ // --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
+ protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
+ "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
+ protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
+ protected int mFailDataSetupCounter = 0;
+ protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
+ protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
+
// member variables
protected PhoneBase mPhone;
protected Activity mActivity = Activity.NONE;
@@ -227,7 +242,7 @@ public abstract class DataConnectionTracker extends Handler {
/** indication of our availability (preconditions to trysetupData are met) **/
protected boolean mAvailability = false;
- // When false we will not auto attach and manully attaching is required.
+ // When false we will not auto attach and manually attaching is required.
protected boolean mAutoAttachOnCreation = false;
// State of screen
@@ -235,12 +250,6 @@ public abstract class DataConnectionTracker extends Handler {
// really a lower power mode")
protected boolean mIsScreenOn = true;
- /** The link properties (dns, gateway, ip, etc) */
- protected LinkProperties mLinkProperties = new LinkProperties();
-
- /** The link capabilities */
- protected LinkCapabilities mLinkCapabilities = new LinkCapabilities();
-
/** Allows the generation of unique Id's for DataConnection objects */
protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
@@ -248,6 +257,10 @@ public abstract class DataConnectionTracker extends Handler {
protected HashMap<Integer, DataConnection> mDataConnections =
new HashMap<Integer, DataConnection>();
+ /** The data connection async channels */
+ protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
+ new HashMap<Integer, DataConnectionAc>();
+
/** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
protected HashMap<String, Integer> mApnToDataConnectionId =
new HashMap<String, Integer>();
@@ -267,7 +280,6 @@ public abstract class DataConnectionTracker extends Handler {
/** Is packet service restricted by network */
protected boolean mIsPsRestricted = false;
-
/* Once disposed dont handle any messages */
protected boolean mIsDisposed = false;
@@ -277,6 +289,7 @@ public abstract class DataConnectionTracker extends Handler {
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
+ if (DBG) log("onReceive: action=" + action);
if (action.equals(Intent.ACTION_SCREEN_ON)) {
mIsScreenOn = true;
stopNetStatPoll();
@@ -302,10 +315,36 @@ public abstract class DataConnectionTracker extends Handler {
// quit and won't report disconnected until next enabling.
mIsWifiConnected = false;
}
+ } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
+ mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
+ mFailDataSetupFailCause = FailCause.fromInt(
+ intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
+ FailCause.ERROR_UNSPECIFIED.getErrorCode()));
+ if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
+ " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
}
}
};
+ protected boolean isDataSetupCompleteOk(AsyncResult ar) {
+ if (ar.exception != null) {
+ if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
+ return false;
+ }
+ if (mFailDataSetupCounter <= 0) {
+ if (DBG) log("isDataSetupCompleteOk return true");
+ return true;
+ }
+ ar.result = mFailDataSetupFailCause;
+ if (DBG) {
+ log("isDataSetupCompleteOk return false" +
+ " mFailDataSetupCounter=" + mFailDataSetupCounter +
+ " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
+ }
+ mFailDataSetupCounter -= 1;
+ return false;
+ }
+
protected void onActionIntentReconnectAlarm(Intent intent) {
String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
if (mState == State.FAILED) {
@@ -331,6 +370,7 @@ public abstract class DataConnectionTracker extends Handler {
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
mDataEnabled = Settings.Secure.getInt(mPhone.getContext().getContentResolver(),
Settings.Secure.MOBILE_DATA, 1) == 1;
@@ -351,6 +391,10 @@ public abstract class DataConnectionTracker extends Handler {
}
public void dispose() {
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ dcac.disconnect();
+ }
+ mDataConnectionAsyncChannels.clear();
mIsDisposed = true;
mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
}
@@ -463,7 +507,13 @@ public abstract class DataConnectionTracker extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
-
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ log("DISCONNECTED_CONNECTED: msg=" + msg);
+ DataConnectionAc dcac = (DataConnectionAc) msg.obj;
+ mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
+ dcac.disconnected();
+ break;
+ }
case EVENT_ENABLE_NEW_APN:
onEnableApn(msg.arg1, msg.arg2);
break;
@@ -528,19 +578,20 @@ public abstract class DataConnectionTracker extends Handler {
break;
}
case EVENT_RESET_DONE: {
+ if (DBG) log("EVENT_RESET_DONE");
onResetDone((AsyncResult) msg.obj);
break;
}
case CMD_SET_DATA_ENABLE: {
- log("CMD_SET_DATA_ENABLE msg=" + msg);
boolean enabled = (msg.arg1 == ENABLED) ? true : false;
+ if (DBG) log("CMD_SET_DATA_ENABLE enabled=" + enabled);
onSetDataEnabled(enabled);
break;
}
case CMD_SET_DEPENDENCY_MET: {
- log("CMD_SET_DEPENDENCY_MET msg=" + msg);
boolean met = (msg.arg1 == ENABLED) ? true : false;
+ if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
Bundle bundle = msg.getData();
if (bundle != null) {
String apnType = (String)bundle.get(APN_TYPE_KEY);
@@ -552,7 +603,7 @@ public abstract class DataConnectionTracker extends Handler {
}
default:
- Log.e("DATA", "Unidentified event = " + msg.what);
+ Log.e("DATA", "Unidentified event msg=" + msg);
break;
}
}
@@ -618,7 +669,8 @@ public abstract class DataConnectionTracker extends Handler {
protected LinkProperties getLinkProperties(String apnType) {
int id = apnTypeToId(apnType);
if (isApnIdEnabled(id)) {
- return new LinkProperties(mLinkProperties);
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(id);
+ return dcac.getLinkPropertiesSync();
} else {
return new LinkProperties();
}
@@ -627,33 +679,13 @@ public abstract class DataConnectionTracker extends Handler {
protected LinkCapabilities getLinkCapabilities(String apnType) {
int id = apnTypeToId(apnType);
if (isApnIdEnabled(id)) {
- return new LinkCapabilities(mLinkCapabilities);
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(id);
+ return dcac.getLinkCapabilitiesSync();
} else {
return new LinkCapabilities();
}
}
- /**
- * Return the LinkProperties for the connection.
- *
- * @param connection
- * @return a copy of the LinkProperties, is never null.
- */
- protected LinkProperties getLinkProperties(DataConnection connection) {
- return connection.getLinkProperties();
- }
-
- /**
- * A capability is an Integer/String pair, the capabilities
- * are defined in the class LinkSocket#Key.
- *
- * @param connection
- * @return a copy of this connections capabilities, may be empty but never null.
- */
- protected LinkCapabilities getLinkCapabilities(DataConnection connection) {
- return connection.getLinkCapabilities();
- }
-
// tell all active apns of the current condition
protected void notifyDataConnection(String reason) {
for (int id = 0; id < APN_NUM_TYPES; id++) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index e299d4a8b8a1..d55f3461ec7e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -20,7 +20,6 @@ import android.os.Message;
import android.util.Log;
import com.android.internal.telephony.DataConnection;
-import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.RetryManager;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index dc8501709cce..2f783e8e2455 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -37,10 +37,12 @@ import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.Phone;
+import com.android.internal.util.AsyncChannel;
import java.util.ArrayList;
@@ -52,9 +54,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
private CDMAPhone mCdmaPhone;
- //useful for debugging
- boolean mFailNextConnect = false;
-
/** The DataConnection being setup */
private CdmaDataConnection mPendingDataConnection;
@@ -297,14 +296,18 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
boolean notificationDeferred = false;
for (DataConnection conn : mDataConnections.values()) {
if(conn != null) {
+ DataConnectionAc dcac =
+ mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
if (tearDown) {
if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
- conn.disconnect(reason, obtainMessage(EVENT_DISCONNECT_DONE,
+ conn.tearDown(reason, obtainMessage(EVENT_DISCONNECT_DONE,
conn.getDataConnectionId(), 0, reason));
notificationDeferred = true;
} else {
if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously");
- conn.resetSynchronously();
+ if (dcac != null) {
+ dcac.resetSync();
+ }
notificationDeferred = false;
}
}
@@ -319,11 +322,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
}
private CdmaDataConnection findFreeDataConnection() {
- for (DataConnection dc : mDataConnections.values()) {
- if (dc.isInactive()) {
- return (CdmaDataConnection) dc;
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ if (dcac.isInactiveSync()) {
+ log("found free GsmDataConnection");
+ return (CdmaDataConnection) dcac.dataConnection;
}
}
+ log("NO free CdmaDataConnection");
return null;
}
@@ -349,12 +354,12 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
}
mActiveApn = new ApnSetting(apnId, "", "", "", "", "", "", "", "", "",
"", 0, types, "IP", "IP");
- if (DBG) log("setupData: mActiveApn=" + mActiveApn);
+ if (DBG) log("call conn.bringUp mActiveApn=" + mActiveApn);
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = reason;
- conn.connect(msg, mActiveApn);
+ conn.bringUp(msg, mActiveApn);
setState(State.INITING);
notifyDataConnection(reason);
@@ -652,12 +657,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
reason = (String) ar.userObj;
}
- if (ar.exception == null) {
- // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
- mLinkProperties = getLinkProperties(mPendingDataConnection);
- mLinkCapabilities = getLinkCapabilities(mPendingDataConnection);
-
- // everything is setup
+ if (isDataSetupCompleteOk(ar)) {
+ // Everything is setup
notifyDefaultData(reason);
} else {
FailCause cause = (FailCause) (ar.result);
@@ -767,6 +768,16 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
int id = mUniqueIdGenerator.getAndIncrement();
dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm);
mDataConnections.put(id, dataConn);
+ DataConnectionAc dcac = new DataConnectionAc(dataConn, LOG_TAG);
+ int status = dcac.fullyConnectSync(mPhone.getContext(), this, dataConn.getHandler());
+ if (status == AsyncChannel.STATUS_SUCCESSFUL) {
+ log("Fully connected");
+ mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
+ } else {
+ log("Could not connect to dcac.dataConnection=" + dcac.dataConnection +
+ " status=" + status);
+ }
+
}
}
@@ -897,6 +908,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
@Override
public void handleMessage (Message msg) {
+ if (DBG) log("CdmaDCT handleMessage msg=" + msg);
if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
log("Ignore CDMA msgs since CDMA phone is inactive");
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 545ad8af6b3c..96953444c87a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -21,7 +21,6 @@ import android.util.Log;
import android.util.Patterns;
import android.text.TextUtils;
-import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 8e675fc3f4f9..69a815373601 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -53,6 +53,7 @@ import com.android.internal.telephony.ApnContext;
import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
@@ -60,6 +61,7 @@ import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.DataConnection.FailCause;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.util.AsyncChannel;
import java.io.IOException;
import java.net.InetAddress;
@@ -102,9 +104,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
/** Delay between APN attempts */
protected static final int APN_DELAY_MILLIS = 5000;
- //useful for debugging
- boolean mFailNextConnect = false;
-
//***** Constants
private static final int POLL_PDP_MILLIS = 5 * 1000;
@@ -119,7 +118,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected void onActionIntentReconnectAlarm(Intent intent) {
- log("GPRS reconnect alarm. Previous state was " + mState);
+ if (DBG) log("GPRS reconnect alarm. Previous state was " + mState);
String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
String type = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
@@ -224,7 +223,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
boolean possible = (isDataAllowed()
&& !(getAnyDataEnabled() && (getOverallState() == State.FAILED)));
if (!possible && DBG && isDataAllowed()) {
- log("Data not possible. No coverage: dataState = " + getOverallState());
+ if (DBG) log("Data not possible. No coverage: dataState = " + getOverallState());
}
return possible;
}
@@ -319,10 +318,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected LinkProperties getLinkProperties(String apnType) {
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext != null) {
- DataConnection dataConnection = apnContext.getDataConnection();
- if (dataConnection != null) {
- if (DBG) log("get active pdp is not null, return link properites for " + apnType);
- return dataConnection.getLinkProperties();
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac != null) {
+ if (DBG) log("return link properites for " + apnType);
+ return dcac.getLinkPropertiesSync();
}
}
if (DBG) log("return new LinkProperties");
@@ -333,10 +332,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected LinkCapabilities getLinkCapabilities(String apnType) {
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext!=null) {
- DataConnection dataConnection = apnContext.getDataConnection();
- if (dataConnection != null) {
+ DataConnectionAc dataConnectionAc = apnContext.getDataConnectionAc();
+ if (dataConnectionAc != null) {
if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType);
- return dataConnection.getLinkCapabilities();
+ return dataConnectionAc.getLinkCapabilitiesSync();
}
}
if (DBG) log("return new LinkCapabilities");
@@ -424,6 +423,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
if (!isAnyEnabled) { // Nothing enabled. return IDLE.
+ if (DBG) log( "overall state is IDLE");
return State.IDLE;
}
@@ -450,34 +450,34 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
*/
@Override
public synchronized int enableApnType(String apnType) {
- if (DBG) log("calling enableApnType with type:" + apnType);
-
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext == null || !isApnTypeAvailable(apnType)) {
- if (DBG) log("type not available");
+ if (DBG) log("enableApnType: " + apnType + " is type not available");
return Phone.APN_TYPE_NOT_AVAILABLE;
}
// If already active, return
- log("enableApnType(" + apnType + ")" + ", mState(" + apnContext.getState() + ")");
+ if (DBG) log("enableApnType: " + apnType + " mState(" + apnContext.getState() + ")");
if (apnContext.getState() == State.INITING) {
- if (DBG) log("return APN_REQUEST_STARTED");
+ if (DBG) log("enableApnType: return APN_REQUEST_STARTED");
return Phone.APN_REQUEST_STARTED;
}
else if (apnContext.getState() == State.CONNECTED) {
- if (DBG) log("return APN_ALREADY_ACTIVE");
+ if (DBG) log("enableApnType: return APN_ALREADY_ACTIVE");
return Phone.APN_ALREADY_ACTIVE;
}
else if (apnContext.getState() == State.DISCONNECTING) {
- if (DBG) log("requested APN while disconnecting");
+ if (DBG) log("enableApnType: while disconnecting, return APN_REQUEST_STARTED");
apnContext.setPendingAction(ApnContext.PENDING_ACTION_RECONNECT);
return Phone.APN_REQUEST_STARTED;
}
- if (DBG) log("new apn request for type " + apnType + " is to be handled");
setEnabled(apnTypeToId(apnType), true);
- if (DBG) log("return APN_REQUEST_STARTED");
+ if (DBG) {
+ log("enableApnType: new apn request for type " + apnType +
+ " return APN_REQUEST_STARTED");
+ }
return Phone.APN_REQUEST_STARTED;
}
@@ -502,7 +502,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
public synchronized int disableApnType(String type) {
- if (DBG) log("calling disableApnType with type:" + type);
+ if (DBG) log("disableApnType:" + type);
ApnContext apnContext = mApnContexts.get(type);
if (apnContext != null) {
@@ -515,18 +515,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
apnContext.setReason(Phone.REASON_DATA_DISABLED);
msg.obj = apnContext;
sendMessage(msg);
- if (DBG) log("return APN_REQUEST_STARTED");
+ if (DBG) log("diableApnType: return APN_REQUEST_STARTED");
return Phone.APN_REQUEST_STARTED;
} else {
- if (DBG) log("return APN_ALREADY_INACTIVE");
+ if (DBG) log("disableApnType: return APN_ALREADY_INACTIVE");
apnContext.setEnabled(false);
apnContext.setDataConnection(null);
return Phone.APN_ALREADY_INACTIVE;
}
} else {
- if (DBG)
- log("no apn context was found, return APN_REQUEST_FAILED");
+ if (DBG) {
+ log("disableApnType: no apn context was found, return APN_REQUEST_FAILED");
+ }
return Phone.APN_REQUEST_FAILED;
}
}
@@ -583,12 +584,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* We presently believe it is unnecessary to tear down the PDP context
* when GPRS detaches, but we should stop the network polling.
*/
+ if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
stopNetStatPoll();
notifyDataConnection(Phone.REASON_DATA_DETACHED);
}
private void onDataConnectionAttached() {
+ if (DBG) log("onDataConnectionAttached");
if (getOverallState() == State.CONNECTED) {
+ if (DBG) log("onDataConnectionAttached: start polling notify attached");
startNetStatPoll();
notifyDataConnection(Phone.REASON_DATA_ATTACHED);
}
@@ -624,11 +628,40 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
if (!desiredPowerState) reason += " - desiredPowerState= false";
- log("Data not allowed due to" + reason);
+ if (DBG) log("isDataAllowed: not allowed due to" + reason);
}
return allowed;
}
+ /**
+ * Release the apnContext
+ *
+ * @param apnContext
+ * @param tearDown
+ * @return refCount
+ */
+ private int releaseApnContext(ApnContext apnContext, boolean tearDown) {
+ if (apnContext == null) {
+ if (DBG) loge("releaseApnContext: apnContext null should not happen, ignore");
+ return -1;
+ }
+ DataConnection dc = apnContext.getDataConnection();
+ if (dc == null) {
+ if (DBG) loge("releaseApnContext: apnContext dc == null should not happen, ignore");
+ return -1;
+ }
+ int refCount = dc.decAndGetRefCount();
+ if (DBG) log("releaseApnContext: dec refCount=" + refCount + " tearDown=" + tearDown);
+ if (tearDown && (refCount == 0)) {
+ if (DBG) log("releaseApnContext: tearing down");
+ Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
+ apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
+ }
+ apnContext.setDataConnection(null);
+ apnContext.setDataConnectionAc(null);
+ return refCount;
+ }
+
private void setupDataOnReadyApns(String reason) {
// Only check for default APN state
for (ApnContext apnContext : mApnContexts.values()) {
@@ -651,9 +684,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private boolean trySetupData(String reason, String type) {
if (DBG) {
- log("***trySetupData for type:" + type +
- " due to " + (reason == null ? "(unspecified)" : reason) +
- " isPsRestricted=" + mIsPsRestricted);
+ log("trySetupData: " + type + " due to " + (reason == null ? "(unspecified)" : reason)
+ + " isPsRestricted=" + mIsPsRestricted);
}
if (type == null) {
@@ -663,18 +695,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
ApnContext apnContext = mApnContexts.get(type);
if (apnContext == null ){
- if (DBG) log("new apn context for type:" + type);
+ if (DBG) log("trySetupData new apn context for type:" + type);
apnContext = new ApnContext(type, LOG_TAG);
mApnContexts.put(type, apnContext);
}
apnContext.setReason(reason);
return trySetupData(apnContext);
-
}
private boolean trySetupData(ApnContext apnContext) {
-
if (DBG) {
log("trySetupData for type:" + apnContext.getApnType() +
" due to " + apnContext.getReason());
@@ -687,7 +717,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
apnContext.setState(State.CONNECTED);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
- log("(fix?) We're on the simulator; assuming data is connected");
+ log("trySetupData: (fix?) We're on the simulator; assuming data is connected");
return true;
}
@@ -699,13 +729,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (apnContext.getState() == State.IDLE) {
ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());
if (waitingApns.isEmpty()) {
- if (DBG) log("No APN found");
+ if (DBG) log("trySetupData: No APN found");
notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN, apnContext);
notifyOffApnsOfAvailability(apnContext.getReason(), false);
return false;
} else {
apnContext.setWaitingApns(waitingApns);
- log ("Create from mAllApns : " + apnListToString(mAllApns));
+ if (DBG) {
+ log ("trySetupData: Create from mAllApns : " + apnListToString(mAllApns));
+ }
}
}
@@ -735,7 +767,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
for (ApnContext apnContext : mApnContexts.values()) {
if (!apnContext.isReady()) {
- if (DBG) log("notify disconnected for type:" + apnContext.getApnType());
+ if (DBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
apnContext.getApnType(),
Phone.DataState.DISCONNECTED);
@@ -753,7 +785,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* @param reason reason for the clean up.
*/
protected void cleanUpAllConnections(boolean tearDown, String reason) {
- if (DBG) log("Clean up all connections due to " + reason);
+ if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
for (ApnContext apnContext : mApnContexts.values()) {
apnContext.setReason(reason);
@@ -784,11 +816,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
if (apnContext == null) {
- if (DBG) log("apn context is null");
+ if (DBG) log("cleanUpConnection: apn context is null");
return;
}
- if (DBG) log("Clean up connection due to " + apnContext.getReason());
+ if (DBG) {
+ log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
+ }
// Clear the reconnect alarm, if set.
if (apnContext.getReconnectIntent() != null) {
@@ -799,24 +833,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
if (apnContext.getState() == State.IDLE || apnContext.getState() == State.DISCONNECTING) {
- if (DBG) log("state is in " + apnContext.getState());
+ if (DBG) log("cleanUpConnection: state= " + apnContext.getState());
return;
}
if (apnContext.getState() == State.FAILED) {
- if (DBG) log("state is in FAILED");
+ if (DBG) log("cleanUpConnection: state is in FAILED");
apnContext.setState(State.IDLE);
return;
}
DataConnection conn = apnContext.getDataConnection();
if (conn != null) {
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(conn.getDataConnectionId());
apnContext.setState(State.DISCONNECTING);
if (tearDown) {
- Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
- conn.disconnect(apnContext.getReason(), msg);
+ releaseApnContext(apnContext, tearDown);
} else {
- conn.resetSynchronously();
+ if (dcac != null) {
+ dcac.resetSync();
+ }
apnContext.setState(State.IDLE);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
}
@@ -871,27 +907,31 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
private GsmDataConnection findFreeDataConnection() {
- for (DataConnection dc : mDataConnections.values()) {
- if (dc.isInactive()) {
- log("found free GsmDataConnection");
- return (GsmDataConnection) dc;
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ if (dcac.isInactiveSync()) {
+ log("findFreeDataConnection: found free GsmDataConnection");
+ return (GsmDataConnection) dcac.dataConnection;
}
}
- log("NO free GsmDataConnection");
+ log("findFreeDataConnection: NO free GsmDataConnection");
return null;
}
protected GsmDataConnection findReadyDataConnection(ApnSetting apn) {
if (DBG)
- log("findReadyDataConnection for apn string <" +
+ log("findReadyDataConnection: apn string <" +
(apn!=null?(apn.toString()):"null") +">");
- for (DataConnection conn : mDataConnections.values()) {
- GsmDataConnection dc = (GsmDataConnection) conn;
- if (DBG) log("dc apn string <" +
- (dc.getApn() != null ? (dc.getApn().toString()) : "null") + ">");
- if (dc.getApn() != null && apn != null
- && dc.getApn().toString().equals(apn.toString())) {
- return dc;
+ if (apn == null) {
+ return null;
+ }
+ for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
+ ApnSetting apnSetting = dcac.getApnSettingSync();
+ if (DBG) {
+ log("findReadyDataConnection: dc apn string <" +
+ (apnSetting != null ? (apnSetting.toString()) : "null") + ">");
+ }
+ if ((apnSetting != null) && TextUtils.equals(apnSetting.toString(), apn.toString())) {
+ return (GsmDataConnection) dcac.dataConnection;
}
}
return null;
@@ -899,7 +939,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private boolean setupData(ApnContext apnContext) {
- if (DBG) log("enter setupData!");
+ if (DBG) log("setupData: apnContext=" + apnContext);
ApnSetting apn;
GsmDataConnection dc;
@@ -920,7 +960,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
if (dc == null) {
- dc = createDataConnection(apnContext);
+ dc = createDataConnection(apnContext.getApnType());
}
if (dc == null) {
@@ -928,17 +968,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return false;
}
- apnContext.setApnSetting(apn);
- apnContext.setDataConnection(dc);
dc.setProfileId( profileId );
dc.setActiveApnType(apnContext.getApnType());
+ int refCount = dc.incAndGetRefCount();
+ if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
+ DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
+ apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId()));
+ apnContext.setApnSetting(apn);
+ apnContext.setDataConnection(dc);
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = apnContext;
-
- if (DBG) log("dc connect!");
- dc.connect(msg, apn);
+ dc.bringUp(msg, apn);
apnContext.setState(State.INITING);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -981,7 +1023,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// TODO: It'd be nice to only do this if the changed entrie(s)
// match the current operator.
- if (DBG) log("onApnChanged createAllApnList and cleanUpAllConnections");
+ if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
createAllApnList();
cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
@@ -998,25 +1040,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private void onDataStateChanged (AsyncResult ar) {
ArrayList<DataCallState> dataCallStates;
+ if (DBG) log("onDataStateChanged(ar) E");
dataCallStates = (ArrayList<DataCallState>)(ar.result);
if (ar.exception != null) {
// This is probably "radio not available" or something
// of that sort. If so, the whole connection is going
// to come down soon anyway
+ if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore");
return;
}
for (ApnContext apnContext : mApnContexts.values()) {
onDataStateChanged(dataCallStates, apnContext);
}
+ if (DBG) log("onDataStateChanged(ar) X");
}
private void onDataStateChanged (ArrayList<DataCallState> dataCallStates,
ApnContext apnContext) {
+ if (DBG) log("onDataStateChanged(dataCallState, apnContext): apnContext=" + apnContext);
if (apnContext == null) {
// Should not happen
+ if (DBG) log("onDataStateChanged(dataCallState, apnContext): ignore apnContext=null");
return;
}
@@ -1027,28 +1074,37 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// context is still listed with active = false, which
// makes it hard to distinguish an activating context from
// an activated-and-then deactivated one.
- if (!dataCallStatesHasCID(dataCallStates, apnContext.getDataConnection().getCid())) {
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac == null) {
+ if (DBG) log("onDataStateChanged(dataCallState, apnContext): dcac==null BAD NEWS");
+ return;
+ }
+ int cid = dcac.getCidSync();
+ if (!dataCallStatesHasCID(dataCallStates, cid)) {
// It looks like the PDP context has deactivated.
// Tear everything down and try to reconnect.
- Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
-
+ if (DBG) {
+ log("onDataStateChanged(dataCallStates,apnContext) " +
+ "PDP connection has dropped. Reconnecting");
+ }
// Add an event log when the network drops PDP
- int cid = getCellLocationId();
- EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
+ int cellLocationId = getCellLocationId();
+ EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
TelephonyManager.getDefault().getNetworkType());
cleanUpConnection(true, apnContext);
- return;
} else if (!dataCallStatesHasActiveCID(dataCallStates,
- apnContext.getDataConnection().getCid())) {
+ apnContext.getDataConnectionAc().getCidSync())) {
- Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
- + " Reconnecting");
+ if (DBG) {
+ log("onDataStateChanged(dataCallStates,apnContext) " +
+ "PDP connection has dropped (active=false case). Reconnecting");
+ }
// Log the network drop on the event log.
- int cid = getCellLocationId();
- EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
+ int cellLocationId = getCellLocationId();
+ EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
TelephonyManager.getDefault().getNetworkType());
cleanUpConnection(true, apnContext);
@@ -1057,9 +1113,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
private void notifyDefaultData(ApnContext apnContext) {
- if (DBG)
- log("notifyDefaultData for type: " + apnContext.getApnType()
+ if (DBG) {
+ log("notifyDefaultData: type=" + apnContext.getApnType()
+ ", reason:" + apnContext.getReason());
+ }
apnContext.setState(State.CONNECTED);
// setState(State.CONNECTED);
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -1091,21 +1148,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (mPdpResetCount < maxPdpReset) {
mPdpResetCount++;
EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv);
+ if (DBG) log("doRecovery() cleanup all connections mPdpResetCount < max");
cleanUpAllConnections(true, Phone.REASON_PDP_RESET);
} else {
mPdpResetCount = 0;
EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv);
+ if (DBG) log("doRecovery() re-register getting preferred network type");
mPhone.getServiceStateTracker().reRegisterNetwork(null);
}
// TODO: Add increasingly drastic recovery steps, eg,
// reset the radio, reset the device.
+ } else {
+ if (DBG) log("doRecovery(): ignore, we're not connected");
}
}
@Override
protected void startNetStatPoll() {
if (getOverallState() == State.CONNECTED && mNetStatPollEnabled == false) {
- log("[DataConnection] Start poll NetStat");
+ if (DBG) log("startNetStatPoll");
resetPollStats();
mNetStatPollEnabled = true;
mPollNetStat.run();
@@ -1116,12 +1177,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected void stopNetStatPoll() {
mNetStatPollEnabled = false;
removeCallbacks(mPollNetStat);
- log("[DataConnection] Stop poll NetStat");
+ if (DBG) log("stopNetStatPoll");
}
@Override
protected void restartRadio() {
- log("************TURN OFF RADIO**************");
+ if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
mPhone.getServiceStateTracker().powerOffRadioSafely(this);
/* Note: no need to call setRadioPower(true). Assuming the desired
@@ -1202,7 +1263,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (mNoRecvPollCount < noRecvPollLimit) {
// It's possible the PDP context went down and we weren't notified.
// Start polling the context list in an attempt to recover.
- if (DBG) log("no DATAIN in a while; polling PDP");
+ if (DBG) log("Polling: no DATAIN in a while; polling PDP");
mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED));
mNoRecvPollCount++;
@@ -1212,7 +1273,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
POLL_NETSTAT_SLOW_MILLIS);
} else {
- if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) +
+ if (DBG) log("Polling: Sent " + String.valueOf(mSentSinceLastRecv) +
" pkts since last received start recovery process");
stopNetStatPoll();
sendMessage(obtainMessage(EVENT_START_RECOVERY));
@@ -1262,14 +1323,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private void reconnectAfterFail(FailCause lastFailCauseCode, ApnContext apnContext) {
if (apnContext == null) {
- Log.d(LOG_TAG, "It is impossible");
+ loge("reconnectAfterFail: apnContext == null, impossible");
return;
}
if (apnContext.getState() == State.FAILED) {
if (!apnContext.getDataConnection().isRetryNeeded()) {
- if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)){
- // if no more retries on a secondary APN attempt, tell the world and revert.
- apnContext.setDataConnection(null);
+ if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
notifyDataConnection(Phone.REASON_APN_FAILED);
return;
}
@@ -1278,7 +1337,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
apnContext.getDataConnection().retryForeverUsingLastTimeout();
} else {
// Try to Re-register to the network.
- log("PDP activate failed, Reregistering to the network");
+ if (DBG) log("reconnectAfterFail: activate failed, Reregistering to network");
mReregisterOnReconnectFailure = true;
mPhone.getServiceStateTracker().reRegisterNetwork(null);
apnContext.getDataConnection().resetRetryCount();
@@ -1287,8 +1346,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
- log("PDP activate failed. Scheduling next attempt for "
+ if (DBG) {
+ log("reconnectAfterFail: activate failed. Scheduling next attempt for "
+ (nextReconnectDelay / 1000) + "s");
+ }
AlarmManager am =
(AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
@@ -1305,8 +1366,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
apnContext.getDataConnection().increaseRetryCount();
if (!shouldPostNotification(lastFailCauseCode)) {
- Log.d(LOG_TAG, "NOT Posting GPRS Unavailable notification "
+ if (DBG) {
+ log("reconnectAfterFail: NOT Posting GPRS Unavailable notification "
+ "-- likely transient error");
+ }
} else {
notifyNoData(lastFailCauseCode, apnContext);
}
@@ -1315,7 +1378,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode,
ApnContext apnContext) {
- if (DBG) log( "notifyNoData for type:" + apnContext.getApnType());
+ if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
apnContext.setState(State.FAILED);
if (lastFailCauseCode.isPermanentFail()
&& (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT))) {
@@ -1327,7 +1390,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (DBG) log("onRecordsLoaded: createAllApnList");
createAllApnList();
if (mRadioAvailable) {
- if (DBG) log("onRecordsLoaded, notifying data availability");
+ if (DBG) log("onRecordsLoaded: notifying data availability");
notifyDataAvailability(null);
}
setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
@@ -1337,7 +1400,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected void onSetDependencyMet(String apnType, boolean met) {
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext == null) {
- log("ApnContext not found in onSetDependencyMet(" + apnType + ", " + met + ")");
+ loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
+ apnType + ", " + met + ")");
return;
}
applyNewState(apnContext, apnContext.isEnabled(), met);
@@ -1373,12 +1437,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
trySetup = true;
} else {
- // TODO send notifications
+ int refCount = conn.incAndGetRefCount();
+ apnContext.setDataConnection(conn);
+ apnContext.setDataConnectionAc(
+ mDataConnectionAsyncChannels.get(conn.getDataConnectionId()));
if (DBG) {
- log("Found existing connection for " + apnContext.getApnType() +
- ": " + conn);
+ log("applyNewState: Found existing connection for " +
+ apnContext.getApnType() + " inc refCount=" + refCount +
+ " conn=" + conn);
}
- apnContext.setDataConnection(conn);
}
}
}
@@ -1395,9 +1462,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
DataConnection conn = c.getDataConnection();
if (conn != null) {
ApnSetting apnSetting = c.getApnSetting();
- if (apnSetting != null && apnSetting.canHandleType(apnType)) return conn;
+ if (apnSetting != null && apnSetting.canHandleType(apnType)) {
+ if (DBG) {
+ log("checkForConnectionForApnContext: apnContext=" + apnContext +
+ " found conn=" + conn);
+ }
+ return conn;
+ }
}
}
+ if (DBG) log("checkForConnectionForApnContext: apnContext=" + apnContext + " NO conn");
return null;
}
@@ -1405,43 +1479,47 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected void onEnableApn(int apnId, int enabled) {
ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
if (apnContext == null) {
- log("ApnContext not found in onEnableApn(" + apnId + ", " + enabled + ")");
+ loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
return;
}
// TODO change our retry manager to use the appropriate numbers for the new APN
- log("onEnableApn with ApnContext E");
+ if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
applyNewState(apnContext, enabled == ENABLED, apnContext.getDependencyMet());
}
@Override
// TODO: We shouldnt need this.
protected boolean onTrySetupData(String reason) {
+ if (DBG) log("onTrySetupData: reason=" + reason);
setupDataOnReadyApns(reason);
return true;
}
protected boolean onTrySetupData(ApnContext apnContext) {
+ if (DBG) log("onTrySetupData: apnContext=" + apnContext);
return trySetupData(apnContext);
}
@Override
protected void onRoamingOff() {
+ if (DBG) log("onRoamingOff");
setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
}
@Override
protected void onRoamingOn() {
if (getDataOnRoamingEnabled()) {
+ if (DBG) log("onRoamingOn: setup data on roaming");
setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
} else {
- if (DBG) log("Tear down data connection on roaming.");
+ if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
}
}
@Override
protected void onRadioAvailable() {
-
+ if (DBG) log("onRadioAvailable");
mRadioAvailable = true;
if (mPhone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
@@ -1449,7 +1527,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// setState(State.CONNECTED);
notifyDataConnection(null);
- log("We're on the simulator; assuming data is connected");
+ log("onRadioAvailable: We're on the simulator; assuming data is connected");
}
if (mPhone.mSIMRecords.getRecordsLoaded()) {
@@ -1477,7 +1555,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// FIXME this can be improved
log("We're on the simulator; assuming radio off is meaningless");
} else {
- if (DBG) log("Radio is off and clean up all connection");
+ if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
}
notifyDataAvailability(null);
@@ -1490,27 +1568,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if(ar.userObj instanceof ApnContext){
apnContext = (ApnContext)ar.userObj;
+ } else {
+ throw new RuntimeException("onDataSetupComplete: No apnContext");
}
- if (ar.exception == null) {
- // Everything is setup
- // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected
+ if (isDataSetupCompleteOk(ar)) {
+ DataConnectionAc dcac = apnContext.getDataConnectionAc();
+ if (dcac == null) {
+ throw new RuntimeException("onDataSetupCompete: No dcac");
+ }
+ DataConnection dc = apnContext.getDataConnection();
+
if (DBG) {
log(String.format("onDataSetupComplete: success apn=%s",
- apnContext.getWaitingApns().get(0).apn));
+ apnContext.getWaitingApns().get(0).apn) + " refCount=" + dc.getRefCount());
}
- mLinkProperties = getLinkProperties(apnContext.getApnType());
- mLinkCapabilities = getLinkCapabilities(apnContext.getApnType());
-
ApnSetting apn = apnContext.getApnSetting();
if (apn.proxy != null && apn.proxy.length() != 0) {
try {
ProxyProperties proxy = new ProxyProperties(apn.proxy,
Integer.parseInt(apn.port), null);
- mLinkProperties.setHttpProxy(proxy);
+ dcac.setLinkPropertiesHttpProxySync(proxy);
} catch (NumberFormatException e) {
- loge("NumberFormatException making ProxyProperties (" + apn.port +
- "): " + e);
+ loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +
+ apn.port + "): " + e);
}
}
@@ -1518,7 +1599,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if(TextUtils.equals(apnContext.getApnType(),Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && mPreferredApn == null) {
- log("PREFERED APN is null");
+ if (DBG) log("onDataSetupComplete: PREFERED APN is null");
mPreferredApn = apnContext.getApnSetting();
if (mPreferredApn != null) {
setPreferredApn(mPreferredApn.id);
@@ -1528,19 +1609,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
SystemProperties.set("gsm.defaultpdpcontext.active", "false");
}
notifyDefaultData(apnContext);
-
- // TODO: For simultaneous PDP support, we need to build another
- // trigger another TRY_SETUP_DATA for the next APN type. (Note
- // that the existing connection may service that type, in which
- // case we should try the next type, etc.
- // I dont believe for simultaneous PDP you need to trigger. Each
- // Connection should be independent and they can be setup simultaneously
- // So, dont have to wait till one is finished.
} else {
- GsmDataConnection.FailCause cause;
- cause = (GsmDataConnection.FailCause) (ar.result);
+ String apnString;
+ DataConnection.FailCause cause;
+
+ cause = (DataConnection.FailCause) (ar.result);
if (DBG) {
- String apnString;
try {
apnString = apnContext.getWaitingApns().get(0).apn;
} catch (Exception e) {
@@ -1573,7 +1647,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
}
apnContext.setState(State.FAILED);
- apnContext.setDataConnection(null);
notifyDataConnection(Phone.REASON_APN_FAILED);
} else {
if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
@@ -1587,6 +1660,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext),
APN_DELAY_MILLIS);
}
+
+ int refCount = releaseApnContext(apnContext, false);
+ if (DBG) {
+ log("onDataSetupComplete: error apn=%s" + apnString + " refCount=" + refCount);
+ }
}
}
@@ -1597,7 +1675,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected void onDisconnectDone(int connId, AsyncResult ar) {
ApnContext apnContext = null;
- if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId);
+ if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE connId=" + connId);
if (ar.userObj instanceof ApnContext) {
apnContext = (ApnContext) ar.userObj;
} else {
@@ -1610,9 +1688,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// Check if APN disabled.
if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
- apnContext.setEnabled(false);
apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
- apnContext.setDataConnection(null);
}
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
@@ -1648,7 +1724,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected void onVoiceCallStarted() {
+ if (DBG) log("onVoiceCallStarted");
if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
+ if (DBG) log("onVoiceCallStarted stop polling");
stopNetStatPoll();
notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
}
@@ -1656,6 +1734,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected void onVoiceCallEnded() {
+ if (DBG) log("onVoiceCallEnded");
if (isConnected()) {
if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
startNetStatPoll();
@@ -1688,10 +1767,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected void notifyDataConnection(String reason) {
- if (DBG) log("notify all enabled connection for:" + reason);
+ if (DBG) log("notifyDataConnection: reason=" + reason);
for (ApnContext apnContext : mApnContexts.values()) {
if (apnContext.isReady()) {
- if (DBG) log("notify for type:"+apnContext.getApnType());
+ if (DBG) log("notifyDataConnection: type:"+apnContext.getApnType());
mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
apnContext.getApnType());
}
@@ -1738,17 +1817,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
/** Return the id for a new data connection */
- private GsmDataConnection createDataConnection(ApnContext apnContext) {
- String apnType = apnContext.getApnType();
- log("createDataConnection(" + apnType + ") E");
+ private GsmDataConnection createDataConnection(String apnType) {
+ if (DBG) log("createDataConnection(" + apnType + ") E");
RetryManager rm = new RetryManager();
if (apnType.equals(Phone.APN_TYPE_DEFAULT)) {
if (!rm.configure(SystemProperties.get("ro.gsm.data_retry_config"))) {
if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) {
// Should never happen, log an error and default to a simple linear sequence.
- log("Could not configure using DEFAULT_DATA_RETRY_CONFIG="
- + DEFAULT_DATA_RETRY_CONFIG);
+ loge("createDataConnection: Could not configure using " +
+ "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
rm.configure(20, 2000, 1000);
}
}
@@ -1756,8 +1834,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (!rm.configure(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) {
if (!rm.configure(SECONDARY_DATA_RETRY_CONFIG)) {
// Should never happen, log an error and default to a simple sequence.
- log("Could note configure using SECONDARY_DATA_RETRY_CONFIG="
- + SECONDARY_DATA_RETRY_CONFIG);
+ loge("createDataConnection: Could note configure using " +
+ "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
rm.configure("max_retries=3, 333, 333, 333");
}
}
@@ -1767,18 +1845,25 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
GsmDataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm);
conn.resetRetryCount();
mDataConnections.put(id, conn);
- apnContext.setDataConnection(conn);
+ DataConnectionAc dcac = new DataConnectionAc(conn, LOG_TAG);
+ int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
+ if (status == AsyncChannel.STATUS_SUCCESSFUL) {
+ mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
+ } else {
+ loge("createDataConnection: Could not connect to dcac.mDc=" + dcac.dataConnection +
+ " status=" + status);
+ }
- log("createDataConnection(" + apnType + ") X id=" + id);
+ if (DBG) log("createDataConnection(" + apnType + ") X id=" + id);
return conn;
}
private void destroyDataConnections() {
if(mDataConnections != null) {
- log("destroyDataConnectionList clear mDataConnectionList");
+ if (DBG) log("destroyDataConnections: clear mDataConnectionList");
mDataConnections.clear();
} else {
- log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
+ if (DBG) log("destroyDataConnectionList mDataConnecitonList is empty, ignore");
}
}
@@ -1802,8 +1887,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
String operator = mPhone.mSIMRecords.getSIMOperatorNumeric();
if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
if (canSetPreferApn && mPreferredApn != null) {
- log("Preferred APN:" + operator + ":"
+ if (DBG) {
+ log("buildWaitingApns: Preferred APN:" + operator + ":"
+ mPreferredApn.numeric + ":" + mPreferredApn);
+ }
if (mPreferredApn.numeric.equals(operator)) {
apnList.add(mPreferredApn);
if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
@@ -1894,10 +1981,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
public void handleMessage (Message msg) {
- if (DBG) log("GSMDataConnTrack handleMessage "+msg);
+ if (DBG) log("handleMessage msg=" + msg);
if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
- log("Ignore GSM msgs since GSM phone is inactive");
+ loge("handleMessage: Ignore GSM msgs since GSM phone is inactive");
return;
}
@@ -1941,7 +2028,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* PDP context and notify us with PDP_CONTEXT_CHANGED.
* But we should stop the network polling and prevent reset PDP.
*/
- log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
+ if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
stopNetStatPoll();
mIsPsRestricted = true;
break;
@@ -1951,7 +2038,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* When PS restrict is removed, we need setup PDP connection if
* PDP connection is down.
*/
- log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
+ if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
mIsPsRestricted = false;
if (isConnected()) {
startNetStatPoll();
@@ -1968,19 +2055,20 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
case EVENT_TRY_SETUP_DATA:
if (msg.obj instanceof ApnContext) {
onTrySetupData((ApnContext)msg.obj);
+ } else if (msg.obj instanceof String) {
+ onTrySetupData((String)msg.obj);
} else {
- if (msg.obj instanceof String) {
- onTrySetupData((String)msg.obj);
- }
+ loge("EVENT_TRY_SETUP request w/o apnContext or String");
}
break;
case EVENT_CLEAN_UP_CONNECTION:
boolean tearDown = (msg.arg1 == 0) ? false : true;
+ if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
if (msg.obj instanceof ApnContext) {
cleanUpConnection(tearDown, (ApnContext)msg.obj);
} else {
- loge("[GsmDataConnectionTracker] connectpion cleanup request w/o apn context");
+ loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context");
}
break;
default:
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c5c3f708b0d0..6285880a2260 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -37,6 +37,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="GLTextureViewActivity"
+ android:label="_TextureViewGL">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<activity
android:name="BitmapMeshActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
new file mode 100644
index 000000000000..7f970989bb4b
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2011 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.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLES20;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class GLTextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
+ private RenderThread mRenderThread;
+ private TextureView mTextureView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mRenderThread.finish();
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ mRenderThread = new RenderThread(surface);
+ mRenderThread.start();
+
+ mTextureView.setCameraDistance(5000);
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+ animator.setRepeatMode(ObjectAnimator.REVERSE);
+ animator.setRepeatCount(ObjectAnimator.INFINITE);
+ animator.setDuration(4000);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ ((View) mTextureView.getParent()).invalidate();
+ }
+ });
+ animator.start();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ }
+
+ private static class RenderThread extends Thread {
+ private static final String LOG_TAG = "GLTextureView";
+
+ static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ static final int EGL_SURFACE_TYPE = 0x3033;
+ static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
+ static final int EGL_OPENGL_ES2_BIT = 4;
+
+ private volatile boolean mFinished;
+
+ private SurfaceTexture mSurface;
+
+ private EGL10 mEgl;
+ private EGLDisplay mEglDisplay;
+ private EGLConfig mEglConfig;
+ private EGLContext mEglContext;
+ private EGLSurface mEglSurface;
+ private GL mGL;
+
+ RenderThread(SurfaceTexture surface) {
+ mSurface = surface;
+ }
+
+ @Override
+ public void run() {
+ initGL();
+
+ float red = 0.0f;
+ while (!mFinished) {
+ checkCurrent();
+
+ GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f);
+ int error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+ }
+
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+ }
+
+ if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+ throw new RuntimeException("Cannot swap buffers");
+ }
+
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+
+ red += 0.021f;
+ if (red > 1.0f) red = 0.0f;
+ }
+
+ finishGL();
+ }
+
+ private void finishGL() {
+ mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ }
+
+ private void checkCurrent() {
+ if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
+ !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed "
+ + getEGLErrorString(mEgl.eglGetError()));
+ }
+ }
+ }
+
+ private void initGL() {
+ mEgl = (EGL10) EGLContext.getEGL();
+
+ mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new RuntimeException("eglGetDisplay failed "
+ + getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ int[] version = new int[2];
+ if (!mEgl.eglInitialize(mEglDisplay, version)) {
+ throw new RuntimeException("eglInitialize failed " +
+ getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ mEglConfig = chooseEglConfig();
+ if (mEglConfig == null) {
+ throw new RuntimeException("eglConfig not initialized");
+ }
+
+ mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+ mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null);
+
+ if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+ int error = mEgl.eglGetError();
+ if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+ Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ return;
+ }
+ throw new RuntimeException("createWindowSurface failed "
+ + getEGLErrorString(error));
+ }
+
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed "
+ + getEGLErrorString(mEgl.eglGetError()));
+ }
+
+ mGL = mEglContext.getGL();
+ }
+
+
+ EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+ int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ }
+
+ private EGLConfig chooseEglConfig() {
+ int[] configsCount = new int[1];
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] configSpec = getConfig();
+ if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+ throw new IllegalArgumentException("eglChooseConfig failed " +
+ getEGLErrorString(mEgl.eglGetError()));
+ } else if (configsCount[0] > 0) {
+ return configs[0];
+ }
+ return null;
+ }
+
+ private int[] getConfig() {
+ return new int[] {
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_ALPHA_SIZE, 8,
+ EGL10.EGL_DEPTH_SIZE, 0,
+ EGL10.EGL_STENCIL_SIZE, 0,
+ EGL10.EGL_NONE
+ };
+ }
+
+ static String getEGLErrorString(int error) {
+ switch (error) {
+ case EGL10.EGL_SUCCESS:
+ return "EGL_SUCCESS";
+ case EGL10.EGL_NOT_INITIALIZED:
+ return "EGL_NOT_INITIALIZED";
+ case EGL10.EGL_BAD_ACCESS:
+ return "EGL_BAD_ACCESS";
+ case EGL10.EGL_BAD_ALLOC:
+ return "EGL_BAD_ALLOC";
+ case EGL10.EGL_BAD_ATTRIBUTE:
+ return "EGL_BAD_ATTRIBUTE";
+ case EGL10.EGL_BAD_CONFIG:
+ return "EGL_BAD_CONFIG";
+ case EGL10.EGL_BAD_CONTEXT:
+ return "EGL_BAD_CONTEXT";
+ case EGL10.EGL_BAD_CURRENT_SURFACE:
+ return "EGL_BAD_CURRENT_SURFACE";
+ case EGL10.EGL_BAD_DISPLAY:
+ return "EGL_BAD_DISPLAY";
+ case EGL10.EGL_BAD_MATCH:
+ return "EGL_BAD_MATCH";
+ case EGL10.EGL_BAD_NATIVE_PIXMAP:
+ return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL10.EGL_BAD_NATIVE_WINDOW:
+ return "EGL_BAD_NATIVE_WINDOW";
+ case EGL10.EGL_BAD_PARAMETER:
+ return "EGL_BAD_PARAMETER";
+ case EGL10.EGL_BAD_SURFACE:
+ return "EGL_BAD_SURFACE";
+ case EGL11.EGL_CONTEXT_LOST:
+ return "EGL_CONTEXT_LOST";
+ default:
+ return "0x" + Integer.toHexString(error);
+ }
+ }
+
+ void finish() {
+ mFinished = true;
+ }
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
index 55fab3f10ca9..7173a85f73e7 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/Lines2Activity.java
@@ -86,6 +86,14 @@ public class Lines2Activity extends Activity {
canvas.drawLines(copyPoints, 0, 12, p);
}
+ private void drawVerticalLine(Canvas canvas, Paint p, float length, float x, float y) {
+ canvas.drawLine(x, y, x, y + length, p);
+ }
+
+ private void drawDiagonalLine(Canvas canvas, Paint p, float length, float x, float y) {
+ canvas.drawLine(x, y, x + length, y + length, p);
+ }
+
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -145,6 +153,99 @@ public class Lines2Activity extends Activity {
canvas.translate(60, 0);
drawLines(canvas, p, mOffset/2, yOffset/2);
canvas.restore();
+
+ yOffset += 100;
+ canvas.save();
+ p.setStrokeWidth(1);
+ float x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ p.setAntiAlias(true);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ }
+ p.setStrokeWidth(5);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ p.setAntiAlias(true);
+ drawVerticalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ }
+ canvas.restore();
+
+ yOffset += 20;
+ canvas.save();
+ p.setStrokeWidth(1);
+ x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ p.setAntiAlias(true);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 5;
+ }
+ p.setStrokeWidth(2);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ p.setAntiAlias(true);
+ drawDiagonalLine(canvas, p, length, x, yOffset);
+ x += 10;
+ }
+ canvas.restore();
+
+ yOffset += 20;
+ canvas.save();
+ p.setStrokeWidth(1);
+ x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 5;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 5;
+ }
+ p.setStrokeWidth(2);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 10;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + 1, yOffset + length, p);
+ x += 10;
+ }
+ canvas.restore();
+
+ yOffset += 20;
+ canvas.save();
+ p.setStrokeWidth(1);
+ x = 10 + mOffset;
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 5;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 5;
+ }
+ p.setStrokeWidth(2);
+ for (float length = 1; length <= 10; length +=1 ) {
+ p.setAntiAlias(false);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 10;
+ p.setAntiAlias(true);
+ canvas.drawLine(x, yOffset, x + length, yOffset + 1, p);
+ x += 10;
+ }
+ canvas.restore();
+
}
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index 4726672cad84..2feda57a1351 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -84,4 +84,9 @@ public class TextureViewActivity extends Activity implements TextureView.Surface
animator.setDuration(4000);
animator.start();
}
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ // Ignored, the Camera does all the work for us
+ }
}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
index f2f9a361fa90..16ebe08a11c7 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/threshold.rs
@@ -63,7 +63,7 @@ static void computeGaussianWeights() {
static void copyInput() {
rs_allocation ain;
- rsSetObject(&ain,rsGetAllocation(InPixel));
+ ain = rsGetAllocation(InPixel);
uint32_t dimx = rsAllocationGetDimX(ain);
uint32_t dimy = rsAllocationGetDimY(ain);
for (uint32_t y = 0; y < dimy; y++) {
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index bf0c93e846b8..198e3f82134b 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -115,11 +115,11 @@ static void setupOffscreenTarget() {
static void displayFontSamples(int fillNum) {
rs_font fonts[5];
- rsSetObject(&fonts[0], gFontSans);
- rsSetObject(&fonts[1], gFontSerif);
- rsSetObject(&fonts[2], gFontSerifBold);
- rsSetObject(&fonts[3], gFontSerifBoldItalic);
- rsSetObject(&fonts[4], gFontSans);
+ fonts[0] = gFontSans;
+ fonts[1] = gFontSerif;
+ fonts[2] = gFontSerifBold;
+ fonts[3] = gFontSerifBoldItalic;
+ fonts[4] = gFontSans;
uint width = gRenderSurfaceW;
uint height = gRenderSurfaceH;
@@ -146,10 +146,6 @@ static void displayFontSamples(int fillNum) {
}
}
}
-
- for (int i = 0; i < 5; i ++) {
- rsClearObject(&fonts[i]);
- }
}
static void bindProgramVertexOrtho() {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
index aeae13ff1331..d8663fb54199 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/rslist.rs
@@ -47,7 +47,7 @@ int root(void) {
rsgBindFont(gFont);
rs_allocation listAlloc;
- rsSetObject(&listAlloc, rsGetAllocation(gList));
+ listAlloc = rsGetAllocation(gList);
int allocSize = rsAllocationGetDimX(listAlloc);
int width = rsgGetWidth();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
index f3bf2448a4f6..22d9c1382024 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/rstypes.rs
@@ -48,17 +48,17 @@ static bool basic_test(uint32_t index) {
struct my_struct structTest;
- rsSetObject(&fontTestLocal, fontTest);
+ fontTestLocal = fontTest;
//allocationTestLocal = allocationTest;
- rsSetObject(&fontTest, fontTestLocal);
+ fontTest = fontTestLocal;
//allocationTest = allocationTestLocal;
/*for (int i = 0; i < 4; i++) {
- rsSetObject(&fontTestLocalArray[i], fontTestLocal);
+ fontTestLocalArray[i] = fontTestLocal;
}*/
- /*rsSetObject(&fontTest, fontTestLocalArray[3]);*/
+ /*fontTest = fontTestLocalArray[3];*/
return failed;
}
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index 6455d8486f51..7f9fc31b5fed 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -23,6 +23,7 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
import android.net.ProxyProperties;
+import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration.IpAssignment;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.ProxySettings;
@@ -120,7 +121,7 @@ class WifiConfigStore {
private static final String ipConfigFile = Environment.getDataDirectory() +
"/misc/wifi/ipconfig.txt";
- private static final int IPCONFIG_FILE_VERSION = 1;
+ private static final int IPCONFIG_FILE_VERSION = 2;
/* IP and proxy configuration keys */
private static final String ID_KEY = "id";
@@ -445,9 +446,8 @@ class WifiConfigStore {
if (iter.hasNext()) {
LinkAddress linkAddress = iter.next();
dhcpInfoInternal.ipAddress = linkAddress.getAddress().getHostAddress();
- Iterator<InetAddress>gateways = linkProperties.getGateways().iterator();
- if (gateways.hasNext()) {
- dhcpInfoInternal.gateway = gateways.next().getHostAddress();
+ for (RouteInfo route : linkProperties.getRoutes()) {
+ dhcpInfoInternal.addRoute(route);
}
dhcpInfoInternal.prefixLength = linkAddress.getNetworkPrefixLength();
Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator();
@@ -604,9 +604,22 @@ class WifiConfigStore {
out.writeUTF(linkAddr.getAddress().getHostAddress());
out.writeInt(linkAddr.getNetworkPrefixLength());
}
- for (InetAddress gateway : linkProperties.getGateways()) {
+ for (RouteInfo route : linkProperties.getRoutes()) {
out.writeUTF(GATEWAY_KEY);
- out.writeUTF(gateway.getHostAddress());
+ LinkAddress dest = route.getDestination();
+ if (dest != null) {
+ out.writeInt(1);
+ out.writeUTF(dest.getAddress().getHostAddress());
+ out.writeInt(dest.getNetworkPrefixLength());
+ } else {
+ out.writeInt(0);
+ }
+ if (route.getGateway() != null) {
+ out.writeInt(1);
+ out.writeUTF(route.getGateway().getHostAddress());
+ } else {
+ out.writeInt(0);
+ }
}
for (InetAddress inetAddr : linkProperties.getDnses()) {
out.writeUTF(DNS_KEY);
@@ -682,7 +695,8 @@ class WifiConfigStore {
in = new DataInputStream(new BufferedInputStream(new FileInputStream(
ipConfigFile)));
- if (in.readInt() != IPCONFIG_FILE_VERSION) {
+ int version = in.readInt();
+ if (version != 2 && version != 1) {
Log.e(TAG, "Bad version on IP configuration file, ignore read");
return;
}
@@ -709,8 +723,22 @@ class WifiConfigStore {
NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
linkProperties.addLinkAddress(linkAddr);
} else if (key.equals(GATEWAY_KEY)) {
- linkProperties.addGateway(
- NetworkUtils.numericToInetAddress(in.readUTF()));
+ LinkAddress dest = null;
+ InetAddress gateway = null;
+ if (version == 1) {
+ // only supported default gateways - leave the dest/prefix empty
+ gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+ } else {
+ if (in.readInt() == 1) {
+ dest = new LinkAddress(
+ NetworkUtils.numericToInetAddress(in.readUTF()),
+ in.readInt());
+ }
+ if (in.readInt() == 1) {
+ gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+ }
+ }
+ linkProperties.addRoute(new RouteInfo(dest, gateway));
} else if (key.equals(DNS_KEY)) {
linkProperties.addDns(
NetworkUtils.numericToInetAddress(in.readUTF()));
@@ -1022,22 +1050,21 @@ class WifiConfigStore {
.getLinkAddresses();
Collection<InetAddress> currentDnses = currentConfig.linkProperties.getDnses();
Collection<InetAddress> newDnses = newConfig.linkProperties.getDnses();
- Collection<InetAddress> currentGateways =
- currentConfig.linkProperties.getGateways();
- Collection<InetAddress> newGateways = newConfig.linkProperties.getGateways();
+ Collection<RouteInfo> currentRoutes = currentConfig.linkProperties.getRoutes();
+ Collection<RouteInfo> newRoutes = newConfig.linkProperties.getRoutes();
boolean linkAddressesDiffer =
(currentLinkAddresses.size() != newLinkAddresses.size()) ||
!currentLinkAddresses.containsAll(newLinkAddresses);
boolean dnsesDiffer = (currentDnses.size() != newDnses.size()) ||
!currentDnses.containsAll(newDnses);
- boolean gatewaysDiffer = (currentGateways.size() != newGateways.size()) ||
- !currentGateways.containsAll(newGateways);
+ boolean routesDiffer = (currentRoutes.size() != newRoutes.size()) ||
+ !currentRoutes.containsAll(newRoutes);
if ((currentConfig.ipAssignment != newConfig.ipAssignment) ||
linkAddressesDiffer ||
dnsesDiffer ||
- gatewaysDiffer) {
+ routesDiffer) {
ipChanged = true;
}
break;
@@ -1112,8 +1139,8 @@ class WifiConfigStore {
for (LinkAddress linkAddr : config.linkProperties.getLinkAddresses()) {
linkProperties.addLinkAddress(linkAddr);
}
- for (InetAddress gateway : config.linkProperties.getGateways()) {
- linkProperties.addGateway(gateway);
+ for (RouteInfo route : config.linkProperties.getRoutes()) {
+ linkProperties.addRoute(route);
}
for (InetAddress dns : config.linkProperties.getDnses()) {
linkProperties.addDns(dns);
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 33d4e1fc489b..91250375f2c9 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -48,6 +48,7 @@ import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.DhcpInfoInternal;
+import android.net.DhcpStateMachine;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -152,6 +153,7 @@ public class WifiStateMachine extends StateMachine {
private NetworkInfo mNetworkInfo;
private SupplicantStateTracker mSupplicantStateTracker;
private WpsStateMachine mWpsStateMachine;
+ private DhcpStateMachine mDhcpStateMachine;
private AlarmManager mAlarmManager;
private PendingIntent mScanIntent;
@@ -189,10 +191,10 @@ public class WifiStateMachine extends StateMachine {
static final int CMD_START_DRIVER = BASE + 13;
/* Start the driver */
static final int CMD_STOP_DRIVER = BASE + 14;
- /* Indicates DHCP succeded */
- static final int CMD_IP_CONFIG_SUCCESS = BASE + 15;
- /* Indicates DHCP failed */
- static final int CMD_IP_CONFIG_FAILURE = BASE + 16;
+ /* Indicates Static IP succeded */
+ static final int CMD_STATIC_IP_SUCCESS = BASE + 15;
+ /* Indicates Static IP failed */
+ static final int CMD_STATIC_IP_FAILURE = BASE + 16;
/* Start the soft access point */
static final int CMD_START_AP = BASE + 21;
@@ -338,8 +340,11 @@ public class WifiStateMachine extends StateMachine {
*/
private static final int DEFAULT_MAX_DHCP_RETRIES = 9;
- private static final int POWER_MODE_ACTIVE = 1;
- private static final int POWER_MODE_AUTO = 0;
+ static final int POWER_MODE_ACTIVE = 1;
+ static final int POWER_MODE_AUTO = 0;
+
+ /* Tracks the power mode for restoration after a DHCP request/renewal goes through */
+ private int mPowerMode = POWER_MODE_AUTO;
/**
* Default framework scan interval in milliseconds. This is used in the scenario in which
@@ -1408,8 +1413,10 @@ public class WifiStateMachine extends StateMachine {
*/
NetworkUtils.resetConnections(mInterfaceName);
- if (!NetworkUtils.stopDhcp(mInterfaceName)) {
- Log.e(TAG, "Could not stop DHCP");
+ if (mDhcpStateMachine != null) {
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
+ mDhcpStateMachine.quit();
+ mDhcpStateMachine = null;
}
/* Disable interface */
@@ -1435,6 +1442,100 @@ public class WifiStateMachine extends StateMachine {
}
+ void handlePreDhcpSetup() {
+ if (!mBluetoothConnectionActive) {
+ /*
+ * There are problems setting the Wi-Fi driver's power
+ * mode to active when bluetooth coexistence mode is
+ * enabled or sense.
+ * <p>
+ * We set Wi-Fi to active mode when
+ * obtaining an IP address because we've found
+ * compatibility issues with some routers with low power
+ * mode.
+ * <p>
+ * In order for this active power mode to properly be set,
+ * we disable coexistence mode until we're done with
+ * obtaining an IP address. One exception is if we
+ * are currently connected to a headset, since disabling
+ * coexistence would interrupt that connection.
+ */
+ // Disable the coexistence mode
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
+ }
+
+ mPowerMode = WifiNative.getPowerModeCommand();
+ if (mPowerMode < 0) {
+ // Handle the case where supplicant driver does not support
+ // getPowerModeCommand.
+ mPowerMode = WifiStateMachine.POWER_MODE_AUTO;
+ }
+ if (mPowerMode != WifiStateMachine.POWER_MODE_ACTIVE) {
+ WifiNative.setPowerModeCommand(WifiStateMachine.POWER_MODE_ACTIVE);
+ }
+ }
+
+
+ void handlePostDhcpSetup() {
+ /* restore power mode */
+ WifiNative.setPowerModeCommand(mPowerMode);
+
+ // Set the coexistence mode back to its default value
+ WifiNative.setBluetoothCoexistenceModeCommand(
+ WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
+ }
+
+ private void handleSuccessfulIpConfiguration(DhcpInfoInternal dhcpInfoInternal) {
+ synchronized (mDhcpInfoInternal) {
+ mDhcpInfoInternal = dhcpInfoInternal;
+ }
+ mLastSignalLevel = -1; // force update of signal strength
+ WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
+ InetAddress addr = NetworkUtils.numericToInetAddress(dhcpInfoInternal.ipAddress);
+ mWifiInfo.setInetAddress(addr);
+ if (getNetworkDetailedState() == DetailedState.CONNECTED) {
+ //DHCP renewal in connected state
+ LinkProperties linkProperties = dhcpInfoInternal.makeLinkProperties();
+ linkProperties.setHttpProxy(WifiConfigStore.getProxyProperties(mLastNetworkId));
+ linkProperties.setInterfaceName(mInterfaceName);
+ if (!linkProperties.equals(mLinkProperties)) {
+ Log.d(TAG, "Link configuration changed for netId: " + mLastNetworkId
+ + " old: " + mLinkProperties + "new: " + linkProperties);
+ NetworkUtils.resetConnections(mInterfaceName);
+ mLinkProperties = linkProperties;
+ sendLinkConfigurationChangedBroadcast();
+ }
+ } else {
+ configureLinkProperties();
+ setNetworkDetailedState(DetailedState.CONNECTED);
+ sendNetworkStateChangeBroadcast(mLastBssid);
+ }
+ }
+
+ private void handleFailedIpConfiguration() {
+ Log.e(TAG, "IP configuration failed");
+
+ mWifiInfo.setInetAddress(null);
+ /**
+ * If we've exceeded the maximum number of retries for DHCP
+ * to a given network, disable the network
+ */
+ if (++mReconnectCount > getMaxDhcpRetries()) {
+ Log.e(TAG, "Failed " +
+ mReconnectCount + " times, Disabling " + mLastNetworkId);
+ WifiConfigStore.disableNetwork(mLastNetworkId);
+ mReconnectCount = 0;
+ }
+
+ /* DHCP times out after about 30 seconds, we do a
+ * disconnect and an immediate reconnect to try again
+ */
+ WifiNative.disconnectCommand();
+ WifiNative.reconnectCommand();
+
+ }
+
/*********************************************************
* Notifications from WifiMonitor
@@ -1606,6 +1707,8 @@ public class WifiStateMachine extends StateMachine {
case CMD_FORGET_NETWORK:
case CMD_RSSI_POLL:
case CMD_ENABLE_ALL_NETWORKS:
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
break;
case CMD_START_WPS:
/* Return failure when the state machine cannot handle WPS initiation*/
@@ -2483,74 +2586,18 @@ public class WifiStateMachine extends StateMachine {
}
class ConnectingState extends State {
- boolean mModifiedBluetoothCoexistenceMode;
- int mPowerMode;
- boolean mUseStaticIp;
- Thread mDhcpThread;
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
- mUseStaticIp = WifiConfigStore.isUsingStaticIp(mLastNetworkId);
- if (!mUseStaticIp) {
- mDhcpThread = null;
- mModifiedBluetoothCoexistenceMode = false;
- mPowerMode = POWER_MODE_AUTO;
-
- if (!mBluetoothConnectionActive) {
- /*
- * There are problems setting the Wi-Fi driver's power
- * mode to active when bluetooth coexistence mode is
- * enabled or sense.
- * <p>
- * We set Wi-Fi to active mode when
- * obtaining an IP address because we've found
- * compatibility issues with some routers with low power
- * mode.
- * <p>
- * In order for this active power mode to properly be set,
- * we disable coexistence mode until we're done with
- * obtaining an IP address. One exception is if we
- * are currently connected to a headset, since disabling
- * coexistence would interrupt that connection.
- */
- mModifiedBluetoothCoexistenceMode = true;
-
- // Disable the coexistence mode
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED);
- }
-
- mPowerMode = WifiNative.getPowerModeCommand();
- if (mPowerMode < 0) {
- // Handle the case where supplicant driver does not support
- // getPowerModeCommand.
- mPowerMode = POWER_MODE_AUTO;
- }
- if (mPowerMode != POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(POWER_MODE_ACTIVE);
- }
- Log.d(TAG, "DHCP request started");
- mDhcpThread = new Thread(new Runnable() {
- public void run() {
- DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
- if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) {
- Log.d(TAG, "DHCP request succeeded");
- synchronized (mDhcpInfoInternal) {
- mDhcpInfoInternal = dhcpInfoInternal;
- }
- WifiConfigStore.setIpConfiguration(mLastNetworkId, dhcpInfoInternal);
- sendMessage(CMD_IP_CONFIG_SUCCESS);
- } else {
- Log.d(TAG, "DHCP request failed: " +
- NetworkUtils.getDhcpError());
- sendMessage(CMD_IP_CONFIG_FAILURE);
- }
- }
- });
- mDhcpThread.start();
+ if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+ //start DHCP
+ mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
+ mContext, WifiStateMachine.this, mInterfaceName);
+ mDhcpStateMachine.registerForPreDhcpNotification();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);
} else {
DhcpInfoInternal dhcpInfoInternal = WifiConfigStore.getIpConfiguration(
mLastNetworkId);
@@ -2562,16 +2609,13 @@ public class WifiStateMachine extends StateMachine {
try {
netd.setInterfaceConfig(mInterfaceName, ifcg);
Log.v(TAG, "Static IP configuration succeeded");
- synchronized (mDhcpInfoInternal) {
- mDhcpInfoInternal = dhcpInfoInternal;
- }
- sendMessage(CMD_IP_CONFIG_SUCCESS);
+ sendMessage(CMD_STATIC_IP_SUCCESS, dhcpInfoInternal);
} catch (RemoteException re) {
Log.v(TAG, "Static IP configuration failed: " + re);
- sendMessage(CMD_IP_CONFIG_FAILURE);
+ sendMessage(CMD_STATIC_IP_FAILURE);
} catch (IllegalStateException e) {
Log.v(TAG, "Static IP configuration failed: " + e);
- sendMessage(CMD_IP_CONFIG_FAILURE);
+ sendMessage(CMD_STATIC_IP_FAILURE);
}
}
}
@@ -2580,44 +2624,26 @@ public class WifiStateMachine extends StateMachine {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
switch(message.what) {
- case CMD_IP_CONFIG_SUCCESS:
- mLastSignalLevel = -1; // force update of signal strength
- InetAddress addr;
- synchronized (mDhcpInfoInternal) {
- addr = NetworkUtils.numericToInetAddress(mDhcpInfoInternal.ipAddress);
- }
- mWifiInfo.setInetAddress(addr);
- configureLinkProperties();
- if (getNetworkDetailedState() == DetailedState.CONNECTED) {
- sendLinkConfigurationChangedBroadcast();
- } else {
- setNetworkDetailedState(DetailedState.CONNECTED);
- sendNetworkStateChangeBroadcast(mLastBssid);
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ handlePreDhcpSetup();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ break;
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ handlePostDhcpSetup();
+ if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+ transitionTo(mConnectedState);
+ } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+ handleFailedIpConfiguration();
+ transitionTo(mDisconnectingState);
}
- //TODO: The framework is not detecting a DHCP renewal and a possible
- //IP change. we should detect this and send out a config change broadcast
+ break;
+ case CMD_STATIC_IP_SUCCESS:
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
transitionTo(mConnectedState);
break;
- case CMD_IP_CONFIG_FAILURE:
- mWifiInfo.setInetAddress(null);
-
- Log.e(TAG, "IP configuration failed");
- /**
- * If we've exceeded the maximum number of retries for DHCP
- * to a given network, disable the network
- */
- if (++mReconnectCount > getMaxDhcpRetries()) {
- Log.e(TAG, "Failed " +
- mReconnectCount + " times, Disabling " + mLastNetworkId);
- WifiConfigStore.disableNetwork(mLastNetworkId);
- mReconnectCount = 0;
- }
-
- /* DHCP times out after about 30 seconds, we do a
- * disconnect and an immediate reconnect to try again
- */
- WifiNative.disconnectCommand();
- WifiNative.reconnectCommand();
+ case CMD_STATIC_IP_FAILURE:
+ handleFailedIpConfiguration();
transitionTo(mDisconnectingState);
break;
case CMD_DISCONNECT:
@@ -2661,23 +2687,6 @@ public class WifiStateMachine extends StateMachine {
EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
-
- @Override
- public void exit() {
- /* reset power state & bluetooth coexistence if on DHCP */
- if (!mUseStaticIp) {
- if (mPowerMode != POWER_MODE_ACTIVE) {
- WifiNative.setPowerModeCommand(mPowerMode);
- }
-
- if (mModifiedBluetoothCoexistenceMode) {
- // Set the coexistence mode back to its default value
- WifiNative.setBluetoothCoexistenceModeCommand(
- WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
- }
- }
-
- }
}
class ConnectedState extends State {
@@ -2695,6 +2704,19 @@ public class WifiStateMachine extends StateMachine {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
boolean eventLoggingEnabled = true;
switch (message.what) {
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ handlePreDhcpSetup();
+ mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE);
+ break;
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ handlePostDhcpSetup();
+ if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS) {
+ handleSuccessfulIpConfiguration((DhcpInfoInternal) message.obj);
+ } else if (message.arg1 == DhcpStateMachine.DHCP_FAILURE) {
+ handleFailedIpConfiguration();
+ transitionTo(mDisconnectingState);
+ }
+ break;
case CMD_DISCONNECT:
WifiNative.disconnectCommand();
transitionTo(mDisconnectingState);