diff options
69 files changed, 2703 insertions, 1156 deletions
diff --git a/Android.mk b/Android.mk index b6f2504740df..b1f43f8e6f2a 100644 --- a/Android.mk +++ b/Android.mk @@ -121,6 +121,7 @@ LOCAL_SRC_FILES += \ core/java/android/os/storage/IMountService.aidl \ core/java/android/os/storage/IMountServiceListener.aidl \ core/java/android/os/storage/IMountShutdownObserver.aidl \ + core/java/android/os/storage/IObbActionListener.aidl \ core/java/android/os/INetworkManagementService.aidl \ core/java/android/os/INetStatService.aidl \ core/java/android/os/IPermissionController.aidl \ diff --git a/api/current.xml b/api/current.xml index 841aa2166abb..65a8a8ee7b2c 100644 --- a/api/current.xml +++ b/api/current.xml @@ -26460,6 +26460,17 @@ <parameter name="holder" type="android.view.SurfaceHolder"> </parameter> </method> +<field name="KEY_NATIVE_SAVED_STATE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android:native_state"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="META_DATA_LIB_NAME" type="java.lang.String" transient="false" @@ -129520,6 +129531,8 @@ > <parameter name="filename" type="java.lang.String"> </parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> </method> <method name="mountObb" return="boolean" @@ -129550,6 +129563,8 @@ </parameter> <parameter name="force" type="boolean"> </parameter> +<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException"> +</exception> </method> </class> </package> diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java index eaf06757b6f7..4dc88b31f1d9 100644 --- a/core/java/android/app/NativeActivity.java +++ b/core/java/android/app/NativeActivity.java @@ -10,6 +10,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; +import android.content.res.Configuration; import android.graphics.PixelFormat; import android.os.Build; import android.os.Bundle; @@ -32,12 +33,27 @@ import java.lang.ref.WeakReference; /** * Convenience for implementing an activity that will be implemented - * purely in native code. That is, a game (or game-like thing). + * purely in native code. That is, a game (or game-like thing). There + * is no need to derive from this class; you can simply declare it in your + * manifest, and use the NDK APIs from there. + * + * <p>A typical manifest would look like: + * + * {@sample development/ndk/platforms/android-9/samples/native-activity/AndroidManifest.xml + * manifest} + * + * <p>A very simple example of native code that is run by NativeActivity + * follows. This reads input events from the user and uses OpenGLES to + * draw into the native activity's window. + * + * {@sample development/ndk/platforms/android-9/samples/native-activity/jni/main.c all} */ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, InputQueue.Callback, OnGlobalLayoutListener { public static final String META_DATA_LIB_NAME = "android.app.lib_name"; + public static final String KEY_NATIVE_SAVED_STATE = "android:native_state"; + private NativeContentView mNativeContentView; private InputMethodManager mIMM; private InputMethodCallback mInputMethodCallback; @@ -59,14 +75,15 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, private native int loadNativeCode(String path, MessageQueue queue, String internalDataPath, String externalDataPath, int sdkVersion, - AssetManager assetMgr); + AssetManager assetMgr, byte[] savedState); private native void unloadNativeCode(int handle); private native void onStartNative(int handle); private native void onResumeNative(int handle); - private native void onSaveInstanceStateNative(int handle); + private native byte[] onSaveInstanceStateNative(int handle); private native void onPauseNative(int handle); private native void onStopNative(int handle); + private native void onConfigurationChangedNative(int handle); private native void onLowMemoryNative(int handle); private native void onWindowFocusChangedNative(int handle, boolean focused); private native void onSurfaceCreatedNative(int handle, Surface surface); @@ -165,10 +182,13 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, throw new IllegalArgumentException("Unable to find native library: " + libname); } + byte[] nativeSavedState = savedInstanceState != null + ? savedInstanceState.getByteArray(KEY_NATIVE_SAVED_STATE) : null; + mNativeHandle = loadNativeCode(path, Looper.myQueue(), getFilesDir().toString(), Environment.getExternalStorageAppFilesDirectory(ai.packageName).toString(), - Build.VERSION.SDK_INT, getAssets()); + Build.VERSION.SDK_INT, getAssets(), nativeSavedState); if (mNativeHandle == 0) { throw new IllegalArgumentException("Unable to load native library: " + path); @@ -206,7 +226,10 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - onSaveInstanceStateNative(mNativeHandle); + byte[] state = onSaveInstanceStateNative(mNativeHandle); + if (state != null) { + outState.putByteArray(KEY_NATIVE_SAVED_STATE, state); + } } @Override @@ -222,6 +245,14 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback2, } @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (!mDestroyed) { + onConfigurationChangedNative(mNativeHandle); + } + } + + @Override public void onLowMemory() { super.onLowMemory(); if (!mDestroyed) { diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 0608cc02bf3d..9bb3b75124f3 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1288,7 +1288,7 @@ public class Resources { height = mMetrics.widthPixels; } int keyboardHidden = mConfiguration.keyboardHidden; - if (keyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO + if (keyboardHidden == Configuration.KEYBOARDHIDDEN_NO && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT; diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 69b35404a61b..a9d7342ec374 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -180,6 +180,11 @@ public class Looper { return mThread; } + /** @hide */ + public MessageQueue getQueue() { + return mQueue; + } + public void dump(Printer pw, String prefix) { pw.println(prefix + this); pw.println(prefix + "mRun=" + mRun); diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl index ca7efe780743..5c69214c32c1 100644 --- a/core/java/android/os/storage/IMountService.aidl +++ b/core/java/android/os/storage/IMountService.aidl @@ -19,6 +19,7 @@ package android.os.storage; import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; +import android.os.storage.IObbActionListener; /** WARNING! Update IMountService.h and IMountService.cpp if you change this file. * In particular, the ordering of the methods below must match the @@ -156,14 +157,20 @@ interface IMountService /** * Mounts an Opaque Binary Blob (OBB) with the specified decryption key and only * allows the calling process's UID access to the contents. + * + * MountService will call back to the supplied IObbActionListener to inform + * it of the terminal state of the call. */ - int mountObb(String filename, String key); + void mountObb(String filename, String key, IObbActionListener token); /** * Unmounts an Opaque Binary Blob (OBB). When the force flag is specified, any * program using it will be forcibly killed to unmount the image. + * + * MountService will call back to the supplied IObbActionListener to inform + * it of the terminal state of the call. */ - int unmountObb(String filename, boolean force); + void unmountObb(String filename, boolean force, IObbActionListener token); /** * Checks whether the specified Opaque Binary Blob (OBB) is mounted somewhere. diff --git a/core/java/android/os/storage/IObbActionListener.aidl b/core/java/android/os/storage/IObbActionListener.aidl new file mode 100644 index 000000000000..78d7a9ed391c --- /dev/null +++ b/core/java/android/os/storage/IObbActionListener.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os.storage; + +/** + * Callback class for receiving events from MountService about + * Opaque Binary Blobs (OBBs). + * + * @hide - Applications should use android.os.storage.StorageManager + * to interact with OBBs. + */ +interface IObbActionListener { + /** + * Return from an OBB action result. + * + * @param filename the path to the OBB the operation was performed on + * @param returnCode status of the operation + */ + void onObbResult(String filename, String status); +} diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 96bf2d5cd59b..cb1794f7536e 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -16,28 +16,14 @@ package android.os.storage; -import android.content.Context; -import android.os.Binder; -import android.os.Bundle; -import android.os.Looper; -import android.os.Parcelable; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; import android.os.Handler; +import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.os.ServiceManager; -import android.os.storage.IMountService; -import android.os.storage.IMountServiceListener; import android.util.Log; -import android.util.SparseArray; -import java.io.FileDescriptor; -import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; /** * StorageManager is the interface to the systems storage service. @@ -87,6 +73,17 @@ public class StorageManager } /** + * Binder listener for OBB action results. + */ + private final ObbActionBinderListener mObbActionListener = new ObbActionBinderListener(); + private class ObbActionBinderListener extends IObbActionListener.Stub { + @Override + public void onObbResult(String filename, String status) throws RemoteException { + Log.i(TAG, "filename = " + filename + ", result = " + status); + } + } + + /** * Private base class for messages sent between the callback thread * and the target looper handler. */ @@ -299,12 +296,23 @@ public class StorageManager } /** - * Mount an OBB file. + * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is + * specified, it is supplied to the mounting process to be used in any + * encryption used in the OBB. + * <p> + * <em>Note:</em> you can only mount OBB files for which the OBB tag on the + * file matches a package ID that is owned by the calling program's UID. + * That is, shared UID applications can obtain access to any other + * application's OBB that shares its UID. + * + * @param filename the path to the OBB file + * @param key decryption key + * @return whether the mount call was successfully queued or not */ public boolean mountObb(String filename, String key) { try { - return mMountService.mountObb(filename, key) - == StorageResultCode.OperationSucceeded; + mMountService.mountObb(filename, key, mObbActionListener); + return true; } catch (RemoteException e) { Log.e(TAG, "Failed to mount OBB", e); } @@ -313,12 +321,24 @@ public class StorageManager } /** - * Mount an OBB file. + * Unmount an Opaque Binary Blob (OBB) file. If the <code>force</code> flag + * is true, it will kill any application needed to unmount the given OBB. + * <p> + * <em>Note:</em> you can only mount OBB files for which the OBB tag on the + * file matches a package ID that is owned by the calling program's UID. + * That is, shared UID applications can obtain access to any other + * application's OBB that shares its UID. + * + * @param filename path to the OBB file + * @param force whether to kill any programs using this in order to unmount + * it + * @return whether the unmount call was successfully queued or not + * @throws IllegalArgumentException when OBB is not already mounted */ - public boolean unmountObb(String filename, boolean force) { + public boolean unmountObb(String filename, boolean force) throws IllegalArgumentException { try { - return mMountService.unmountObb(filename, force) - == StorageResultCode.OperationSucceeded; + mMountService.unmountObb(filename, force, mObbActionListener); + return true; } catch (RemoteException e) { Log.e(TAG, "Failed to mount OBB", e); } @@ -326,7 +346,13 @@ public class StorageManager return false; } - public boolean isObbMounted(String filename) { + /** + * Check whether an Opaque Binary Blob (OBB) is mounted or not. + * + * @param filename path to OBB image + * @return true if OBB is mounted; false if not mounted or on error + */ + public boolean isObbMounted(String filename) throws IllegalArgumentException { try { return mMountService.isObbMounted(filename); } catch (RemoteException e) { @@ -337,13 +363,21 @@ public class StorageManager } /** - * Check the mounted path of an OBB file. + * Check the mounted path of an Opaque Binary Blob (OBB) file. This will + * give you the path to where you can obtain access to the internals of the + * OBB. + * + * @param filename path to OBB image + * @return absolute path to mounted OBB image data or <code>null</code> if + * not mounted or exception encountered trying to read status */ public String getMountedObbPath(String filename) { try { return mMountService.getMountedObbPath(filename); } catch (RemoteException e) { Log.e(TAG, "Failed to find mounted path for OBB", e); + } catch (IllegalArgumentException e) { + Log.d(TAG, "Couldn't read OBB file", e); } return null; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index d6b92125490c..e86e3bf3bcba 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -28,6 +28,7 @@ import android.view.IWindowSession; import android.view.KeyEvent; import android.view.InputEvent; import android.view.MotionEvent; +import android.view.InputChannel; /** * System private interface to the window manager. @@ -119,6 +120,7 @@ interface IWindowManager int getKeycodeStateForDevice(int devid, int sw); int getTrackballKeycodeState(int sw); int getDPadKeycodeState(int sw); + InputChannel monitorInput(String inputChannelName); // Report whether the hardware supports the given keys; returns true if successful boolean hasKeys(in int[] keycodes, inout boolean[] keyExists); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b5b29b59e23b..b8623e73366e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4848,7 +4848,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility * of ViewGroup that are responsible for arranging their children. * @return The LayoutParams associated with this view */ - @ViewDebug.ExportedProperty(deepExport = true, category = "layout") + @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") public ViewGroup.LayoutParams getLayoutParams() { return mLayoutParams; } diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 7908f3615e6d..2ca08ea8be29 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -1377,9 +1377,8 @@ public class ViewDebug { Object methodValue = method.invoke(view, (Object[]) null); final Class<?> returnType = method.getReturnType(); final ExportedProperty property = sAnnotations.get(method); - String fullName = (property.category().length() == 0) ? - method.getName() : - (property.category() + ":" + method.getName()); + String categoryPrefix = + property.category().length() != 0 ? property.category() + ":" : ""; if (returnType == int.class) { @@ -1390,7 +1389,8 @@ public class ViewDebug { final FlagToString[] flagsMapping = property.flagMapping(); if (flagsMapping.length > 0) { final int intValue = (Integer) methodValue; - final String valuePrefix = prefix + fullName + '_'; + final String valuePrefix = + categoryPrefix + prefix + method.getName() + '_'; exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); } @@ -1415,7 +1415,7 @@ public class ViewDebug { } } else if (returnType == int[].class) { final int[] array = (int[]) methodValue; - final String valuePrefix = prefix + fullName + '_'; + final String valuePrefix = categoryPrefix + prefix + method.getName() + '_'; final String suffix = "()"; exportUnrolledArray(context, out, property, array, valuePrefix, suffix); @@ -1429,7 +1429,7 @@ public class ViewDebug { } } - writeEntry(out, prefix, fullName, "()", methodValue); + writeEntry(out, categoryPrefix + prefix, method.getName(), "()", methodValue); } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } @@ -1450,9 +1450,8 @@ public class ViewDebug { Object fieldValue = null; final Class<?> type = field.getType(); final ExportedProperty property = sAnnotations.get(field); - String fullName = (property.category().length() == 0) ? - field.getName() : - (property.category() + ":" + field.getName()); + String categoryPrefix = + property.category().length() != 0 ? property.category() + ":" : ""; if (type == int.class) { @@ -1463,7 +1462,8 @@ public class ViewDebug { final FlagToString[] flagsMapping = property.flagMapping(); if (flagsMapping.length > 0) { final int intValue = field.getInt(view); - final String valuePrefix = prefix + fullName + '_'; + final String valuePrefix = + categoryPrefix + prefix + field.getName() + '_'; exportUnrolledFlags(out, flagsMapping, intValue, valuePrefix); } @@ -1486,7 +1486,7 @@ public class ViewDebug { } } else if (type == int[].class) { final int[] array = (int[]) field.get(view); - final String valuePrefix = prefix + fullName + '_'; + final String valuePrefix = categoryPrefix + prefix + field.getName() + '_'; final String suffix = ""; exportUnrolledArray(context, out, property, array, valuePrefix, suffix); @@ -1495,8 +1495,8 @@ public class ViewDebug { return; } else if (!type.isPrimitive()) { if (property.deepExport()) { - dumpViewProperties(context, field.get(view), out, - prefix + property.prefix()); + dumpViewProperties(context, field.get(view), out, prefix + + property.prefix()); continue; } } @@ -1505,7 +1505,7 @@ public class ViewDebug { fieldValue = field.get(view); } - writeEntry(out, prefix, fullName, "", fieldValue); + writeEntry(out, categoryPrefix + prefix, field.getName(), "", fieldValue); } catch (IllegalAccessException e) { } } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 7ce04cfd113f..57c9055552b0 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -52,7 +52,6 @@ import android.Manifest; import android.media.AudioManager; import java.lang.ref.WeakReference; -import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -1869,7 +1868,7 @@ public final class ViewRoot extends Handler implements ViewParent, if (LOCAL_LOGV) Log.v( TAG, "Dispatching key " + msg.obj + " to " + mView); - deliverKeyEvent((KeyEvent)msg.obj, true); + deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0); break; case DISPATCH_POINTER: { MotionEvent event = (MotionEvent) msg.obj; @@ -2021,9 +2020,14 @@ public final class ViewRoot extends Handler implements ViewParent, } private void finishKeyEvent(KeyEvent event) { + if (LOCAL_LOGV) Log.v(TAG, "Telling window manager key is finished"); + if (mFinishedCallback != null) { mFinishedCallback.run(); mFinishedCallback = null; + } else { + Slog.w(TAG, "Attempted to tell the input queue that the current key event " + + "is finished but there is no key event actually in progress."); } } @@ -2483,8 +2487,6 @@ public final class ViewRoot extends Handler implements ViewParent, ? mView.dispatchKeyEventPreIme(event) : true; if (handled) { if (sendDone) { - if (LOCAL_LOGV) Log.v( - TAG, "Telling window manager key is finished"); finishKeyEvent(event); } return; @@ -2516,8 +2518,6 @@ public final class ViewRoot extends Handler implements ViewParent, deliverKeyEventToViewHierarchy(event, sendDone); return; } else if (sendDone) { - if (LOCAL_LOGV) Log.v( - TAG, "Telling window manager key is finished"); finishKeyEvent(event); } else { Log.w(TAG, "handleFinishedEvent(seq=" + seq @@ -2591,8 +2591,6 @@ public final class ViewRoot extends Handler implements ViewParent, } finally { if (sendDone) { - if (LOCAL_LOGV) Log.v( - TAG, "Telling window manager key is finished"); finishKeyEvent(event); } // Let the exception fall through -- the looper will catch @@ -2776,9 +2774,14 @@ public final class ViewRoot extends Handler implements ViewParent, private final InputHandler mInputHandler = new InputHandler() { public void handleKey(KeyEvent event, Runnable finishedCallback) { + if (mFinishedCallback != null) { + Slog.w(TAG, "Received a new key event from the input queue but there is " + + "already an unfinished key event in progress."); + } + mFinishedCallback = finishedCallback; - dispatchKey(event); + dispatchKey(event, true); } public void handleMotion(MotionEvent event, Runnable finishedCallback) { @@ -2789,9 +2792,13 @@ public final class ViewRoot extends Handler implements ViewParent, }; public void dispatchKey(KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { - //noinspection ConstantConditions - if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) { + dispatchKey(event, false); + } + + private void dispatchKey(KeyEvent event, boolean sendDone) { + //noinspection ConstantConditions + if (false && event.getAction() == KeyEvent.ACTION_DOWN) { + if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) { if (Config.LOGD) Log.d("keydisp", "==================================================="); if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:"); @@ -2804,6 +2811,7 @@ public final class ViewRoot extends Handler implements ViewParent, Message msg = obtainMessage(DISPATCH_KEY); msg.obj = event; + msg.arg1 = sendDone ? 1 : 0; if (LOCAL_LOGV) Log.v( TAG, "sending key " + event + " to " + mView); diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 33757f023ec3..659f9cd673c6 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -779,11 +779,6 @@ public interface WindowManagerPolicy { */ public void enableScreenAfterBoot(); - /** - * Called every time the window manager is dispatching a pointer event. - */ - public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY); - public void setCurrentOrientationLw(int newOrientation); /** diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java index b18419dc1768..7acd9baba8b4 100644 --- a/core/java/android/webkit/WebViewDatabase.java +++ b/core/java/android/webkit/WebViewDatabase.java @@ -727,6 +727,9 @@ public class WebViewDatabase { } long getCacheTotalSize() { + if (mCacheDatabase == null) { + return 0; + } long size = 0; Cursor cursor = null; final String query = "SELECT SUM(contentlength) as sum FROM cache"; diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl index 89649a98efa8..5d1f632797a7 100755 --- a/core/java/com/android/internal/app/IMediaContainerService.aidl +++ b/core/java/com/android/internal/app/IMediaContainerService.aidl @@ -19,6 +19,7 @@ package com.android.internal.app; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.content.pm.PackageInfoLite; +import android.content.res.ObbInfo; interface IMediaContainerService { String copyResourceToContainer(in Uri packageURI, @@ -28,4 +29,5 @@ interface IMediaContainerService { in ParcelFileDescriptor outStream); PackageInfoLite getMinimalPackageInfo(in Uri fileUri, int flags); boolean checkFreeStorage(boolean external, in Uri fileUri); + ObbInfo getObbInfo(String filename); } diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java new file mode 100644 index 000000000000..ce5959d1ea91 --- /dev/null +++ b/core/java/com/android/internal/app/PlatLogoActivity.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.ImageView; + +public class PlatLogoActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ImageView content = new ImageView(this); + content.setImageResource(com.android.internal.R.drawable.platlogo); + content.setScaleType(ImageView.ScaleType.FIT_CENTER); + + setContentView(content); + } +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 5c37c7c52ab7..efdc3994ff77 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -135,7 +135,8 @@ LOCAL_SRC_FILES:= \ android_backup_BackupDataOutput.cpp \ android_backup_FileBackupHelperBase.cpp \ android_backup_BackupHelperDispatcher.cpp \ - android_content_res_ObbScanner.cpp + android_content_res_ObbScanner.cpp \ + android_content_res_Configuration.cpp LOCAL_C_INCLUDES += \ $(JNI_H_INCLUDE) \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 7fe56a765e0a..62ca2efe3b8b 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -167,6 +167,7 @@ extern int register_android_view_InputQueue(JNIEnv* env); extern int register_android_view_KeyEvent(JNIEnv* env); extern int register_android_view_MotionEvent(JNIEnv* env); extern int register_android_content_res_ObbScanner(JNIEnv* env); +extern int register_android_content_res_Configuration(JNIEnv* env); static AndroidRuntime* gCurRuntime = NULL; @@ -1340,6 +1341,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_MotionEvent), REG_JNI(register_android_content_res_ObbScanner), + REG_JNI(register_android_content_res_Configuration), }; /* diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index 1feb3b3ecda9..0932473aa859 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -600,7 +600,7 @@ static bool mainWorkCallback(int fd, int events, void* data) { static jint loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue, jstring internalDataDir, jstring externalDataDir, int sdkVersion, - jobject jAssetMgr) + jobject jAssetMgr, jbyteArray savedState) { LOG_TRACE("loadNativeCode_native"); @@ -666,7 +666,18 @@ loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQ code->assetManager = assetManagerForJavaObject(env, jAssetMgr); - code->createActivityFunc(code, NULL, 0); + jbyte* rawSavedState = NULL; + jsize rawSavedSize = 0; + if (savedState != NULL) { + rawSavedState = env->GetByteArrayElements(savedState, NULL); + rawSavedSize = env->GetArrayLength(savedState); + } + + code->createActivityFunc(code, rawSavedState, rawSavedSize); + + if (rawSavedState != NULL) { + env->ReleaseByteArrayElements(savedState, rawSavedState, 0); + } } return (jint)code; @@ -706,17 +717,31 @@ onResume_native(JNIEnv* env, jobject clazz, jint handle) } } -static void +static jbyteArray onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle) { LOG_TRACE("onSaveInstanceState_native"); + + jbyteArray array = NULL; + if (handle != 0) { NativeCode* code = (NativeCode*)handle; if (code->callbacks.onSaveInstanceState != NULL) { size_t len = 0; - code->callbacks.onSaveInstanceState(code, &len); + jbyte* state = (jbyte*)code->callbacks.onSaveInstanceState(code, &len); + if (len > 0) { + array = env->NewByteArray(len); + if (array != NULL) { + env->SetByteArrayRegion(array, 0, len, state); + } + } + if (state != NULL) { + free(state); + } } } + + return array; } static void @@ -744,6 +769,18 @@ onStop_native(JNIEnv* env, jobject clazz, jint handle) } static void +onConfigurationChanged_native(JNIEnv* env, jobject clazz, jint handle) +{ + LOG_TRACE("onConfigurationChanged_native"); + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onConfigurationChanged != NULL) { + code->callbacks.onConfigurationChanged(code); + } + } +} + +static void onLowMemory_native(JNIEnv* env, jobject clazz, jint handle) { LOG_TRACE("onLowMemory_native"); @@ -934,14 +971,15 @@ finishPreDispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, } static const JNINativeMethod g_methods[] = { - { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;)I", + { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;ILandroid/content/res/AssetManager;[B)I", (void*)loadNativeCode_native }, { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, { "onStartNative", "(I)V", (void*)onStart_native }, { "onResumeNative", "(I)V", (void*)onResume_native }, - { "onSaveInstanceStateNative", "(I)V", (void*)onSaveInstanceState_native }, + { "onSaveInstanceStateNative", "(I)[B", (void*)onSaveInstanceState_native }, { "onPauseNative", "(I)V", (void*)onPause_native }, { "onStopNative", "(I)V", (void*)onStop_native }, + { "onConfigurationChangedNative", "(I)V", (void*)onConfigurationChanged_native }, { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native }, { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native }, { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native }, diff --git a/core/jni/android_content_res_Configuration.cpp b/core/jni/android_content_res_Configuration.cpp new file mode 100644 index 000000000000..28a43ab09f76 --- /dev/null +++ b/core/jni/android_content_res_Configuration.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Configuration" + +#include <utils/Log.h> +#include "utils/misc.h" + +#include "jni.h" +#include <android_runtime/android_content_res_Configuration.h> +#include "android_runtime/AndroidRuntime.h" + +namespace android { + +static struct { + jclass clazz; + + jfieldID mcc; + jfieldID mnc; + jfieldID locale; + jfieldID screenLayout; + jfieldID touchscreen; + jfieldID keyboard; + jfieldID keyboardHidden; + jfieldID hardKeyboardHidden; + jfieldID navigation; + jfieldID navigationHidden; + jfieldID orientation; + jfieldID uiMode; +} gConfigurationClassInfo; + +void android_Configuration_getFromJava( + JNIEnv* env, jobject clazz, struct AConfiguration* out) { + out->mcc = env->GetIntField(clazz, gConfigurationClassInfo.mcc); + out->mnc = env->GetIntField(clazz, gConfigurationClassInfo.mnc); + out->screenLayout = env->GetIntField(clazz, gConfigurationClassInfo.screenLayout); + out->touchscreen = env->GetIntField(clazz, gConfigurationClassInfo.touchscreen); + out->keyboard = env->GetIntField(clazz, gConfigurationClassInfo.keyboard); + out->navigation = env->GetIntField(clazz, gConfigurationClassInfo.navigation); + + out->inputFlags = env->GetIntField(clazz, gConfigurationClassInfo.keyboardHidden); + int hardKeyboardHidden = env->GetIntField(clazz, gConfigurationClassInfo.hardKeyboardHidden); + if (out->inputFlags == ACONFIGURATION_KEYSHIDDEN_NO + && hardKeyboardHidden == 2) { + out->inputFlags = ACONFIGURATION_KEYSHIDDEN_SOFT; + } + out->inputFlags |= env->GetIntField(clazz, gConfigurationClassInfo.navigationHidden) + << ResTable_config::SHIFT_NAVHIDDEN; + + out->orientation = env->GetIntField(clazz, gConfigurationClassInfo.orientation); + out->uiMode = env->GetIntField(clazz, gConfigurationClassInfo.uiMode); +} + +/* + * JNI registration. + */ +static JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + //{ "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)Z", + // (void*) android_content_res_ObbScanner_getObbInfo }, +}; + +#define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); \ + var = jclass(env->NewGlobalRef(var)); + +#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ + var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find field " fieldName); + +int register_android_content_res_Configuration(JNIEnv* env) +{ + FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration"); + + GET_FIELD_ID(gConfigurationClassInfo.mcc, gConfigurationClassInfo.clazz, + "mcc", "I"); + GET_FIELD_ID(gConfigurationClassInfo.mnc, gConfigurationClassInfo.clazz, + "mnc", "I"); + GET_FIELD_ID(gConfigurationClassInfo.locale, gConfigurationClassInfo.clazz, + "locale", "Ljava/util/Locale;"); + GET_FIELD_ID(gConfigurationClassInfo.screenLayout, gConfigurationClassInfo.clazz, + "screenLayout", "I"); + GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz, + "touchscreen", "I"); + GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz, + "keyboard", "I"); + GET_FIELD_ID(gConfigurationClassInfo.keyboardHidden, gConfigurationClassInfo.clazz, + "keyboardHidden", "I"); + GET_FIELD_ID(gConfigurationClassInfo.hardKeyboardHidden, gConfigurationClassInfo.clazz, + "hardKeyboardHidden", "I"); + GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz, + "navigation", "I"); + GET_FIELD_ID(gConfigurationClassInfo.navigationHidden, gConfigurationClassInfo.clazz, + "navigationHidden", "I"); + GET_FIELD_ID(gConfigurationClassInfo.orientation, gConfigurationClassInfo.clazz, + "orientation", "I"); + GET_FIELD_ID(gConfigurationClassInfo.uiMode, gConfigurationClassInfo.clazz, + "uiMode", "I"); + + return AndroidRuntime::registerNativeMethods(env, "android/content/res/Configuration", gMethods, + NELEM(gMethods)); +} + +}; // namespace android diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 82f822f0dc67..19b30cc4e7a6 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1275,6 +1275,9 @@ android:finishOnCloseSystemDialogs="true" android:excludeFromRecents="true"> </activity> + <activity android:name="com.android.internal.app.PlatLogoActivity" + android:theme="@style/Theme.NoTitleBar.Fullscreen"> + </activity> <activity android:name="com.android.internal.app.DisableCarModeActivity" android:theme="@style/Theme.NoDisplay" android:excludeFromRecents="true"> diff --git a/core/res/res/drawable-nodpi/platlogo.jpg b/core/res/res/drawable-nodpi/platlogo.jpg Binary files differnew file mode 100644 index 000000000000..0e7780c12b1a --- /dev/null +++ b/core/res/res/drawable-nodpi/platlogo.jpg diff --git a/include/android_runtime/android_content_res_Configuration.h b/include/android_runtime/android_content_res_Configuration.h new file mode 100644 index 000000000000..2f5a98249cb7 --- /dev/null +++ b/include/android_runtime/android_content_res_Configuration.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_CONTENT_RES_CONFIGURATION_H +#define _ANDROID_CONTENT_RES_CONFIGURATION_H + +#include <utils/ResourceTypes.h> +#include <android/configuration.h> + +#include "jni.h" + +struct AConfiguration : android::ResTable_config { +}; + +namespace android { + +extern void android_Configuration_getFromJava( + JNIEnv* env, jobject clazz, struct AConfiguration* out); + +} // namespace android + + +#endif // _ANDROID_CONTENT_RES_CONFIGURATION_H diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h index 97694ff0a997..9e2bf37e8fa4 100644 --- a/include/utils/AssetManager.h +++ b/include/utils/AssetManager.h @@ -129,6 +129,8 @@ public: */ void setConfiguration(const ResTable_config& config, const char* locale = NULL); + void getConfiguration(ResTable_config* outConfig) const; + typedef Asset::AccessMode AccessMode; // typing shortcut /* diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h index 075927cdfa2e..d2ca82eb55c7 100644 --- a/include/utils/ObbFile.h +++ b/include/utils/ObbFile.h @@ -35,6 +35,8 @@ public: bool readFrom(int fd); bool writeTo(const char* filename); bool writeTo(int fd); + bool removeFrom(const char* filename); + bool removeFrom(int fd); const char* getFileName() const { return mFileName; @@ -78,6 +80,8 @@ private: size_t mFileSize; + size_t mFooterStart; + unsigned char* mReadBuf; bool parseObbFile(int fd); diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index c7d9ff1dd678..da86da41006d 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -31,6 +31,8 @@ #include <stdint.h> #include <sys/types.h> +#include <android/configuration.h> + namespace android { /** ******************************************************************** @@ -822,25 +824,25 @@ struct ResTable_config }; enum { - ORIENTATION_ANY = 0x0000, - ORIENTATION_PORT = 0x0001, - ORIENTATION_LAND = 0x0002, - ORIENTATION_SQUARE = 0x0003, + ORIENTATION_ANY = ACONFIGURATION_ORIENTATION_ANY, + ORIENTATION_PORT = ACONFIGURATION_ORIENTATION_PORT, + ORIENTATION_LAND = ACONFIGURATION_ORIENTATION_LAND, + ORIENTATION_SQUARE = ACONFIGURATION_ORIENTATION_SQUARE, }; enum { - TOUCHSCREEN_ANY = 0x0000, - TOUCHSCREEN_NOTOUCH = 0x0001, - TOUCHSCREEN_STYLUS = 0x0002, - TOUCHSCREEN_FINGER = 0x0003, + TOUCHSCREEN_ANY = ACONFIGURATION_TOUCHSCREEN_ANY, + TOUCHSCREEN_NOTOUCH = ACONFIGURATION_TOUCHSCREEN_NOTOUCH, + TOUCHSCREEN_STYLUS = ACONFIGURATION_TOUCHSCREEN_STYLUS, + TOUCHSCREEN_FINGER = ACONFIGURATION_TOUCHSCREEN_FINGER, }; enum { - DENSITY_DEFAULT = 0, - DENSITY_LOW = 120, - DENSITY_MEDIUM = 160, - DENSITY_HIGH = 240, - DENSITY_NONE = 0xffff + DENSITY_DEFAULT = ACONFIGURATION_DENSITY_DEFAULT, + DENSITY_LOW = ACONFIGURATION_DENSITY_LOW, + DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM, + DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH, + DENSITY_NONE = ACONFIGURATION_DENSITY_NONE }; union { @@ -853,33 +855,34 @@ struct ResTable_config }; enum { - KEYBOARD_ANY = 0x0000, - KEYBOARD_NOKEYS = 0x0001, - KEYBOARD_QWERTY = 0x0002, - KEYBOARD_12KEY = 0x0003, + KEYBOARD_ANY = ACONFIGURATION_KEYBOARD_ANY, + KEYBOARD_NOKEYS = ACONFIGURATION_KEYBOARD_NOKEYS, + KEYBOARD_QWERTY = ACONFIGURATION_KEYBOARD_QWERTY, + KEYBOARD_12KEY = ACONFIGURATION_KEYBOARD_12KEY, }; enum { - NAVIGATION_ANY = 0x0000, - NAVIGATION_NONAV = 0x0001, - NAVIGATION_DPAD = 0x0002, - NAVIGATION_TRACKBALL = 0x0003, - NAVIGATION_WHEEL = 0x0004, + NAVIGATION_ANY = ACONFIGURATION_NAVIGATION_ANY, + NAVIGATION_NONAV = ACONFIGURATION_NAVIGATION_NONAV, + NAVIGATION_DPAD = ACONFIGURATION_NAVIGATION_DPAD, + NAVIGATION_TRACKBALL = ACONFIGURATION_NAVIGATION_TRACKBALL, + NAVIGATION_WHEEL = ACONFIGURATION_NAVIGATION_WHEEL, }; enum { MASK_KEYSHIDDEN = 0x0003, - KEYSHIDDEN_ANY = 0x0000, - KEYSHIDDEN_NO = 0x0001, - KEYSHIDDEN_YES = 0x0002, - KEYSHIDDEN_SOFT = 0x0003, + KEYSHIDDEN_ANY = ACONFIGURATION_KEYSHIDDEN_ANY, + KEYSHIDDEN_NO = ACONFIGURATION_KEYSHIDDEN_NO, + KEYSHIDDEN_YES = ACONFIGURATION_KEYSHIDDEN_YES, + KEYSHIDDEN_SOFT = ACONFIGURATION_KEYSHIDDEN_SOFT, }; enum { MASK_NAVHIDDEN = 0x000c, - NAVHIDDEN_ANY = 0x0000, - NAVHIDDEN_NO = 0x0004, - NAVHIDDEN_YES = 0x0008, + SHIFT_NAVHIDDEN = 2, + NAVHIDDEN_ANY = ACONFIGURATION_NAVHIDDEN_ANY << SHIFT_NAVHIDDEN, + NAVHIDDEN_NO = ACONFIGURATION_NAVHIDDEN_NO << SHIFT_NAVHIDDEN, + NAVHIDDEN_YES = ACONFIGURATION_NAVHIDDEN_YES << SHIFT_NAVHIDDEN, }; union { @@ -929,32 +932,34 @@ struct ResTable_config enum { // screenLayout bits for screen size class. MASK_SCREENSIZE = 0x0f, - SCREENSIZE_ANY = 0x00, - SCREENSIZE_SMALL = 0x01, - SCREENSIZE_NORMAL = 0x02, - SCREENSIZE_LARGE = 0x03, - SCREENSIZE_XLARGE = 0x04, + SCREENSIZE_ANY = ACONFIGURATION_SCREENSIZE_ANY, + SCREENSIZE_SMALL = ACONFIGURATION_SCREENSIZE_SMALL, + SCREENSIZE_NORMAL = ACONFIGURATION_SCREENSIZE_NORMAL, + SCREENSIZE_LARGE = ACONFIGURATION_SCREENSIZE_LARGE, + SCREENSIZE_XLARGE = ACONFIGURATION_SCREENSIZE_XLARGE, // screenLayout bits for wide/long screen variation. MASK_SCREENLONG = 0x30, - SCREENLONG_ANY = 0x00, - SCREENLONG_NO = 0x10, - SCREENLONG_YES = 0x20, + SHIFT_SCREENLONG = 4, + SCREENLONG_ANY = ACONFIGURATION_SCREENLONG_ANY << SHIFT_SCREENLONG, + SCREENLONG_NO = ACONFIGURATION_SCREENLONG_NO << SHIFT_SCREENLONG, + SCREENLONG_YES = ACONFIGURATION_SCREENLONG_YES << SHIFT_SCREENLONG, }; enum { // uiMode bits for the mode type. MASK_UI_MODE_TYPE = 0x0f, - UI_MODE_TYPE_ANY = 0x00, - UI_MODE_TYPE_NORMAL = 0x01, - UI_MODE_TYPE_DESK = 0x02, - UI_MODE_TYPE_CAR = 0x03, + UI_MODE_TYPE_ANY = ACONFIGURATION_UI_MODE_TYPE_ANY, + UI_MODE_TYPE_NORMAL = ACONFIGURATION_UI_MODE_TYPE_NORMAL, + UI_MODE_TYPE_DESK = ACONFIGURATION_UI_MODE_TYPE_DESK, + UI_MODE_TYPE_CAR = ACONFIGURATION_UI_MODE_TYPE_CAR, // uiMode bits for the night switch. MASK_UI_MODE_NIGHT = 0x30, - UI_MODE_NIGHT_ANY = 0x00, - UI_MODE_NIGHT_NO = 0x10, - UI_MODE_NIGHT_YES = 0x20, + SHIFT_UI_MODE_NIGHT = 4, + UI_MODE_NIGHT_ANY = ACONFIGURATION_UI_MODE_NIGHT_ANY << SHIFT_UI_MODE_NIGHT, + UI_MODE_NIGHT_NO = ACONFIGURATION_UI_MODE_NIGHT_NO << SHIFT_UI_MODE_NIGHT, + UI_MODE_NIGHT_YES = ACONFIGURATION_UI_MODE_NIGHT_YES << SHIFT_UI_MODE_NIGHT, }; union { @@ -1023,19 +1028,19 @@ struct ResTable_config // match the corresponding ones in android.content.pm.ActivityInfo and // attrs_manifest.xml. enum { - CONFIG_MCC = 0x0001, - CONFIG_MNC = 0x0002, - CONFIG_LOCALE = 0x0004, - CONFIG_TOUCHSCREEN = 0x0008, - CONFIG_KEYBOARD = 0x0010, - CONFIG_KEYBOARD_HIDDEN = 0x0020, - CONFIG_NAVIGATION = 0x0040, - CONFIG_ORIENTATION = 0x0080, - CONFIG_DENSITY = 0x0100, - CONFIG_SCREEN_SIZE = 0x0200, - CONFIG_VERSION = 0x0400, - CONFIG_SCREEN_LAYOUT = 0x0800, - CONFIG_UI_MODE = 0x1000 + CONFIG_MCC = ACONFIGURATION_MCC, + CONFIG_MNC = ACONFIGURATION_MCC, + CONFIG_LOCALE = ACONFIGURATION_LOCALE, + CONFIG_TOUCHSCREEN = ACONFIGURATION_TOUCHSCREEN, + CONFIG_KEYBOARD = ACONFIGURATION_KEYBOARD, + CONFIG_KEYBOARD_HIDDEN = ACONFIGURATION_KEYBOARD_HIDDEN, + CONFIG_NAVIGATION = ACONFIGURATION_NAVIGATION, + CONFIG_ORIENTATION = ACONFIGURATION_ORIENTATION, + CONFIG_DENSITY = ACONFIGURATION_DENSITY, + CONFIG_SCREEN_SIZE = ACONFIGURATION_SCREEN_SIZE, + CONFIG_VERSION = ACONFIGURATION_VERSION, + CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT, + CONFIG_UI_MODE = ACONFIGURATION_UI_MODE }; // Compare two configuration, returning CONFIG_* flags set for each value diff --git a/include/utils/String8.h b/include/utils/String8.h index 4e41410f4388..ef0b51a443ec 100644 --- a/include/utils/String8.h +++ b/include/utils/String8.h @@ -171,7 +171,8 @@ public: status_t append(const char* other); status_t append(const char* other, size_t numChars); - status_t appendFormat(const char* fmt, ...); + status_t appendFormat(const char* fmt, ...) + __attribute__((format (printf, 2, 3))); // Note that this function takes O(N) time to calculate the value. // No cache value is stored. diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 60a0d82e255d..e09e755861dc 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -232,6 +232,12 @@ void AssetManager::setConfiguration(const ResTable_config& config, const char* l } } +void AssetManager::getConfiguration(ResTable_config* outConfig) const +{ + AutoMutex _l(mLock); + *outConfig = *mConfig; +} + /* * Open an asset. * diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp index fe49300eb25d..adedf0c5d0dc 100644 --- a/libs/utils/ObbFile.cpp +++ b/libs/utils/ObbFile.cpp @@ -156,9 +156,9 @@ bool ObbFile::parseObbFile(int fd) return false; } - if (footerSize < kFooterMinSize) { - LOGW("claimed footer size is too small (%08zx; minimum size is 0x%x)\n", - footerSize, kFooterMinSize); + if (footerSize < (kFooterMinSize - kFooterTagSize)) { + LOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n", + footerSize, kFooterMinSize - kFooterTagSize); return false; } } @@ -169,6 +169,8 @@ bool ObbFile::parseObbFile(int fd) return false; } + mFooterStart = fileOffset; + char* scanBuf = (char*)malloc(footerSize); if (scanBuf == NULL) { LOGW("couldn't allocate scanBuf: %s\n", strerror(errno)); @@ -293,4 +295,38 @@ bool ObbFile::writeTo(int fd) return true; } +bool ObbFile::removeFrom(const char* filename) +{ + int fd; + bool success = false; + + fd = ::open(filename, O_RDWR); + if (fd < 0) { + goto out; + } + success = removeFrom(fd); + close(fd); + +out: + if (!success) { + LOGW("failed to remove signature from %s: %s\n", filename, strerror(errno)); + } + return success; +} + +bool ObbFile::removeFrom(int fd) +{ + if (fd < 0) { + return false; + } + + if (!readFrom(fd)) { + return false; + } + + ftruncate(fd, mFooterStart); + + return true; +} + } diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp index 4eb63e8c66da..947ff3409390 100644 --- a/media/libmedia/IMediaRecorder.cpp +++ b/media/libmedia/IMediaRecorder.cpp @@ -23,6 +23,7 @@ #include <camera/ICamera.h> #include <media/IMediaRecorderClient.h> #include <media/IMediaRecorder.h> +#include <unistd.h> namespace android { @@ -373,6 +374,7 @@ status_t BnMediaRecorder::onTransact( int64_t offset = data.readInt64(); int64_t length = data.readInt64(); reply->writeInt32(setOutputFile(fd, offset, length)); + ::close(fd); return NO_ERROR; } break; case SET_VIDEO_SIZE: { diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index f6f89c7a1cad..8481d4935c4e 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -55,11 +55,6 @@ StagefrightRecorder::StagefrightRecorder() StagefrightRecorder::~StagefrightRecorder() { LOGV("Destructor"); stop(); - - if (mOutputFd >= 0) { - ::close(mOutputFd); - mOutputFd = -1; - } } status_t StagefrightRecorder::init() { @@ -1084,6 +1079,11 @@ status_t StagefrightRecorder::stop() { mFlags = 0; } + if (mOutputFd >= 0) { + ::close(mOutputFd); + mOutputFd = -1; + } + return OK; } diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 9c48daf9348a..3e31d6155aa0 100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -244,6 +244,7 @@ void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) { void CameraSource::signalBufferReturned(MediaBuffer *buffer) { LOGV("signalBufferReturned: %p", buffer->data()); + Mutex::Autolock autoLock(mLock); for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin(); it != mFramesBeingEncoded.end(); ++it) { if ((*it)->pointer() == buffer->data()) { @@ -312,6 +313,7 @@ status_t CameraSource::read( (*buffer)->setObserver(this); (*buffer)->add_ref(); (*buffer)->meta_data()->setInt64(kKeyTime, frameTime); + return OK; } } diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml index 246f9fc528ab..f70a1451c91c 100644 --- a/media/tests/MediaFrameworkTest/AndroidManifest.xml +++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml @@ -51,4 +51,9 @@ android:label="MediaRecorder stress tests InstrumentationRunner"> </instrumentation> + <instrumentation android:name=".MediaFrameworkPowerTestRunner" + android:targetPackage="com.android.mediaframeworktest" + android:label="Media Power tests InstrumentationRunner"> + </instrumentation> + </manifest> diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPowerTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPowerTestRunner.java new file mode 100755 index 000000000000..34db4dbd3bde --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkPowerTestRunner.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mediaframeworktest; + +import com.android.mediaframeworktest.power.MediaPlayerPowerTest; + +import junit.framework.TestSuite; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; + + +/** + * Instrumentation Test Runner for all MediaPlayer tests. + * + * Running all tests: + * + * adb shell am instrument \ + * -w com.android.mediaframeworktest/.MediaFrameworkPowerTestRunner + */ + +public class MediaFrameworkPowerTestRunner extends InstrumentationTestRunner { + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(MediaPlayerPowerTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return MediaFrameworkPowerTestRunner.class.getClassLoader(); + } +} + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/power/MediaPlayerPowerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/power/MediaPlayerPowerTest.java new file mode 100644 index 000000000000..9e91740ca5c2 --- /dev/null +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/power/MediaPlayerPowerTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.mediaframeworktest.power; + +import com.android.mediaframeworktest.MediaFrameworkTest; +import com.android.mediaframeworktest.MediaNames; +import android.media.MediaPlayer; +import android.os.Environment; +import android.test.ActivityInstrumentationTestCase2; +import android.util.Log; + +import java.io.File; + +/** + * Junit / Instrumentation test case for the power measurment the media player + */ +public class MediaPlayerPowerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { + private String TAG = "MediaPlayerPowerTest"; + private String MP3_POWERTEST = + Environment.getExternalStorageDirectory().toString() + "/power_sample_mp3.mp3"; + private String MP3_STREAM = "http://75.17.48.204:10088/power_media/power_sample_mp3.mp3"; + private String OGG_STREAM = "http://75.17.48.204:10088/power_media/power_sample_ogg.mp3"; + private String AAC_STREAM = "http://75.17.48.204:10088/power_media/power_sample_aac.mp3"; + + public MediaPlayerPowerTest() { + super("com.android.mediaframeworktest", MediaFrameworkTest.class); + } + + protected void setUp() throws Exception { + getActivity(); + super.setUp(); + + } + + public void audioPlayback(String filePath) { + try { + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(filePath); + mp.prepare(); + mp.start(); + Thread.sleep(200000); + mp.stop(); + mp.release(); + } catch (Exception e) { + Log.v(TAG, e.toString()); + assertTrue("MP3 Playback", false); + } + } + + // A very simple test case which start the audio player. + // Power measurment will be done in other application. + public void testPowerLocalMP3Playback() throws Exception { + audioPlayback(MP3_POWERTEST); + } + + public void testPowerStreamMP3Playback() throws Exception { + audioPlayback(MP3_STREAM); + } + + public void testPowerStreamOGGPlayback() throws Exception { + audioPlayback(OGG_STREAM); + } + + public void testPowerStreamAACPlayback() throws Exception { + audioPlayback(AAC_STREAM); + } +} diff --git a/native/android/Android.mk b/native/android/Android.mk index 950a1e9a7ad1..bd2b27af7f18 100644 --- a/native/android/Android.mk +++ b/native/android/Android.mk @@ -7,6 +7,7 @@ include $(CLEAR_VARS) # LOCAL_SRC_FILES:= \ asset_manager.cpp \ + configuration.cpp \ input.cpp \ looper.cpp \ native_activity.cpp \ diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp index 36c381ef1b84..3f7c1b69af17 100644 --- a/native/android/asset_manager.cpp +++ b/native/android/asset_manager.cpp @@ -17,7 +17,7 @@ #define LOG_TAG "NAsset" #include <utils/Log.h> -#include <android/asset_manager.h> +#include <android/asset_manager_jni.h> #include <utils/AssetManager.h> #include <utils/AssetDir.h> #include <utils/Asset.h> diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp new file mode 100644 index 000000000000..d76164ff418e --- /dev/null +++ b/native/android/configuration.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Configuration" +#include <utils/Log.h> + +#include <utils/AssetManager.h> + +#include <android_runtime/android_content_res_Configuration.h> + +using namespace android; + +AConfiguration* AConfiguration_new() { + AConfiguration* config = new AConfiguration; + memset(config, 0, sizeof(AConfiguration)); + return config; +} + +void AConfiguration_delete(AConfiguration* config) { + delete config; +} + +void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) { + ((AssetManager*)am)->getConfiguration(out); +} + +void AConfiguration_copy(AConfiguration* dest, AConfiguration* src) { + *dest = *src; +} + +int32_t AConfiguration_getMcc(AConfiguration* config) { + return config->mcc; +} + +int32_t AConfiguration_getMnc(AConfiguration* config) { + return config->mnc; +} + +void AConfiguration_getLanguage(AConfiguration* config, char* outLanguage) { + outLanguage[0] = config->language[0]; + outLanguage[1] = config->language[1]; +} + +void AConfiguration_getCountry(AConfiguration* config, char* outCountry) { + outCountry[0] = config->country[0]; + outCountry[1] = config->country[1]; +} + +int32_t AConfiguration_getOrientation(AConfiguration* config) { + return config->orientation; +} + +int32_t AConfiguration_getTouchscreen(AConfiguration* config) { + return config->touchscreen; +} + +int32_t AConfiguration_getDensity(AConfiguration* config) { + return config->density; +} + +int32_t AConfiguration_getKeyboard(AConfiguration* config) { + return config->keyboard; +} + +int32_t AConfiguration_getNavigation(AConfiguration* config) { + return config->navigation; +} + +int32_t AConfiguration_getKeysHidden(AConfiguration* config) { + return config->inputFlags&ResTable_config::MASK_KEYSHIDDEN; +} + +int32_t AConfiguration_getNavHidden(AConfiguration* config) { + return (config->inputFlags&ResTable_config::MASK_NAVHIDDEN) + >> ResTable_config::SHIFT_NAVHIDDEN; +} + +int32_t AConfiguration_getSdkVersion(AConfiguration* config) { + return config->sdkVersion; +} + +int32_t AConfiguration_getScreenSize(AConfiguration* config) { + return config->screenLayout&ResTable_config::MASK_SCREENSIZE; +} + +int32_t AConfiguration_getScreenLong(AConfiguration* config) { + return (config->screenLayout&ResTable_config::MASK_SCREENLONG) + >> ResTable_config::SHIFT_SCREENLONG; +} + +int32_t AConfiguration_getUiModeType(AConfiguration* config) { + return config->uiMode&ResTable_config::MASK_UI_MODE_TYPE; +} + +int32_t AConfiguration_getUiModeNight(AConfiguration* config) { + return (config->uiMode&ResTable_config::MASK_UI_MODE_NIGHT) + >> ResTable_config::SHIFT_UI_MODE_NIGHT; + +} + +// ---------------------------------------------------------------------- + +void AConfiguration_setMcc(AConfiguration* config, int32_t mcc) { + config->mcc = mcc; +} + +void AConfiguration_setMnc(AConfiguration* config, int32_t mnc) { + config->mnc = mnc; +} + +void AConfiguration_setLanguage(AConfiguration* config, const char* language) { + config->language[0] = language[0]; + config->language[1] = language[1]; +} + +void AConfiguration_setCountry(AConfiguration* config, const char* country) { + config->country[0] = country[0]; + config->country[1] = country[1]; +} + +void AConfiguration_setOrientation(AConfiguration* config, int32_t orientation) { + config->orientation = orientation; +} + +void AConfiguration_setTouchscreen(AConfiguration* config, int32_t touchscreen) { + config->touchscreen = touchscreen; +} + +void AConfiguration_setDensity(AConfiguration* config, int32_t density) { + config->density = density; +} + +void AConfiguration_setKeyboard(AConfiguration* config, int32_t keyboard) { + config->keyboard = keyboard; +} + +void AConfiguration_setNavigation(AConfiguration* config, int32_t navigation) { + config->navigation = navigation; +} + +void AConfiguration_setKeysHidden(AConfiguration* config, int32_t keysHidden) { + config->inputFlags = (config->inputFlags&~ResTable_config::MASK_KEYSHIDDEN) + | (keysHidden&ResTable_config::MASK_KEYSHIDDEN); +} + +void AConfiguration_setNavHidden(AConfiguration* config, int32_t navHidden) { + config->inputFlags = (config->inputFlags&~ResTable_config::MASK_NAVHIDDEN) + | ((navHidden<<ResTable_config::SHIFT_NAVHIDDEN)&ResTable_config::MASK_NAVHIDDEN); +} + +void AConfiguration_setSdkVersion(AConfiguration* config, int32_t sdkVersion) { + config->sdkVersion = sdkVersion; +} + +void AConfiguration_setScreenSize(AConfiguration* config, int32_t screenSize) { + config->screenLayout = (config->screenLayout&~ResTable_config::MASK_SCREENSIZE) + | (screenSize&ResTable_config::MASK_SCREENSIZE); +} + +void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong) { + config->screenLayout = (config->screenLayout&~ResTable_config::MASK_SCREENLONG) + | ((screenLong<<ResTable_config::SHIFT_SCREENLONG)&ResTable_config::MASK_SCREENLONG); +} + +void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType) { + config->uiMode = (config->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | (uiModeType&ResTable_config::MASK_UI_MODE_TYPE); +} + +void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight) { + config->uiMode = (config->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) + | ((uiModeNight<<ResTable_config::SHIFT_UI_MODE_NIGHT)&ResTable_config::MASK_UI_MODE_NIGHT); + +} + +// ---------------------------------------------------------------------- + +int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2) { + return (config1->diff(*config2)); +} + +int32_t AConfiguration_match(AConfiguration* base, AConfiguration* requested) { + return base->match(*requested); +} + +int32_t AConfiguration_isBetterThan(AConfiguration* base, AConfiguration* test, + AConfiguration* requested) { + return base->isBetterThan(*test, requested); +} diff --git a/native/copy-to-ndk.sh b/native/copy-to-ndk.sh new file mode 100644 index 000000000000..4f5a16a4b595 --- /dev/null +++ b/native/copy-to-ndk.sh @@ -0,0 +1,55 @@ +# Take care of copying current header files over to the correct +# location in the NDK. + +copyndkheaders() { + local CURR_PLATFORM=android-9 + local ALL_PLATFORMS="$CURR_PLATFORM android-8 android-5 android-4 android-3" + + local SRC_HEADERS=$ANDROID_BUILD_TOP/frameworks/base/native/include/android + local NDK_PLATFORMS=$ANDROID_BUILD_TOP/development/ndk/platforms + local DST_HEADERS=$NDK_PLATFORMS/$CURR_PLATFORM + + local SRC_LIB_ANDROID=$ANDROID_PRODUCT_OUT/system/lib/libandroid.so + local DST_LIB_ANDROID=$NDK_PLATFORMS/$CURR_PLATFORM/arch-arm/usr/lib/libandroid.so + + local didsomething="" + + #echo "SRC_HEADERS: $SRC_HEADERS" + + for i in $(cd $SRC_HEADERS; ls *.h); do + local src=$SRC_HEADERS/$i + local changed="" + for j in $ALL_PLATFORMS; do + local dst=$NDK_PLATFORMS/$j/arch-arm/usr/include/android/$i + if [ "$changed" == "" -a -e $dst ]; then + #echo "Exists: $dst" + if diff $src $dst >/dev/null; then + echo "$i: has not changed from $j" >/dev/null + changed="false" + else + changed="true" + echo "$i: has changed from $j" >/dev/null + fi + fi + done + if [ "$changed" == "true" -o "$changed" == "" ]; then + echo "Updating: $i" + cp $src $NDK_PLATFORMS/$CURR_PLATFORM/arch-arm/usr/include/android/$i + didsomething="true" + fi + done + + if diff $SRC_LIB_ANDROID $DST_LIB_ANDROID >/dev/null; then + echo "libandroid.so: has not changed" >/dev/null + else + echo "Updating: $DST_LIB_ANDROID" + cp $SRC_LIB_ANDROID $DST_LIB_ANDROID + didsomething="true" + fi + if [ "$didsomething" != "" ]; then + echo "Headers changed... rebuilding platforms." + sh $ANDROID_BUILD_TOP/ndk/build/tools/build-platforms.sh + fi +} + +copyndkheaders diff --git a/native/include/android/asset_manager.h b/native/include/android/asset_manager.h index 89989f8cc4f5..4fa0ef3a3a12 100644 --- a/native/include/android/asset_manager.h +++ b/native/include/android/asset_manager.h @@ -18,8 +18,6 @@ #ifndef ANDROID_ASSET_MANAGER_H #define ANDROID_ASSET_MANAGER_H -#include <jni.h> - #ifdef __cplusplus extern "C" { #endif @@ -43,14 +41,6 @@ enum { /** - * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager - * object. Note that the caller is responsible for obtaining and holding a VM reference - * to the jobject to prevent its being garbage collected while the native object is - * in use. - */ -AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager); - -/** * Open the named directory within the asset hierarchy. The directory can then * be inspected with the AAssetDir functions. To open the top-level directory, * pass in "" as the dirName. diff --git a/native/include/android/asset_manager_jni.h b/native/include/android/asset_manager_jni.h new file mode 100644 index 000000000000..aec2d3c97c07 --- /dev/null +++ b/native/include/android/asset_manager_jni.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_ASSET_MANAGER_JNI_H +#define ANDROID_ASSET_MANAGER_JNI_H + +#include <android/asset_manager.h> +#include <jni.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager + * object. Note that the caller is responsible for obtaining and holding a VM reference + * to the jobject to prevent its being garbage collected while the native object is + * in use. + */ +AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_ASSET_MANAGER_JNI_H diff --git a/native/include/android/configuration.h b/native/include/android/configuration.h new file mode 100644 index 000000000000..79b9b1e302ed --- /dev/null +++ b/native/include/android/configuration.h @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CONFIGURATION_H +#define ANDROID_CONFIGURATION_H + +#include <android/asset_manager.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct AConfiguration; +typedef struct AConfiguration AConfiguration; + +enum { + ACONFIGURATION_ORIENTATION_ANY = 0x0000, + ACONFIGURATION_ORIENTATION_PORT = 0x0001, + ACONFIGURATION_ORIENTATION_LAND = 0x0002, + ACONFIGURATION_ORIENTATION_SQUARE = 0x0003, + + ACONFIGURATION_TOUCHSCREEN_ANY = 0x0000, + ACONFIGURATION_TOUCHSCREEN_NOTOUCH = 0x0001, + ACONFIGURATION_TOUCHSCREEN_STYLUS = 0x0002, + ACONFIGURATION_TOUCHSCREEN_FINGER = 0x0003, + + ACONFIGURATION_DENSITY_DEFAULT = 0, + ACONFIGURATION_DENSITY_LOW = 120, + ACONFIGURATION_DENSITY_MEDIUM = 160, + ACONFIGURATION_DENSITY_HIGH = 240, + ACONFIGURATION_DENSITY_NONE = 0xffff, + + ACONFIGURATION_KEYBOARD_ANY = 0x0000, + ACONFIGURATION_KEYBOARD_NOKEYS = 0x0001, + ACONFIGURATION_KEYBOARD_QWERTY = 0x0002, + ACONFIGURATION_KEYBOARD_12KEY = 0x0003, + + ACONFIGURATION_NAVIGATION_ANY = 0x0000, + ACONFIGURATION_NAVIGATION_NONAV = 0x0001, + ACONFIGURATION_NAVIGATION_DPAD = 0x0002, + ACONFIGURATION_NAVIGATION_TRACKBALL = 0x0003, + ACONFIGURATION_NAVIGATION_WHEEL = 0x0004, + + ACONFIGURATION_KEYSHIDDEN_ANY = 0x0000, + ACONFIGURATION_KEYSHIDDEN_NO = 0x0001, + ACONFIGURATION_KEYSHIDDEN_YES = 0x0002, + ACONFIGURATION_KEYSHIDDEN_SOFT = 0x0003, + + ACONFIGURATION_NAVHIDDEN_ANY = 0x0000, + ACONFIGURATION_NAVHIDDEN_NO = 0x0001, + ACONFIGURATION_NAVHIDDEN_YES = 0x0002, + + ACONFIGURATION_SCREENSIZE_ANY = 0x00, + ACONFIGURATION_SCREENSIZE_SMALL = 0x01, + ACONFIGURATION_SCREENSIZE_NORMAL = 0x02, + ACONFIGURATION_SCREENSIZE_LARGE = 0x03, + ACONFIGURATION_SCREENSIZE_XLARGE = 0x04, + + ACONFIGURATION_SCREENLONG_ANY = 0x00, + ACONFIGURATION_SCREENLONG_NO = 0x1, + ACONFIGURATION_SCREENLONG_YES = 0x2, + + ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00, + ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01, + ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02, + ACONFIGURATION_UI_MODE_TYPE_CAR = 0x03, + + ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00, + ACONFIGURATION_UI_MODE_NIGHT_NO = 0x10, + ACONFIGURATION_UI_MODE_NIGHT_YES = 0x20, + + ACONFIGURATION_MCC = 0x0001, + ACONFIGURATION_MNC = 0x0002, + ACONFIGURATION_LOCALE = 0x0004, + ACONFIGURATION_TOUCHSCREEN = 0x0008, + ACONFIGURATION_KEYBOARD = 0x0010, + ACONFIGURATION_KEYBOARD_HIDDEN = 0x0020, + ACONFIGURATION_NAVIGATION = 0x0040, + ACONFIGURATION_ORIENTATION = 0x0080, + ACONFIGURATION_DENSITY = 0x0100, + ACONFIGURATION_SCREEN_SIZE = 0x0200, + ACONFIGURATION_VERSION = 0x0400, + ACONFIGURATION_SCREEN_LAYOUT = 0x0800, + ACONFIGURATION_UI_MODE = 0x1000, +}; + +/** + * Create a new AConfiguration, initialized with no values set. + */ +AConfiguration* AConfiguration_new(); + +/** + * Free an AConfiguration that was previously created with + * AConfiguration_new(). + */ +void AConfiguration_delete(AConfiguration* config); + +/** + * Create and return a new AConfiguration based on the current configuration in + * use in the given AssetManager. + */ +void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am); + +/** + * Copy the contents of 'src' to 'dest'. + */ +void AConfiguration_copy(AConfiguration* dest, AConfiguration* src); + +/** + * Return the current MCC set in the configuration. 0 if not set. + */ +int32_t AConfiguration_getMcc(AConfiguration* config); + +/** + * Set the current MCC in the configuration. 0 to clear. + */ +void AConfiguration_setMcc(AConfiguration* config, int32_t mcc); + +/** + * Return the current MNC set in the configuration. 0 if not set. + */ +int32_t AConfiguration_getMnc(AConfiguration* config); + +/** + * Set the current MNC in the configuration. 0 to clear. + */ +void AConfiguration_setMnc(AConfiguration* config, int32_t mnc); + +/** + * Return the current language code set in the configuration. The output will + * be filled with an array of two characters. They are not 0-terminated. If + * a language is not set, they will be 0. + */ +void AConfiguration_getLanguage(AConfiguration* config, char* outLanguage); + +/** + * Set the current language code in the configuration, from the first two + * characters in the string. + */ +void AConfiguration_setLanguage(AConfiguration* config, const char* language); + +/** + * Return the current country code set in the configuration. The output will + * be filled with an array of two characters. They are not 0-terminated. If + * a country is not set, they will be 0. + */ +void AConfiguration_getCountry(AConfiguration* config, char* outCountry); + +/** + * Set the current country code in the configuration, from the first two + * characters in the string. + */ +void AConfiguration_setCountry(AConfiguration* config, const char* country); + +/** + * Return the current ACONFIGURATION_ORIENTATION_* set in the configuration. + */ +int32_t AConfiguration_getOrientation(AConfiguration* config); + +/** + * Set the current orientation in the configuration. + */ +void AConfiguration_setOrientation(AConfiguration* config, int32_t orientation); + +/** + * Return the current ACONFIGURATION_TOUCHSCREEN_* set in the configuration. + */ +int32_t AConfiguration_getTouchscreen(AConfiguration* config); + +/** + * Set the current touchscreen in the configuration. + */ +void AConfiguration_setTouchscreen(AConfiguration* config, int32_t touchscreen); + +/** + * Return the current ACONFIGURATION_DENSITY_* set in the configuration. + */ +int32_t AConfiguration_getDensity(AConfiguration* config); + +/** + * Set the current density in the configuration. + */ +void AConfiguration_setDensity(AConfiguration* config, int32_t density); + +/** + * Return the current ACONFIGURATION_KEYBOARD_* set in the configuration. + */ +int32_t AConfiguration_getKeyboard(AConfiguration* config); + +/** + * Set the current keyboard in the configuration. + */ +void AConfiguration_setKeyboard(AConfiguration* config, int32_t keyboard); + +/** + * Return the current ACONFIGURATION_NAVIGATION_* set in the configuration. + */ +int32_t AConfiguration_getNavigation(AConfiguration* config); + +/** + * Set the current navigation in the configuration. + */ +void AConfiguration_setNavigation(AConfiguration* config, int32_t navigation); + +/** + * Return the current ACONFIGURATION_KEYSHIDDEN_* set in the configuration. + */ +int32_t AConfiguration_getKeysHidden(AConfiguration* config); + +/** + * Set the current keys hidden in the configuration. + */ +void AConfiguration_setKeysHidden(AConfiguration* config, int32_t keysHidden); + +/** + * Return the current ACONFIGURATION_NAVHIDDEN_* set in the configuration. + */ +int32_t AConfiguration_getNavHidden(AConfiguration* config); + +/** + * Set the current nav hidden in the configuration. + */ +void AConfiguration_setNavHidden(AConfiguration* config, int32_t navHidden); + +/** + * Return the current SDK (API) version set in the configuration. + */ +int32_t AConfiguration_getSdkVersion(AConfiguration* config); + +/** + * Set the current SDK version in the configuration. + */ +void AConfiguration_setSdkVersion(AConfiguration* config, int32_t sdkVersion); + +/** + * Return the current ACONFIGURATION_SCREENSIZE_* set in the configuration. + */ +int32_t AConfiguration_getScreenSize(AConfiguration* config); + +/** + * Set the current screen size in the configuration. + */ +void AConfiguration_setScreenSize(AConfiguration* config, int32_t screenSize); + +/** + * Return the current ACONFIGURATION_SCREENLONG_* set in the configuration. + */ +int32_t AConfiguration_getScreenLong(AConfiguration* config); + +/** + * Set the current screen long in the configuration. + */ +void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong); + +/** + * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration. + */ +int32_t AConfiguration_getUiModeType(AConfiguration* config); + +/** + * Set the current UI mode type in the configuration. + */ +void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType); + +/** + * Return the current ACONFIGURATION_UI_MODE_NIGHT_* set in the configuration. + */ +int32_t AConfiguration_getUiModeNight(AConfiguration* config); + +/** + * Set the current UI mode night in the configuration. + */ +void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight); + +/** + * Perform a diff between two configurations. Returns a bit mask of + * ACONFIGURATION_* constants, each bit set meaning that configuration element + * is different between them. + */ +int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2); + +/** + * Determine whether 'base' is a valid configuration for use within the + * environment 'requested'. Returns 0 if there are any values in 'base' + * that conflict with 'requested'. Returns 1 if it does not conflict. + */ +int32_t AConfiguration_match(AConfiguration* base, AConfiguration* requested); + +/** + * Determine whether the configuration in 'test' is better than the existing + * configuration in 'base'. If 'requested' is non-NULL, this decision is based + * on the overall configuration given there. If it is NULL, this decision is + * simply based on which configuration is more specific. Returns non-0 if + * 'test' is better than 'base'. + * + * This assumes you have already filtered the configurations with + * AConfiguration_match(). + */ +int32_t AConfiguration_isBetterThan(AConfiguration* base, AConfiguration* test, + AConfiguration* requested); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_CONFIGURATION_H diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h index ee4204d884f2..d74e1ce5a3d3 100644 --- a/native/include/android/native_activity.h +++ b/native/include/android/native_activity.h @@ -197,6 +197,12 @@ typedef struct ANativeActivityCallbacks { void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect); /** + * The current device AConfiguration has changed. The new configuration can + * be retrieved from assetManager. + */ + void (*onConfigurationChanged)(ANativeActivity* activity); + + /** * The system is running low on memory. Use this callback to release * resources you do not need, to help the system avoid killing more * important processes. @@ -208,7 +214,9 @@ typedef struct ANativeActivityCallbacks { * This is the function that must be in the native code to instantiate the * application's native activity. It is called with the activity instance (see * above); if the code is being instantiated from a previously saved instance, - * the savedState will be non-NULL and point to the saved data. + * the savedState will be non-NULL and point to the saved data. You must make + * any copy of this data you need -- it will be released after you return from + * this function. */ typedef void ANativeActivity_createFunc(ANativeActivity* activity, void* savedState, size_t savedStateSize); diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h index 7599d7e550f6..ad03d0e930da 100644 --- a/native/include/android/native_window.h +++ b/native/include/android/native_window.h @@ -36,12 +36,23 @@ struct ANativeWindow; typedef struct ANativeWindow ANativeWindow; typedef struct ANativeWindow_Buffer { + // The number of pixels that are show horizontally. int32_t width; + + // The number of pixels that are shown vertically. int32_t height; + + // The number of *pixels* that a line in the buffer takes in + // memory. This may be >= width. int32_t stride; + + // The format of the buffer. One of WINDOW_FORMAT_* int32_t format; + + // The actual bits. void* bits; + // Do not touch. uint32_t reserved[6]; } ANativeWindow_Buffer; diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index f1c6532a90fb..c6e0a2423a1f 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -24,6 +24,8 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageParser; +import android.content.res.ObbInfo; +import android.content.res.ObbScanner; import android.net.Uri; import android.os.Environment; import android.os.IBinder; @@ -142,6 +144,10 @@ public class DefaultContainerService extends IntentService { public boolean checkFreeStorage(boolean external, Uri fileUri) { return checkFreeStorageInner(external, fileUri); } + + public ObbInfo getObbInfo(String filename) { + return ObbScanner.getObbInfo(filename); + } }; public DefaultContainerService() { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 83d9c47c4a04..e2e6f1a14983 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -37,6 +37,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.LocalPowerManager; +import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; @@ -48,15 +49,20 @@ import android.provider.Settings; import com.android.internal.policy.PolicyManager; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.telephony.ITelephony; +import com.android.internal.view.BaseInputHandler; import com.android.internal.widget.PointerLocationView; import android.util.Config; import android.util.EventLog; import android.util.Log; +import android.util.Slog; import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.IWindowManager; +import android.view.InputChannel; +import android.view.InputQueue; +import android.view.InputHandler; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.WindowOrientationListener; @@ -220,6 +226,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mPointerLocationMode = 0; PointerLocationView mPointerLocationView = null; + InputChannel mPointerLocationInputChannel; + + private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() { + @Override + public void handleMotion(MotionEvent event, Runnable finishedCallback) { + finishedCallback.run(); + synchronized (mLock) { + mPointerLocationView.addTouchEvent(event); + } + } + }; // The current size of the screen. int mW, mH; @@ -613,8 +630,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); wm.addView(addView, lp); + + if (mPointerLocationInputChannel == null) { + try { + mPointerLocationInputChannel = + mWindowManager.monitorInput("PointerLocationView"); + InputQueue.registerInputChannel(mPointerLocationInputChannel, + mPointerLocationInputHandler, mHandler.getLooper().getQueue()); + } catch (RemoteException ex) { + Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.", + ex); + } + } } if (removeView != null) { + if (mPointerLocationInputChannel != null) { + InputQueue.unregisterInputChannel(mPointerLocationInputChannel); + mPointerLocationInputChannel.dispose(); + mPointerLocationInputChannel = null; + } + WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); wm.removeView(removeView); @@ -728,20 +763,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { : Configuration.KEYBOARDHIDDEN_YES; } - public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY) { - if (mPointerLocationView == null) { - return; - } - synchronized (mLock) { - if (mPointerLocationView == null) { - return; - } - ev.offsetLocation(targetX, targetY); - mPointerLocationView.addTouchEvent(ev); - ev.offsetLocation(-targetX, -targetY); - } - } - /** {@inheritDoc} */ public int windowTypeToLayerLw(int type) { if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index 91951233fca1..c2c799b4e0a0 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -75,7 +75,8 @@ public class InputManager { int sw); private static native boolean nativeHasKeys(int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); - private static native void nativeRegisterInputChannel(InputChannel inputChannel); + private static native void nativeRegisterInputChannel(InputChannel inputChannel, + boolean monitor); private static native void nativeUnregisterInputChannel(InputChannel inputChannel); private static native int nativeInjectInputEvent(InputEvent event, int injectorPid, int injectorUid, int syncMode, int timeoutMillis); @@ -225,14 +226,38 @@ public class InputManager { return nativeHasKeys(deviceId, sourceMask, keyCodes, keyExists); } + /** + * Creates an input channel that will receive all input from the input dispatcher. + * @param inputChannelName The input channel name. + * @return The input channel. + */ + public InputChannel monitorInput(String inputChannelName) { + if (inputChannelName == null) { + throw new IllegalArgumentException("inputChannelName must not be null."); + } + + InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); + nativeRegisterInputChannel(inputChannels[0], true); + inputChannels[0].dispose(); // don't need to retain the Java object reference + return inputChannels[1]; + } + + /** + * Registers an input channel so that it can be used as an input event target. + * @param inputChannel The input channel to register. + */ public void registerInputChannel(InputChannel inputChannel) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } - nativeRegisterInputChannel(inputChannel); + nativeRegisterInputChannel(inputChannel, false); } + /** + * Unregisters an input channel. + * @param inputChannel The input channel to unregister. + */ public void unregisterInputChannel(InputChannel inputChannel) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index d7b92ec0ae71..344bfc1421a0 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -16,34 +16,42 @@ package com.android.server; +import com.android.internal.app.IMediaContainerService; import com.android.server.am.ActivityManagerService; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.res.ObbInfo; -import android.content.res.ObbScanner; import android.net.Uri; -import android.os.storage.IMountService; -import android.os.storage.IMountServiceListener; -import android.os.storage.IMountShutdownObserver; -import android.os.storage.StorageResultCode; import android.os.Binder; +import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.os.IBinder; -import android.os.Environment; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.storage.IMountService; +import android.os.storage.IMountServiceListener; +import android.os.storage.IMountShutdownObserver; +import android.os.storage.IObbActionListener; +import android.os.storage.StorageResultCode; import android.util.Slog; + import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; /** * MountService implements back-end services for platform storage @@ -135,9 +143,77 @@ class MountService extends IMountService.Stub final private HashSet<String> mAsecMountSet = new HashSet<String>(); /** - * Private hash of currently mounted filesystem images. + * Mounted OBB tracking information. Used to track the current state of all + * OBBs. + */ + final private Map<IObbActionListener, ObbState> mObbMounts = new HashMap<IObbActionListener, ObbState>(); + final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); + + class ObbState implements IBinder.DeathRecipient { + public ObbState(String filename, IObbActionListener token, int callerUid) { + this.filename = filename; + this.token = token; + this.callerUid = callerUid; + mounted = false; + } + + // OBB source filename + String filename; + + // Token of remote Binder caller + IObbActionListener token; + + // Binder.callingUid() + public int callerUid; + + // Whether this is mounted currently. + boolean mounted; + + @Override + public void binderDied() { + ObbAction action = new UnmountObbAction(this, true); + mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); + + removeObbState(this); + + token.asBinder().unlinkToDeath(this, 0); + } + } + + // OBB Action Handler + final private ObbActionHandler mObbActionHandler; + + // OBB action handler messages + private static final int OBB_RUN_ACTION = 1; + private static final int OBB_MCS_BOUND = 2; + private static final int OBB_MCS_UNBIND = 3; + private static final int OBB_MCS_RECONNECT = 4; + private static final int OBB_MCS_GIVE_UP = 5; + + /* + * Default Container Service information */ - final private HashSet<String> mObbMountSet = new HashSet<String>(); + static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( + "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); + + final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); + + class DefaultContainerConnection implements ServiceConnection { + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG_OBB) + Slog.i(TAG, "onServiceConnected"); + IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); + mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); + } + + public void onServiceDisconnected(ComponentName name) { + if (DEBUG_OBB) + Slog.i(TAG, "onServiceDisconnected"); + } + }; + + // Used in the ObbActionHandler + private IMediaContainerService mContainerService = null; // Handler messages private static final int H_UNMOUNT_PM_UPDATE = 1; @@ -359,7 +435,7 @@ class MountService extends IMountService.Stub public void binderDied() { if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); - synchronized(mListeners) { + synchronized (mListeners) { mListeners.remove(this); mListener.asBinder().unlinkToDeath(this, 0); } @@ -904,6 +980,9 @@ class MountService extends IMountService.Stub mHandlerThread.start(); mHandler = new MountServiceHandler(mHandlerThread.getLooper()); + // Add OBB Action Handler to MountService thread. + mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); + /* * Vold does not run in the simulator, so pretend the connector thread * ran and did its thing. @@ -1338,12 +1417,16 @@ class MountService extends IMountService.Stub mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); } - private boolean isCallerOwnerOfPackage(String packageName) { + private boolean isCallerOwnerOfPackageOrSystem(String packageName) { final int callerUid = Binder.getCallingUid(); - return isUidOwnerOfPackage(packageName, callerUid); + return isUidOwnerOfPackageOrSystem(packageName, callerUid); } - private boolean isUidOwnerOfPackage(String packageName, int callerUid) { + private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { + if (callerUid == android.os.Process.SYSTEM_UID) { + return true; + } + if (packageName == null) { return false; } @@ -1362,12 +1445,6 @@ class MountService extends IMountService.Stub waitForReady(); warnOnNotMounted(); - // XXX replace with call to IMediaContainerService - ObbInfo obbInfo = ObbScanner.getObbInfo(filename); - if (!isCallerOwnerOfPackage(obbInfo.packageName)) { - throw new IllegalArgumentException("Caller package does not match OBB file"); - } - try { ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename)); String []tok = rsp.get(0).split(" "); @@ -1379,7 +1456,7 @@ class MountService extends IMountService.Stub } catch (NativeDaemonConnectorException e) { int code = e.getCode(); if (code == VoldResponseCode.OpFailedStorageNotFound) { - throw new IllegalArgumentException(String.format("OBB '%s' not found", filename)); + return null; } else { throw new IllegalStateException(String.format("Unexpected response code %d", code)); } @@ -1387,95 +1464,390 @@ class MountService extends IMountService.Stub } public boolean isObbMounted(String filename) { + synchronized (mObbMounts) { + return mObbPathToStateMap.containsKey(filename); + } + } + + public void mountObb(String filename, String key, IObbActionListener token) { waitForReady(); warnOnNotMounted(); - // XXX replace with call to IMediaContainerService - ObbInfo obbInfo = ObbScanner.getObbInfo(filename); - if (!isCallerOwnerOfPackage(obbInfo.packageName)) { - throw new IllegalArgumentException("Caller package does not match OBB file"); + final ObbState obbState; + + synchronized (mObbMounts) { + if (isObbMounted(filename)) { + throw new IllegalArgumentException("OBB file is already mounted"); + } + + if (mObbMounts.containsKey(token)) { + throw new IllegalArgumentException("You may only have one OBB mounted at a time"); + } + + final int callerUid = Binder.getCallingUid(); + obbState = new ObbState(filename, token, callerUid); + addObbState(obbState); } - synchronized (mObbMountSet) { - return mObbMountSet.contains(filename); + try { + token.asBinder().linkToDeath(obbState, 0); + } catch (RemoteException rex) { + Slog.e(TAG, "Failed to link to listener death"); } + + MountObbAction action = new MountObbAction(obbState, key); + mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); + + if (DEBUG_OBB) + Slog.i(TAG, "Send to OBB handler: " + action.toString()); } - public int mountObb(String filename, String key) { - waitForReady(); - warnOnNotMounted(); + public void unmountObb(String filename, boolean force, IObbActionListener token) { + final ObbState obbState; - synchronized (mObbMountSet) { - if (mObbMountSet.contains(filename)) { - return StorageResultCode.OperationFailedStorageMounted; + synchronized (mObbMounts) { + if (!isObbMounted(filename)) { + throw new IllegalArgumentException("OBB is not mounted"); } + obbState = mObbPathToStateMap.get(filename); } - final int callerUid = Binder.getCallingUid(); + UnmountObbAction action = new UnmountObbAction(obbState, force); + mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); + + if (DEBUG_OBB) + Slog.i(TAG, "Send to OBB handler: " + action.toString()); + } - // XXX replace with call to IMediaContainerService - ObbInfo obbInfo = ObbScanner.getObbInfo(filename); - if (!isUidOwnerOfPackage(obbInfo.packageName, callerUid)) { - throw new IllegalArgumentException("Caller package does not match OBB file"); + private void addObbState(ObbState obbState) { + synchronized (mObbMounts) { + mObbMounts.put(obbState.token, obbState); + mObbPathToStateMap.put(obbState.filename, obbState); } + } - if (key == null) { - key = "none"; + private void removeObbState(ObbState obbState) { + synchronized (mObbMounts) { + mObbMounts.remove(obbState.token); + mObbPathToStateMap.remove(obbState.filename); } + } - int rc = StorageResultCode.OperationSucceeded; - String cmd = String.format("obb mount %s %s %d", filename, key, callerUid); - try { - mConnector.doCommand(cmd); - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code != VoldResponseCode.OpFailedStorageBusy) { - rc = StorageResultCode.OperationFailedInternalError; + private class ObbActionHandler extends Handler { + private boolean mBound = false; + private List<ObbAction> mActions = new LinkedList<ObbAction>(); + + ObbActionHandler(Looper l) { + super(l); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case OBB_RUN_ACTION: { + ObbAction action = (ObbAction) msg.obj; + + if (DEBUG_OBB) + Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); + + // If a bind was already initiated we don't really + // need to do anything. The pending install + // will be processed later on. + if (!mBound) { + // If this is the only one pending we might + // have to bind to the service again. + if (!connectToService()) { + Slog.e(TAG, "Failed to bind to media container service"); + action.handleError(); + return; + } else { + // Once we bind to the service, the first + // pending request will be processed. + mActions.add(action); + } + } else { + // Already bound to the service. Just make + // sure we trigger off processing the first request. + if (mActions.size() == 0) { + mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); + } + + mActions.add(action); + } + break; + } + case OBB_MCS_BOUND: { + if (DEBUG_OBB) + Slog.i(TAG, "OBB_MCS_BOUND"); + if (msg.obj != null) { + mContainerService = (IMediaContainerService) msg.obj; + } + if (mContainerService == null) { + // Something seriously wrong. Bail out + Slog.e(TAG, "Cannot bind to media container service"); + for (ObbAction action : mActions) { + // Indicate service bind error + action.handleError(); + } + mActions.clear(); + } else if (mActions.size() > 0) { + ObbAction action = mActions.get(0); + if (action != null) { + action.execute(this); + } + } else { + // Should never happen ideally. + Slog.w(TAG, "Empty queue"); + } + break; + } + case OBB_MCS_RECONNECT: { + if (DEBUG_OBB) + Slog.i(TAG, "OBB_MCS_RECONNECT"); + if (mActions.size() > 0) { + if (mBound) { + disconnectService(); + } + if (!connectToService()) { + Slog.e(TAG, "Failed to bind to media container service"); + for (ObbAction action : mActions) { + // Indicate service bind error + action.handleError(); + } + mActions.clear(); + } + } + break; + } + case OBB_MCS_UNBIND: { + if (DEBUG_OBB) + Slog.i(TAG, "OBB_MCS_UNBIND"); + + // Delete pending install + if (mActions.size() > 0) { + mActions.remove(0); + } + if (mActions.size() == 0) { + if (mBound) { + disconnectService(); + } + } else { + // There are more pending requests in queue. + // Just post MCS_BOUND message to trigger processing + // of next pending install. + mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); + } + break; + } + case OBB_MCS_GIVE_UP: { + if (DEBUG_OBB) + Slog.i(TAG, "OBB_MCS_GIVE_UP"); + mActions.remove(0); + break; + } } } - if (rc == StorageResultCode.OperationSucceeded) { - synchronized (mObbMountSet) { - mObbMountSet.add(filename); + private boolean connectToService() { + if (DEBUG_OBB) + Slog.i(TAG, "Trying to bind to DefaultContainerService"); + + Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); + if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { + mBound = true; + return true; } + return false; + } + + private void disconnectService() { + mContainerService = null; + mBound = false; + mContext.unbindService(mDefContainerConn); } - return rc; } - public int unmountObb(String filename, boolean force) { - waitForReady(); - warnOnNotMounted(); + abstract class ObbAction { + private static final int MAX_RETRIES = 3; + private int mRetries; - ObbInfo obbInfo = ObbScanner.getObbInfo(filename); - if (!isCallerOwnerOfPackage(obbInfo.packageName)) { - throw new IllegalArgumentException("Caller package does not match OBB file"); + ObbState mObbState; + + ObbAction(ObbState obbState) { + mObbState = obbState; } - synchronized (mObbMountSet) { - if (!mObbMountSet.contains(filename)) { - return StorageResultCode.OperationFailedStorageNotMounted; + public void execute(ObbActionHandler handler) { + try { + if (DEBUG_OBB) + Slog.i(TAG, "Starting to execute action: " + this.toString()); + mRetries++; + if (mRetries > MAX_RETRIES) { + Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); + mObbActionHandler.sendEmptyMessage(OBB_MCS_GIVE_UP); + handleError(); + return; + } else { + handleExecute(); + if (DEBUG_OBB) + Slog.i(TAG, "Posting install MCS_UNBIND"); + mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); + } + } catch (RemoteException e) { + if (DEBUG_OBB) + Slog.i(TAG, "Posting install MCS_RECONNECT"); + mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); + } catch (Exception e) { + if (DEBUG_OBB) + Slog.d(TAG, "Error handling OBB action", e); + handleError(); } - } + } - int rc = StorageResultCode.OperationSucceeded; - String cmd = String.format("obb unmount %s%s", filename, (force ? " force" : "")); - try { - mConnector.doCommand(cmd); - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedStorageBusy) { - rc = StorageResultCode.OperationFailedStorageBusy; + abstract void handleExecute() throws RemoteException; + abstract void handleError(); + } + + class MountObbAction extends ObbAction { + private String mKey; + + MountObbAction(ObbState obbState, String key) { + super(obbState); + mKey = key; + } + + public void handleExecute() throws RemoteException { + ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename); + if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) { + throw new IllegalArgumentException("Caller package does not match OBB file"); + } + + if (mKey == null) { + mKey = "none"; + } + + int rc = StorageResultCode.OperationSucceeded; + String cmd = String.format("obb mount %s %s %d", mObbState.filename, mKey, + mObbState.callerUid); + try { + mConnector.doCommand(cmd); + } catch (NativeDaemonConnectorException e) { + int code = e.getCode(); + if (code != VoldResponseCode.OpFailedStorageBusy) { + rc = StorageResultCode.OperationFailedInternalError; + } + } + + if (rc == StorageResultCode.OperationSucceeded) { + try { + mObbState.token.onObbResult(mObbState.filename, "mounted"); + } catch (RemoteException e) { + Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); + } } else { - rc = StorageResultCode.OperationFailedInternalError; + Slog.e(TAG, "Couldn't mount OBB file"); + + // We didn't succeed, so remove this from the mount-set. + removeObbState(mObbState); } } - if (rc == StorageResultCode.OperationSucceeded) { - synchronized (mObbMountSet) { - mObbMountSet.remove(filename); + public void handleError() { + removeObbState(mObbState); + + try { + mObbState.token.onObbResult(mObbState.filename, "error"); + } catch (RemoteException e) { + Slog.e(TAG, "Couldn't send back OBB mount error for " + mObbState.filename); } } - return rc; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("MountObbAction{"); + sb.append("filename="); + sb.append(mObbState.filename); + sb.append(",callerUid="); + sb.append(mObbState.callerUid); + sb.append(",token="); + sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL"); + sb.append('}'); + return sb.toString(); + } + } + + class UnmountObbAction extends ObbAction { + private boolean mForceUnmount; + + UnmountObbAction(ObbState obbState, boolean force) { + super(obbState); + mForceUnmount = force; + } + + public void handleExecute() throws RemoteException { + ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename); + + if (!isCallerOwnerOfPackageOrSystem(obbInfo.packageName)) { + throw new IllegalArgumentException("Caller package does not match OBB file"); + } + + int rc = StorageResultCode.OperationSucceeded; + String cmd = String.format("obb unmount %s%s", mObbState.filename, + (mForceUnmount ? " force" : "")); + try { + mConnector.doCommand(cmd); + } catch (NativeDaemonConnectorException e) { + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedStorageBusy) { + rc = StorageResultCode.OperationFailedStorageBusy; + } else { + rc = StorageResultCode.OperationFailedInternalError; + } + } + + if (rc == StorageResultCode.OperationSucceeded) { + removeObbState(mObbState); + + try { + mObbState.token.onObbResult(mObbState.filename, "unmounted"); + } catch (RemoteException e) { + Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); + } + } else { + try { + mObbState.token.onObbResult(mObbState.filename, "error"); + } catch (RemoteException e) { + Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); + } + } + } + + public void handleError() { + removeObbState(mObbState); + + try { + mObbState.token.onObbResult(mObbState.filename, "error"); + } catch (RemoteException e) { + Slog.e(TAG, "Couldn't send back OBB unmount error for " + mObbState.filename); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("UnmountObbAction{"); + sb.append("filename="); + sb.append(mObbState.filename != null ? mObbState.filename : "null"); + sb.append(",force="); + sb.append(mForceUnmount); + sb.append(",callerUid="); + sb.append(mObbState.callerUid); + sb.append(",token="); + sb.append(mObbState.token != null ? mObbState.token.toString() : "null"); + sb.append('}'); + return sb.toString(); + } } } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 0def5f23fc26..59deef3eaefe 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -62,10 +62,14 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; +import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; +import android.graphics.Typeface; +import android.graphics.Paint.FontMetricsInt; import android.os.BatteryStats; import android.os.Binder; import android.os.Bundle; @@ -92,6 +96,7 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; +import android.util.TypedValue; import android.view.Display; import android.view.Gravity; import android.view.HapticFeedbackConstants; @@ -115,6 +120,7 @@ import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; +import android.view.Surface.OutOfResourcesException; import android.view.WindowManager.LayoutParams; import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; @@ -370,6 +376,7 @@ public class WindowManagerService extends IWindowManager.Stub private DimAnimator mDimAnimator = null; Surface mBlurSurface; boolean mBlurShown; + Watermark mWatermark; int mTransactionSequence = 0; @@ -4382,11 +4389,19 @@ public class WindowManagerService extends IWindowManager.Stub } return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, sw); } - + public boolean hasKeys(int[] keycodes, boolean[] keyExists) { return mInputManager.hasKeys(-1, InputDevice.SOURCE_ANY, keycodes, keyExists); } + public InputChannel monitorInput(String inputChannelName) { + if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE, + "monitorInput()")) { + throw new SecurityException("Requires READ_INPUT_STATE permission"); + } + return mInputManager.monitorInput(inputChannelName); + } + public void enableScreenAfterBoot() { synchronized(mWindowMap) { if (mSystemBooted) { @@ -8507,12 +8522,6 @@ public class WindowManagerService extends IWindowManager.Stub updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES); } - if (mFxSession == null) { - mFxSession = new SurfaceSession(); - } - - if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION"); - // Initialize state of exiting tokens. for (i=mExitingTokens.size()-1; i>=0; i--) { mExitingTokens.get(i).hasVisible = false; @@ -8529,8 +8538,24 @@ public class WindowManagerService extends IWindowManager.Stub float buttonBrightness = -1; boolean focusDisplayed = false; boolean animating = false; + boolean createWatermark = false; + + if (mFxSession == null) { + mFxSession = new SurfaceSession(); + createWatermark = true; + } + + if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION"); Surface.openTransaction(); + + if (createWatermark) { + createWatermark(); + } + if (mWatermark != null) { + mWatermark.positionSurface(dw, dh); + } + try { boolean wallpaperForceHidingChanged = false; int repeats = 0; @@ -10047,6 +10072,93 @@ public class WindowManagerService extends IWindowManager.Stub mScreenFrozenLock.release(); } + static int getPropertyInt(String name, int defUnits, int defDps, DisplayMetrics dm) { + String str = SystemProperties.get(name); + try { + int val = Integer.parseInt(str); + return val; + } catch (Exception e) { + } + if (defUnits == TypedValue.COMPLEX_UNIT_PX) { + return defDps; + } + int val = (int)TypedValue.applyDimension(defUnits, defDps, dm); + return val; + } + + class Watermark { + Surface mSurface; + int mWidth; + int mHeight; + int mXPercent; + int mYPercent; + + Watermark(SurfaceSession session, String text) { + final DisplayMetrics dm = new DisplayMetrics(); + mDisplay.getMetrics(dm); + + int fontSize = getPropertyInt("ro.watermark.height", + TypedValue.COMPLEX_UNIT_DIP, 48, dm); + mXPercent = getPropertyInt("ro.watermark.x", + TypedValue.COMPLEX_UNIT_PX, 50, dm); + mYPercent = getPropertyInt("ro.watermark.y", + TypedValue.COMPLEX_UNIT_PX, 99, dm); + int color = getPropertyInt("ro.watermark.color", + TypedValue.COMPLEX_UNIT_PX, 0x80ffffff, dm); + int shadowRadius = getPropertyInt("ro.watermark.shadow.radius", + TypedValue.COMPLEX_UNIT_PX, 5, dm); + int shadowDx = getPropertyInt("ro.watermark.shadow.dx", + TypedValue.COMPLEX_UNIT_PX, 0, dm); + int shadowDy = getPropertyInt("ro.watermark.shadow.dy", + TypedValue.COMPLEX_UNIT_PX, 0, dm); + int shadowColor = getPropertyInt("ro.watermark.shadow.color", + TypedValue.COMPLEX_UNIT_PX, 0xff000000, dm); + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setTextSize(fontSize); + paint.setColor(color); + paint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor); + paint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)); + + FontMetricsInt fm = paint.getFontMetricsInt(); + mHeight = fm.descent - fm.ascent + 20; + mWidth = (int)paint.measureText(text) + 20; + + try { + mSurface = new Surface(session, 0, + "WatermarkSurface", + -1, mWidth, mHeight, PixelFormat.TRANSLUCENT, 0); + mSurface.setLayer(TYPE_LAYER_MULTIPLIER*100); + Rect dirty = new Rect(0, 0, mWidth, mHeight); + Canvas c = mSurface.lockCanvas(dirty); + c.drawText(text, 10, -fm.ascent+10, paint); + mSurface.unlockCanvasAndPost(c); + mSurface.show(); + } catch (OutOfResourcesException e) { + } + } + + void positionSurface(int dw, int dh) { + int availW = dw - mWidth; + int availH = dh - mHeight; + mSurface.setPosition((availW*mXPercent)/100, + (availH*mYPercent)/100); + } + } + + void createWatermark() { + if (mWatermark != null) { + return; + } + + String text = SystemProperties.get("ro.watermark.text"); + if (text == null || text.length() <= 0) { + return; + } + + mWatermark = new Watermark(mFxSession, text); + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission("android.permission.DUMP") diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 162fffef5d2b..dff6a8a9a793 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3571,6 +3571,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { // Tell anyone interested that we are done booting! + SystemProperties.set("sys.boot_completed", "1"); broadcastIntentLocked(null, null, new Intent(Intent.ACTION_BOOT_COMPLETED, null), null, null, 0, null, null, diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 0982b32719a4..ebe71ab777b6 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -213,7 +213,7 @@ public: void setDisplayOrientation(int32_t displayId, int32_t orientation); status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel, - jweak inputChannelObjWeak); + jweak inputChannelObjWeak, bool monitor); status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); void setInputWindows(JNIEnv* env, jobjectArray windowObjArray); @@ -334,6 +334,7 @@ private: bool mWindowsReady; Vector<InputWindow> mWindows; Vector<InputWindow*> mWallpaperWindows; + Vector<sp<InputChannel> > mMonitoringChannels; // Focus tracking for keys, trackball, etc. InputWindow* mFocusedWindow; @@ -382,6 +383,10 @@ private: static void addTarget(const InputWindow* window, int32_t targetFlags, nsecs_t timeSpentWaitingForApplication, Vector<InputTarget>& outTargets); + void registerMonitoringChannel(const sp<InputChannel>& inputChannel); + void unregisterMonitoringChannel(const sp<InputChannel>& inputChannel); + void addMonitoringTargetsLd(Vector<InputTarget>& outTargets); + static inline JNIEnv* jniEnv() { return AndroidRuntime::getJNIEnv(); } @@ -492,7 +497,7 @@ void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orient } status_t NativeInputManager::registerInputChannel(JNIEnv* env, - const sp<InputChannel>& inputChannel, jobject inputChannelObj) { + const sp<InputChannel>& inputChannel, jobject inputChannelObj, bool monitor) { jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj); if (! inputChannelObjWeak) { LOGE("Could not create weak reference for input channel."); @@ -519,9 +524,14 @@ status_t NativeInputManager::registerInputChannel(JNIEnv* env, status = mInputManager->registerInputChannel(inputChannel); if (! status) { + // Success. + if (monitor) { + registerMonitoringChannel(inputChannel); + } return OK; } + // Failed! { AutoMutex _l(mInputChannelRegistryLock); mInputChannelObjWeakByReceiveFd.removeItem(inputChannel->getReceivePipeFd()); @@ -552,6 +562,8 @@ status_t NativeInputManager::unregisterInputChannel(JNIEnv* env, env->DeleteWeakGlobalRef(inputChannelObjWeak); + unregisterMonitoringChannel(inputChannel); + return mInputManager->unregisterInputChannel(inputChannel); } @@ -829,6 +841,8 @@ void NativeInputManager::notifyInputChannelBroken(const sp<InputChannel>& inputC env->DeleteLocalRef(inputChannelObjLocal); } + + unregisterMonitoringChannel(inputChannel); } bool NativeInputManager::notifyInputChannelANR(const sp<InputChannel>& inputChannel, @@ -1429,7 +1443,9 @@ int32_t NativeInputManager::waitForTouchedWindowLd(MotionEvent* motionEvent, uin // If there is no currently touched window then fail. if (! mTouchedWindow) { - LOGW("Dropping event because there is no touched window to receive it."); +#if DEBUG_INPUT_DISPATCHER_POLICY + LOGD("Dropping event because there is no touched window to receive it."); +#endif injectionResult = INPUT_EVENT_INJECTION_FAILED; injectionPermission = INJECTION_PERMISSION_GRANTED; break; // failed, exit wait loop @@ -1587,6 +1603,8 @@ int32_t NativeInputManager::waitForKeyEventTargets(KeyEvent* keyEvent, uint32_t outTargets.clear(); return INPUT_EVENT_INJECTION_SUCCEEDED; } + + addMonitoringTargetsLd(outTargets); } pokeUserActivityIfNeeded(windowType, POWER_MANAGER_BUTTON_EVENT); @@ -1631,6 +1649,8 @@ int32_t NativeInputManager::waitForNonTouchEventTargets(MotionEvent* motionEvent } windowType = focusedWindow->layoutParamsType; + + addMonitoringTargetsLd(outTargets); } // release lock pokeUserActivityIfNeeded(windowType, POWER_MANAGER_BUTTON_EVENT); @@ -1657,6 +1677,8 @@ int32_t NativeInputManager::waitForTouchEventTargets(MotionEvent* motionEvent, } windowType = touchedWindow->layoutParamsType; + + addMonitoringTargetsLd(outTargets); } // release lock int32_t eventType; @@ -1714,6 +1736,39 @@ void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) android_server_PowerManagerService_userActivity(eventTime, eventType); } +void NativeInputManager::registerMonitoringChannel(const sp<InputChannel>& inputChannel) { + { // acquire lock + AutoMutex _l(mDispatchLock); + mMonitoringChannels.push(inputChannel); + } // release lock +} + +void NativeInputManager::unregisterMonitoringChannel(const sp<InputChannel>& inputChannel) { + { // acquire lock + AutoMutex _l(mDispatchLock); + + for (size_t i = 0; i < mMonitoringChannels.size(); i++) { + if (mMonitoringChannels[i] == inputChannel) { + mMonitoringChannels.removeAt(i); + break; + } + } + } // release lock +} + +void NativeInputManager::addMonitoringTargetsLd(Vector<InputTarget>& outTargets) { + for (size_t i = 0; i < mMonitoringChannels.size(); i++) { + outTargets.push(); + + InputTarget& target = outTargets.editTop(); + target.inputChannel = mMonitoringChannels[i]; + target.flags = 0; + target.timeout = -1; + target.xOffset = 0; + target.yOffset = 0; + } +} + static void dumpMotionRange(String8& dump, const char* name, const InputDeviceInfo::MotionRange* range) { if (range) { @@ -1805,6 +1860,11 @@ void NativeInputManager::dumpDispatchStateLd(String8& dump) { mWindows[i].ownerPid, mWindows[i].ownerUid, mWindows[i].dispatchingTimeout / 1000000.0); } + + for (size_t i = 0; i < mMonitoringChannels.size(); i++) { + dump.appendFormat(" monitoringChannel[%d]: '%s'\n", + i, mMonitoringChannels[i]->getName().string()); + } } // ---------------------------------------------------------------------------- @@ -2012,7 +2072,7 @@ static void android_server_InputManager_handleInputChannelDisposed(JNIEnv* env, } static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz, - jobject inputChannelObj) { + jobject inputChannelObj, jboolean monitor) { if (checkInputManagerUnitialized(env)) { return; } @@ -2026,15 +2086,17 @@ static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, status_t status = gNativeInputManager->registerInputChannel( - env, inputChannel, inputChannelObj); + env, inputChannel, inputChannelObj, monitor); if (status) { jniThrowRuntimeException(env, "Failed to register input channel. " "Check logs for details."); return; } - android_view_InputChannel_setDisposeCallback(env, inputChannelObj, - android_server_InputManager_handleInputChannelDisposed, NULL); + if (! monitor) { + android_view_InputChannel_setDisposeCallback(env, inputChannelObj, + android_server_InputManager_handleInputChannelDisposed, NULL); + } } static void android_server_InputManager_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz, @@ -2149,7 +2211,7 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeGetSwitchState }, { "nativeHasKeys", "(II[I[Z)Z", (void*) android_server_InputManager_nativeHasKeys }, - { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;)V", + { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;Z)V", (void*) android_server_InputManager_nativeRegisterInputChannel }, { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V", (void*) android_server_InputManager_nativeUnregisterInputChannel }, diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index a14bfb569b8b..79772edec355 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \ clz.cpp.arm \ DisplayHardware/DisplayHardware.cpp \ DisplayHardware/DisplayHardwareBase.cpp \ + DisplayHardware/HWComposer.cpp \ BlurFilter.cpp.arm \ GLExtensions.cpp \ Layer.cpp \ diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index 2eac0a80a08b..166c52804e10 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -36,11 +36,11 @@ #include "DisplayHardware/DisplayHardware.h" -#include <hardware/copybit.h> #include <hardware/overlay.h> #include <hardware/gralloc.h> #include "GLExtensions.h" +#include "HWComposer.h" using namespace android; @@ -76,7 +76,7 @@ DisplayHardware::DisplayHardware( const sp<SurfaceFlinger>& flinger, uint32_t dpy) : DisplayHardwareBase(flinger, dpy), - mFlags(0) + mFlags(0), mHwc(0) { init(dpy); } @@ -262,6 +262,17 @@ void DisplayHardware::init(uint32_t dpy) // Unbind the context from this thread eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + + // initialize the H/W composer + mHwc = new HWComposer(); + if (mHwc->initCheck() == NO_ERROR) { + mHwc->setFrameBuffer(mDisplay, mSurface); + } +} + +HWComposer& DisplayHardware::getHwComposer() const { + return *mHwc; } /* @@ -317,7 +328,12 @@ void DisplayHardware::flip(const Region& dirty) const } mPageFlipCount++; - eglSwapBuffers(dpy, surface); + + if (mHwc->initCheck() == NO_ERROR) { + mHwc->commit(); + } else { + eglSwapBuffers(dpy, surface); + } checkEGLErrors("eglSwapBuffers"); // for debugging diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h index 66bf5215d5d6..f2cfd2db579b 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -34,12 +34,11 @@ #include "DisplayHardware/DisplayHardwareBase.h" struct overlay_control_device_t; -struct framebuffer_device_t; -struct copybit_image_t; namespace android { class FramebufferNativeWindow; +class HWComposer; class DisplayHardware : public DisplayHardwareBase { @@ -80,6 +79,9 @@ public: uint32_t getPageFlipCount() const; EGLDisplay getEGLDisplay() const { return mDisplay; } overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; } + + // Hardware Composer + HWComposer& getHwComposer() const; status_t compositionComplete() const; @@ -107,6 +109,8 @@ private: GLint mMaxViewportDims; GLint mMaxTextureSize; + HWComposer* mHwc; + sp<FramebufferNativeWindow> mNativeWindow; overlay_control_device_t* mOverlayEngine; }; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp new file mode 100644 index 000000000000..8ca880b09502 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include <utils/Errors.h> + +#include <hardware/hardware.h> + +#include <cutils/log.h> + +#include <EGL/egl.h> + +#include "HWComposer.h" + +namespace android { +// --------------------------------------------------------------------------- + +HWComposer::HWComposer() + : mModule(0), mHwc(0), mList(0), + mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE) +{ + int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); + LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); + if (err == 0) { + err = hwc_open(mModule, &mHwc); + LOGE_IF(err, "%s device failed to initialize (%s)", + HWC_HARDWARE_COMPOSER, strerror(-err)); + } +} + +HWComposer::~HWComposer() { + free(mList); + if (mHwc) { + hwc_close(mHwc); + } +} + +status_t HWComposer::initCheck() const { + return mHwc ? NO_ERROR : NO_INIT; +} + +void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) { + mDpy = (hwc_display_t)dpy; + mSur = (hwc_surface_t)sur; +} + +status_t HWComposer::createWorkList(size_t numLayers) { + if (mHwc && (!mList || mList->numHwLayers < numLayers)) { + free(mList); + size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t); + mList = (hwc_layer_list_t*)malloc(size); + mList->flags = HWC_GEOMETRY_CHANGED; + mList->numHwLayers = numLayers; + } + return NO_ERROR; +} + +status_t HWComposer::prepare() const { + int err = mHwc->prepare(mHwc, mList); + return (status_t)err; +} + +status_t HWComposer::commit() const { + int err = mHwc->set(mHwc, mDpy, mSur, mList); + mList->flags &= ~HWC_GEOMETRY_CHANGED; + return (status_t)err; +} + +HWComposer::iterator HWComposer::begin() { + return mList ? &(mList->hwLayers[0]) : NULL; +} + +HWComposer::iterator HWComposer::end() { + return mList ? &(mList->hwLayers[mList->numHwLayers]) : NULL; +} + +// --------------------------------------------------------------------------- +}; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h new file mode 100644 index 000000000000..729f23bbe0f5 --- /dev/null +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SF_HWCOMPOSER_H +#define ANDROID_SF_HWCOMPOSER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <EGL/egl.h> + +#include <hardware/hwcomposer.h> + +namespace android { +// --------------------------------------------------------------------------- + +class HWComposer +{ +public: + + HWComposer(); + ~HWComposer(); + + status_t initCheck() const; + + // tells the HAL what the framebuffer is + void setFrameBuffer(EGLDisplay dpy, EGLSurface sur); + + // create a work list for numLayers layer + status_t createWorkList(size_t numLayers); + + // Asks the HAL what it can do + status_t prepare() const; + + // commits the list + status_t commit() const; + + + typedef hwc_layer_t const * const_iterator; + typedef hwc_layer_t* iterator; + + iterator begin(); + iterator end(); + +private: + hw_module_t const* mModule; + hwc_composer_device_t* mHwc; + hwc_layer_list_t* mList; + hwc_display_t mDpy; + hwc_surface_t mSur; +}; + + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_SF_HWCOMPOSER_H diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 629d993ca007..3720e166992b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -35,6 +35,7 @@ #include "Layer.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/HWComposer.h" #define DEBUG_RESIZE 0 @@ -177,6 +178,62 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, return NO_ERROR; } +void Layer::setGeometry(hwc_layer_t* hwcl) +{ + hwcl->compositionType = HWC_FRAMEBUFFER; + hwcl->hints = 0; + hwcl->flags = 0; + hwcl->transform = 0; + hwcl->blending = HWC_BLENDING_NONE; + + // we can't do alpha-fade with the hwc HAL + const State& s(drawingState()); + if (s.alpha < 0xFF) { + hwcl->flags = HWC_SKIP_LAYER; + return; + } + + // we can only handle simple transformation + if (mOrientation & Transform::ROT_INVALID) { + hwcl->flags = HWC_SKIP_LAYER; + return; + } + + hwcl->transform = mOrientation; + + if (needsBlending()) { + hwcl->blending = mPremultipliedAlpha ? + HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE; + } + + hwcl->displayFrame.left = mTransformedBounds.left; + hwcl->displayFrame.top = mTransformedBounds.top; + hwcl->displayFrame.right = mTransformedBounds.right; + hwcl->displayFrame.bottom = mTransformedBounds.bottom; + + hwcl->visibleRegionScreen.rects = + reinterpret_cast<hwc_rect_t const *>( + visibleRegionScreen.getArray( + &hwcl->visibleRegionScreen.numRects)); +} + +void Layer::setPerFrameData(hwc_layer_t* hwcl) { + sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); + if (buffer == NULL) { + // this situation can happen if we ran out of memory for instance. + // not much we can do. continue to use whatever texture was bound + // to this context. + hwcl->handle = NULL; + return; + } + hwcl->handle = const_cast<native_handle_t*>(buffer->handle); + // TODO: set the crop value properly + hwcl->sourceCrop.left = 0; + hwcl->sourceCrop.top = 0; + hwcl->sourceCrop.right = buffer->width; + hwcl->sourceCrop.bottom = buffer->height; +} + void Layer::reloadTexture(const Region& dirty) { sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index e1d283beddb7..188da6a784df 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -68,6 +68,8 @@ public: bool isFixedSize() const; // LayerBase interface + virtual void setGeometry(hwc_layer_t* hwcl); + virtual void setPerFrameData(hwc_layer_t* hwcl); virtual void onDraw(const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); virtual void lockPageFlip(bool& recomputeVisibleRegions); diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index d5aa53f9f178..043d54d96210 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -39,8 +39,11 @@ namespace android { // --------------------------------------------------------------------------- +int32_t LayerBase::sSequence = 1; + LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) : dpy(display), contentDirty(false), + sequence(uint32_t(android_atomic_inc(&sSequence))), mFlinger(flinger), mNeedsFiltering(false), mOrientation(0), @@ -304,22 +307,17 @@ void LayerBase::drawRegion(const Region& reg) const } } -void LayerBase::draw(const Region& inClip) const -{ - // invalidate the region we'll update - Region clip(inClip); // copy-on-write, so no-op most of the time - - // Remove the transparent area from the clipping region - const State& s = drawingState(); - if (LIKELY(!s.transparentRegion.isEmpty())) { - clip.subtract(transparentRegionScreen); - if (clip.isEmpty()) { - // usually this won't happen because this should be taken care of - // by SurfaceFlinger::computeVisibleRegions() - return; - } - } +void LayerBase::setGeometry(hwc_layer_t* hwcl) { + hwcl->flags |= HWC_SKIP_LAYER; +} +void LayerBase::setPerFrameData(hwc_layer_t* hwcl) { + hwcl->compositionType = HWC_FRAMEBUFFER; + hwcl->handle = NULL; +} + +void LayerBase::draw(const Region& clip) const +{ // reset GL state glEnable(GL_SCISSOR_TEST); diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 4288cf79469b..dd1cd05f1b93 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -35,6 +35,8 @@ #include <pixelflinger/pixelflinger.h> +#include <hardware/hwcomposer.h> + #include "Transform.h" namespace android { @@ -53,6 +55,8 @@ class Texture; class LayerBase : public RefBase { + static int32_t sSequence; + public: LayerBase(SurfaceFlinger* flinger, DisplayID display); @@ -61,6 +65,7 @@ public: Region visibleRegionScreen; Region transparentRegionScreen; Region coveredRegionScreen; + int32_t sequence; struct State { uint32_t w; @@ -105,6 +110,10 @@ public: virtual const char* getTypeId() const { return "LayerBase"; } + virtual void setGeometry(hwc_layer_t* hwcl); + + virtual void setPerFrameData(hwc_layer_t* hwcl); + /** * draw - performs some global clipping optimizations * and calls onDraw(). @@ -210,12 +219,6 @@ public: inline const State& currentState() const { return mCurrentState; } inline State& currentState() { return mCurrentState; } - static int compareCurrentStateZ( - sp<LayerBase> const * layerA, - sp<LayerBase> const * layerB) { - return layerA[0]->currentState().z - layerB[0]->currentState().z; - } - int32_t getOrientation() const { return mOrientation; } int tx() const { return mLeft; } int ty() const { return mTop; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3167c4cb7ed1..47bb4c1b1111 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -52,6 +52,7 @@ #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/HWComposer.h" /* ideally AID_GRAPHICS would be in a semi-public header * or there would be a way to map a user/group name to its id @@ -65,95 +66,6 @@ namespace android { // --------------------------------------------------------------------------- -SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs) - : lookup(rhs.lookup), layers(rhs.layers) -{ -} - -ssize_t SurfaceFlinger::LayerVector::indexOf( - const sp<LayerBase>& key, size_t guess) const -{ - if (guess<size() && lookup.keyAt(guess) == key) - return guess; - const ssize_t i = lookup.indexOfKey(key); - if (i>=0) { - const size_t idx = lookup.valueAt(i); - LOGE_IF(layers[idx]!=key, - "LayerVector[%p]: layers[%d]=%p, key=%p", - this, int(idx), layers[idx].get(), key.get()); - return idx; - } - return i; -} - -ssize_t SurfaceFlinger::LayerVector::add( - const sp<LayerBase>& layer, - Vector< sp<LayerBase> >::compar_t cmp) -{ - size_t count = layers.size(); - ssize_t l = 0; - ssize_t h = count-1; - ssize_t mid; - sp<LayerBase> const* a = layers.array(); - while (l <= h) { - mid = l + (h - l)/2; - const int c = cmp(a+mid, &layer); - if (c == 0) { l = mid; break; } - else if (c<0) { l = mid+1; } - else { h = mid-1; } - } - size_t order = l; - while (order<count && !cmp(&layer, a+order)) { - order++; - } - count = lookup.size(); - for (size_t i=0 ; i<count ; i++) { - if (lookup.valueAt(i) >= order) { - lookup.editValueAt(i)++; - } - } - layers.insertAt(layer, order); - lookup.add(layer, order); - return order; -} - -ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer) -{ - const ssize_t keyIndex = lookup.indexOfKey(layer); - if (keyIndex >= 0) { - const size_t index = lookup.valueAt(keyIndex); - LOGE_IF(layers[index]!=layer, - "LayerVector[%p]: layers[%u]=%p, layer=%p", - this, int(index), layers[index].get(), layer.get()); - layers.removeItemsAt(index); - lookup.removeItemsAt(keyIndex); - const size_t count = lookup.size(); - for (size_t i=0 ; i<count ; i++) { - if (lookup.valueAt(i) >= size_t(index)) { - lookup.editValueAt(i)--; - } - } - return index; - } - return NAME_NOT_FOUND; -} - -ssize_t SurfaceFlinger::LayerVector::reorder( - const sp<LayerBase>& layer, - Vector< sp<LayerBase> >::compar_t cmp) -{ - // XXX: it's a little lame. but oh well... - ssize_t err = remove(layer); - if (err >=0) - err = add(layer, cmp); - return err; -} - -// --------------------------------------------------------------------------- -#if 0 -#pragma mark - -#endif - SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), Thread(false), mTransactionFlags(0), @@ -165,6 +77,7 @@ SurfaceFlinger::SurfaceFlinger() mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), mDump("android.permission.DUMP"), mVisibleRegionsDirty(false), + mHwWorkListDirty(false), mDeferReleaseConsole(false), mFreezeDisplay(false), mFreezeCount(0), @@ -457,6 +370,11 @@ bool SurfaceFlinger::threadLoop() // post surfaces (if needed) handlePageFlip(); + if (UNLIKELY(mHwWorkListDirty)) { + // build the h/w work list + handleWorkList(); + } + const DisplayHardware& hw(graphicPlane(0).displayHardware()); if (LIKELY(hw.canDraw() && !isFrozen())) { // repaint the framebuffer (if needed) @@ -521,6 +439,10 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { Vector< sp<LayerBase> > ditchedLayers; + /* + * Perform and commit the transaction + */ + { // scope for the lock Mutex::Autolock _l(mStateLock); const nsecs_t now = systemTime(); @@ -528,9 +450,15 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) handleTransactionLocked(transactionFlags, ditchedLayers); mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; + mHwWorkListDirty = true; + // here the transaction has been committed } - // do this without lock held + /* + * Clean-up all layers that went away + * (do this without the lock held) + */ + const size_t count = ditchedLayers.size(); for (size_t i=0 ; i<count ; i++) { if (ditchedLayers[i] != 0) { @@ -764,8 +692,8 @@ void SurfaceFlinger::commitTransaction() void SurfaceFlinger::handlePageFlip() { bool visibleRegions = mVisibleRegionsDirty; - LayerVector& currentLayers = const_cast<LayerVector&>( - mDrawingState.layersSortedByZ); + LayerVector& currentLayers( + const_cast<LayerVector&>(mDrawingState.layersSortedByZ)); visibleRegions |= lockPageFlip(currentLayers); const DisplayHardware& hw = graphicPlane(0).displayHardware(); @@ -773,8 +701,22 @@ void SurfaceFlinger::handlePageFlip() if (visibleRegions) { Region opaqueRegion; computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion); + + /* + * rebuild the visible layer list + */ + mVisibleLayersSortedByZ.clear(); + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + size_t count = currentLayers.size(); + mVisibleLayersSortedByZ.setCapacity(count); + for (size_t i=0 ; i<count ; i++) { + if (!currentLayers[i]->visibleRegionScreen.isEmpty()) + mVisibleLayersSortedByZ.add(currentLayers[i]); + } + mWormholeRegion = screenRegion.subtract(opaqueRegion); mVisibleRegionsDirty = false; + mHwWorkListDirty = true; } unlockPageFlip(currentLayers); @@ -805,6 +747,21 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) } } +void SurfaceFlinger::handleWorkList() +{ + mHwWorkListDirty = false; + HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ); + const size_t count = currentLayers.size(); + hwc.createWorkList(count); + HWComposer::iterator cur(hwc.begin()); + HWComposer::iterator last(hwc.end()); + for (size_t i=0 ; (i<count) && (cur!=last) ; ++i, ++cur) { + currentLayers[i]->setGeometry(cur); + } + } +} void SurfaceFlinger::handleRepaint() { @@ -869,18 +826,61 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) // draw something... drawWormhole(); } - const SurfaceFlinger& flinger(*this); - const LayerVector& drawingLayers(mDrawingState.layersSortedByZ); - const size_t count = drawingLayers.size(); - sp<LayerBase> const* const layers = drawingLayers.array(); + + status_t err = NO_ERROR; + const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const size_t count = layers.size(); + + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + HWComposer& hwc(hw.getHwComposer()); + HWComposer::iterator cur(hwc.begin()); + HWComposer::iterator last(hwc.end()); + + // update the per-frame h/w composer data for each layer + if (cur != last) { + for (size_t i=0 ; i<count && cur!=last ; ++i, ++cur) { + layers[i]->setPerFrameData(cur); + } + err = hwc.prepare(); + LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + } + + // and then, render the layers targeted at the framebuffer + Region transparent(hw.bounds()); for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer = layers[i]; - const Region& visibleRegion(layer->visibleRegionScreen); - if (!visibleRegion.isEmpty()) { - const Region clip(dirty.intersect(visibleRegion)); - if (!clip.isEmpty()) { - layer->draw(clip); + + // see if we need to skip this layer + if (!err && cur != last) { + if (!((cur->compositionType == HWC_FRAMEBUFFER) || + (cur->flags & HWC_SKIP_LAYER))) { + ++cur; + continue; } + ++cur; + } + + // draw the layer into the framebuffer + const sp<LayerBase>& layer(layers[i]); + transparent.subtractSelf(layer->visibleRegionScreen); + const Region clip(dirty.intersect(layer->visibleRegionScreen)); + if (!clip.isEmpty()) { + layer->draw(clip); + } + } + + // finally clear everything we didn't draw as a result of calling + // prepare (this leaves the FB transparent). + transparent.andSelf(dirty); + if (!transparent.isEmpty()) { + glClearColor(0,0,0,0); + Region::const_iterator it = transparent.begin(); + Region::const_iterator const end = transparent.end(); + const int32_t height = hw.getHeight(); + while (it != end) { + const Rect& r(*it++); + const GLint sy = height - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glClear(GL_COLOR_BUFFER_BIT); } } } @@ -1029,8 +1029,7 @@ status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer) status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer) { - ssize_t i = mCurrentState.layersSortedByZ.add( - layer, &LayerBase::compareCurrentStateZ); + ssize_t i = mCurrentState.layersSortedByZ.add(layer); return (i < 0) ? status_t(i) : status_t(NO_ERROR); } @@ -1372,9 +1371,10 @@ status_t SurfaceFlinger::setClientState( flags |= eTraversalNeeded; } if (what & eLayerChanged) { + ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); if (layer->setLayer(s.z)) { - mCurrentState.layersSortedByZ.reorder( - layer, &Layer::compareCurrentStateZ); + mCurrentState.layersSortedByZ.removeAt(idx); + mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) // AND transaction (list changed) flags |= eTransactionNeeded|eTraversalNeeded; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8821e5c071e2..8e286e505d33 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -40,9 +40,6 @@ #include "MessageQueue.h" -struct copybit_device_t; -struct overlay_device_t; - namespace android { // --------------------------------------------------------------------------- @@ -246,21 +243,19 @@ private: status_t setClientState(const sp<Client>& client, int32_t count, const layer_state_t* states); - - class LayerVector { + class LayerVector : public SortedVector< sp<LayerBase> > { public: - inline LayerVector() { } - LayerVector(const LayerVector&); - inline size_t size() const { return layers.size(); } - inline sp<LayerBase> const* array() const { return layers.array(); } - ssize_t add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t); - ssize_t remove(const sp<LayerBase>&); - ssize_t reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t); - ssize_t indexOf(const sp<LayerBase>& key, size_t guess=0) const; - inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; } - private: - KeyedVector< sp<LayerBase> , size_t> lookup; - Vector< sp<LayerBase> > layers; + LayerVector() { } + LayerVector(const LayerVector& rhs) : SortedVector< sp<LayerBase> >(rhs) { } + virtual int do_compare(const void* lhs, const void* rhs) const { + const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs)); + const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs)); + // sort layers by Z order + uint32_t lz = l->currentState().z; + uint32_t rz = r->currentState().z; + // then by sequence, so we get a stable ordering + return (lz != rz) ? (lz - rz) : (l->sequence - r->sequence); + } }; struct State { @@ -301,6 +296,7 @@ private: void handlePageFlip(); bool lockPageFlip(const LayerVector& currentLayers); void unlockPageFlip(const LayerVector& currentLayers); + void handleWorkList(); void handleRepaint(); void postFramebuffer(); void composeSurfaces(const Region& dirty); @@ -375,10 +371,13 @@ private: Region mInvalidRegion; Region mWormholeRegion; bool mVisibleRegionsDirty; + bool mHwWorkListDirty; bool mDeferReleaseConsole; bool mFreezeDisplay; int32_t mFreezeCount; nsecs_t mFreezeDisplayTime; + Vector< sp<LayerBase> > mVisibleLayersSortedByZ; + // don't use a lock for these, we don't care int mDebugRegion; diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index b57f358285af..4dc19913f1da 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -215,7 +215,7 @@ public final class CallManager { * @param phone */ public void unregisterPhone(Phone phone) { - if (phone != null && !mPhones.contains(phone)) { + if (phone != null && mPhones.contains(phone)) { mPhones.remove(phone); mRingingCalls.remove(phone.getRingingCall()); mBackgroundCalls.remove(phone.getBackgroundCall()); diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index edc1f8ae75f9..a94518fa144a 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -102,6 +102,10 @@ public class SipPhone extends SipPhoneBase { return mProfile.getProfileName(); } + public String getSipUri() { + return mProfile.getUriString(); + } + public boolean canTake(Object incomingCall) { synchronized (SipPhone.class) { if (!(incomingCall instanceof SipAudioCall)) return false; diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java index a1bdd2f35a0a..611e3ea020ec 100644 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java @@ -42,7 +42,7 @@ public class SipPhoneFactory { SipProfile profile = new SipProfile.Builder(sipUri).build(); return new SipPhone(context, phoneNotifier, profile); } catch (ParseException e) { - Log.w("SipPhoneProxy", "setPhone", e); + Log.w("SipPhoneFactory", "makePhone", e); return null; } } diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneProxy.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneProxy.java deleted file mode 100644 index 7cc1a9b8fbb3..000000000000 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneProxy.java +++ /dev/null @@ -1,749 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.sip; - -import com.android.internal.telephony.*; -import com.android.internal.telephony.gsm.NetworkInfo; -import com.android.internal.telephony.test.SimulatedRadioControl; - -import android.content.Context; -import android.os.Handler; -import android.os.Message; -import android.telephony.CellLocation; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; -import android.util.Log; - -import java.util.List; - -/** - * Temporary. Will be removed after integrating with CallManager. - * (TODO) - * @hide - */ -public class SipPhoneProxy implements Phone { - private static final String LOG_TAG = "PHONE"; - - private static SipPhoneProxy sPhoneProxy = new SipPhoneProxy(); - - public static SipPhoneProxy getInstance() { - return sPhoneProxy; - } - - private SipPhone mActivePhone; - private CallProxy mRingingCall = new CallProxy(); - private CallProxy mForegroundCall = new CallProxy(); - private CallProxy mBackgroundCall = new CallProxy(); - - private SipPhoneProxy() { - } - - public void onNewCall(Object call) { - if (mActivePhone.canTake(call)) { - Log.v("SipPhoneProxy", "onNewCall(): call taken: " + call); - } else { - Log.v("SipPhoneProxy", "onNewCall(): call dropped: " + call); - } - } - - public synchronized void setPhone(SipPhone phone) { - if (phone == null) return; - if (mActivePhone != null) phone.migrateFrom(mActivePhone); - mActivePhone = phone; - mForegroundCall.setTarget(phone.getForegroundCall()); - mBackgroundCall.setTarget(phone.getBackgroundCall()); - mRingingCall.setTarget(phone.getRingingCall()); - } - - public synchronized Call getForegroundCall() { - return mForegroundCall; - } - - public synchronized Call getBackgroundCall() { - return mBackgroundCall; - } - - public synchronized Call getRingingCall() { - return mRingingCall; - } - - - public ServiceState getServiceState() { - return mActivePhone.getServiceState(); - } - - public CellLocation getCellLocation() { - return mActivePhone.getCellLocation(); - } - - public DataState getDataConnectionState() { - return mActivePhone.getDataConnectionState(); - } - - public DataActivityState getDataActivityState() { - return mActivePhone.getDataActivityState(); - } - - public Context getContext() { - return mActivePhone.getContext(); - } - - public void disableDnsCheck(boolean b) { - mActivePhone.disableDnsCheck(b); - } - - public boolean isDnsCheckDisabled() { - return mActivePhone.isDnsCheckDisabled(); - } - - public State getState() { - return mActivePhone.getState(); - } - - public String getPhoneName() { - return mActivePhone.getPhoneName(); - } - - public int getPhoneType() { - return mActivePhone.getPhoneType(); - } - - public String[] getActiveApnTypes() { - return mActivePhone.getActiveApnTypes(); - } - - public String getActiveApn() { - return mActivePhone.getActiveApn(); - } - - public SignalStrength getSignalStrength() { - return mActivePhone.getSignalStrength(); - } - - public void registerForUnknownConnection(Handler h, int what, Object obj) { - mActivePhone.registerForUnknownConnection(h, what, obj); - } - - public void unregisterForUnknownConnection(Handler h) { - mActivePhone.unregisterForUnknownConnection(h); - } - - public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) { - mActivePhone.registerForPreciseCallStateChanged(h, what, obj); - } - - public void unregisterForPreciseCallStateChanged(Handler h) { - mActivePhone.unregisterForPreciseCallStateChanged(h); - } - - public void registerForNewRingingConnection(Handler h, int what, Object obj) { - mActivePhone.registerForNewRingingConnection(h, what, obj); - } - - public void unregisterForNewRingingConnection(Handler h) { - mActivePhone.unregisterForNewRingingConnection(h); - } - - public void registerForIncomingRing(Handler h, int what, Object obj) { - mActivePhone.registerForIncomingRing(h, what, obj); - } - - public void unregisterForIncomingRing(Handler h) { - mActivePhone.unregisterForIncomingRing(h); - } - - public void registerForDisconnect(Handler h, int what, Object obj) { - mActivePhone.registerForDisconnect(h, what, obj); - } - - public void unregisterForDisconnect(Handler h) { - mActivePhone.unregisterForDisconnect(h); - } - - public void registerForMmiInitiate(Handler h, int what, Object obj) { - mActivePhone.registerForMmiInitiate(h, what, obj); - } - - public void unregisterForMmiInitiate(Handler h) { - mActivePhone.unregisterForMmiInitiate(h); - } - - public void registerForMmiComplete(Handler h, int what, Object obj) { - mActivePhone.registerForMmiComplete(h, what, obj); - } - - public void unregisterForMmiComplete(Handler h) { - mActivePhone.unregisterForMmiComplete(h); - } - - public List<? extends MmiCode> getPendingMmiCodes() { - return mActivePhone.getPendingMmiCodes(); - } - - public void sendUssdResponse(String ussdMessge) { - mActivePhone.sendUssdResponse(ussdMessge); - } - - public void registerForServiceStateChanged(Handler h, int what, Object obj) { - mActivePhone.registerForServiceStateChanged(h, what, obj); - } - - public void unregisterForServiceStateChanged(Handler h) { - mActivePhone.unregisterForServiceStateChanged(h); - } - - public void registerForSuppServiceNotification(Handler h, int what, Object obj) { - mActivePhone.registerForSuppServiceNotification(h, what, obj); - } - - public void unregisterForSuppServiceNotification(Handler h) { - mActivePhone.unregisterForSuppServiceNotification(h); - } - - public void registerForSuppServiceFailed(Handler h, int what, Object obj) { - mActivePhone.registerForSuppServiceFailed(h, what, obj); - } - - public void unregisterForSuppServiceFailed(Handler h) { - mActivePhone.unregisterForSuppServiceFailed(h); - } - - public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ - mActivePhone.registerForInCallVoicePrivacyOn(h,what,obj); - } - - public void unregisterForInCallVoicePrivacyOn(Handler h){ - mActivePhone.unregisterForInCallVoicePrivacyOn(h); - } - - public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ - mActivePhone.registerForInCallVoicePrivacyOff(h,what,obj); - } - - public void unregisterForInCallVoicePrivacyOff(Handler h){ - mActivePhone.unregisterForInCallVoicePrivacyOff(h); - } - - public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) { - mActivePhone.registerForCdmaOtaStatusChange(h,what,obj); - } - - public void unregisterForCdmaOtaStatusChange(Handler h) { - mActivePhone.unregisterForCdmaOtaStatusChange(h); - } - - public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { - mActivePhone.registerForSubscriptionInfoReady(h, what, obj); - } - - public void unregisterForSubscriptionInfoReady(Handler h) { - mActivePhone.unregisterForSubscriptionInfoReady(h); - } - - public void registerForEcmTimerReset(Handler h, int what, Object obj) { - mActivePhone.registerForEcmTimerReset(h,what,obj); - } - - public void unregisterForEcmTimerReset(Handler h) { - mActivePhone.unregisterForEcmTimerReset(h); - } - - public void registerForRingbackTone(Handler h, int what, Object obj) { - mActivePhone.registerForRingbackTone(h,what,obj); - } - - public void unregisterForRingbackTone(Handler h) { - mActivePhone.unregisterForRingbackTone(h); - } - - public void registerForResendIncallMute(Handler h, int what, Object obj) { - mActivePhone.registerForResendIncallMute(h,what,obj); - } - - public void unregisterForResendIncallMute(Handler h) { - mActivePhone.unregisterForResendIncallMute(h); - } - - public boolean getIccRecordsLoaded() { - return mActivePhone.getIccRecordsLoaded(); - } - - public IccCard getIccCard() { - return mActivePhone.getIccCard(); - } - - public void acceptCall() throws CallStateException { - mActivePhone.acceptCall(); - } - - public void rejectCall() throws CallStateException { - mActivePhone.rejectCall(); - } - - public void switchHoldingAndActive() throws CallStateException { - mActivePhone.switchHoldingAndActive(); - } - - public boolean canConference() { - return mActivePhone.canConference(); - } - - public void conference() throws CallStateException { - mActivePhone.conference(); - } - - public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { - mActivePhone.enableEnhancedVoicePrivacy(enable, onComplete); - } - - public void getEnhancedVoicePrivacy(Message onComplete) { - mActivePhone.getEnhancedVoicePrivacy(onComplete); - } - - public boolean canTransfer() { - return mActivePhone.canTransfer(); - } - - public void explicitCallTransfer() throws CallStateException { - mActivePhone.explicitCallTransfer(); - } - - public void clearDisconnected() { - mActivePhone.clearDisconnected(); - } - - public Connection dial(String dialString) throws CallStateException { - return mActivePhone.dial(dialString); - } - - public Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException { - return mActivePhone.dial(dialString); - } - - public boolean handlePinMmi(String dialString) { - return mActivePhone.handlePinMmi(dialString); - } - - public boolean handleInCallMmiCommands(String command) throws CallStateException { - return mActivePhone.handleInCallMmiCommands(command); - } - - public void sendDtmf(char c) { - mActivePhone.sendDtmf(c); - } - - public void startDtmf(char c) { - mActivePhone.startDtmf(c); - } - - public void stopDtmf() { - mActivePhone.stopDtmf(); - } - - public void setRadioPower(boolean power) { - mActivePhone.setRadioPower(power); - } - - public boolean getMessageWaitingIndicator() { - return mActivePhone.getMessageWaitingIndicator(); - } - - public boolean getCallForwardingIndicator() { - return mActivePhone.getCallForwardingIndicator(); - } - - public String getLine1Number() { - return mActivePhone.getLine1Number(); - } - - public String getCdmaMin() { - return mActivePhone.getCdmaMin(); - } - - public boolean isMinInfoReady() { - return mActivePhone.isMinInfoReady(); - } - - public String getCdmaPrlVersion() { - return mActivePhone.getCdmaPrlVersion(); - } - - public String getLine1AlphaTag() { - return mActivePhone.getLine1AlphaTag(); - } - - public void setLine1Number(String alphaTag, String number, Message onComplete) { - mActivePhone.setLine1Number(alphaTag, number, onComplete); - } - - public String getVoiceMailNumber() { - return mActivePhone.getVoiceMailNumber(); - } - - /** @hide */ - public int getVoiceMessageCount(){ - return mActivePhone.getVoiceMessageCount(); - } - - public String getVoiceMailAlphaTag() { - return mActivePhone.getVoiceMailAlphaTag(); - } - - public void setVoiceMailNumber(String alphaTag,String voiceMailNumber, - Message onComplete) { - mActivePhone.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); - } - - public void getCallForwardingOption(int commandInterfaceCFReason, - Message onComplete) { - mActivePhone.getCallForwardingOption(commandInterfaceCFReason, - onComplete); - } - - public void setCallForwardingOption(int commandInterfaceCFReason, - int commandInterfaceCFAction, String dialingNumber, - int timerSeconds, Message onComplete) { - mActivePhone.setCallForwardingOption(commandInterfaceCFReason, - commandInterfaceCFAction, dialingNumber, timerSeconds, onComplete); - } - - public void getOutgoingCallerIdDisplay(Message onComplete) { - mActivePhone.getOutgoingCallerIdDisplay(onComplete); - } - - public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, - Message onComplete) { - mActivePhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, - onComplete); - } - - public void getCallWaiting(Message onComplete) { - mActivePhone.getCallWaiting(onComplete); - } - - public void setCallWaiting(boolean enable, Message onComplete) { - mActivePhone.setCallWaiting(enable, onComplete); - } - - public void getAvailableNetworks(Message response) { - mActivePhone.getAvailableNetworks(response); - } - - public void setNetworkSelectionModeAutomatic(Message response) { - mActivePhone.setNetworkSelectionModeAutomatic(response); - } - - public void selectNetworkManually(NetworkInfo network, Message response) { - mActivePhone.selectNetworkManually(network, response); - } - - public void setPreferredNetworkType(int networkType, Message response) { - mActivePhone.setPreferredNetworkType(networkType, response); - } - - public void getPreferredNetworkType(Message response) { - mActivePhone.getPreferredNetworkType(response); - } - - public void getNeighboringCids(Message response) { - mActivePhone.getNeighboringCids(response); - } - - public void setOnPostDialCharacter(Handler h, int what, Object obj) { - mActivePhone.setOnPostDialCharacter(h, what, obj); - } - - public void setMute(boolean muted) { - mActivePhone.setMute(muted); - } - - public boolean getMute() { - return mActivePhone.getMute(); - } - - public void invokeOemRilRequestRaw(byte[] data, Message response) { - mActivePhone.invokeOemRilRequestRaw(data, response); - } - - public void invokeOemRilRequestStrings(String[] strings, Message response) { - mActivePhone.invokeOemRilRequestStrings(strings, response); - } - - public void getDataCallList(Message response) { - mActivePhone.getDataCallList(response); - } - - public List<DataConnection> getCurrentDataConnectionList() { - return mActivePhone.getCurrentDataConnectionList(); - } - - public void updateServiceLocation() { - mActivePhone.updateServiceLocation(); - } - - public void enableLocationUpdates() { - mActivePhone.enableLocationUpdates(); - } - - public void disableLocationUpdates() { - mActivePhone.disableLocationUpdates(); - } - - public void setUnitTestMode(boolean f) { - mActivePhone.setUnitTestMode(f); - } - - public boolean getUnitTestMode() { - return mActivePhone.getUnitTestMode(); - } - - public void setBandMode(int bandMode, Message response) { - mActivePhone.setBandMode(bandMode, response); - } - - public void queryAvailableBandMode(Message response) { - mActivePhone.queryAvailableBandMode(response); - } - - public boolean getDataRoamingEnabled() { - return mActivePhone.getDataRoamingEnabled(); - } - - public void setDataRoamingEnabled(boolean enable) { - mActivePhone.setDataRoamingEnabled(enable); - } - - public void queryCdmaRoamingPreference(Message response) { - mActivePhone.queryCdmaRoamingPreference(response); - } - - public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { - mActivePhone.setCdmaRoamingPreference(cdmaRoamingType, response); - } - - public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { - mActivePhone.setCdmaSubscription(cdmaSubscriptionType, response); - } - - public SimulatedRadioControl getSimulatedRadioControl() { - return mActivePhone.getSimulatedRadioControl(); - } - - public boolean enableDataConnectivity() { - return mActivePhone.enableDataConnectivity(); - } - - public boolean disableDataConnectivity() { - return mActivePhone.disableDataConnectivity(); - } - - public int enableApnType(String type) { - return mActivePhone.enableApnType(type); - } - - public int disableApnType(String type) { - return mActivePhone.disableApnType(type); - } - - public boolean isDataConnectivityEnabled() { - return mActivePhone.isDataConnectivityEnabled(); - } - - public boolean isDataConnectivityPossible() { - return mActivePhone.isDataConnectivityPossible(); - } - - public String getInterfaceName(String apnType) { - return mActivePhone.getInterfaceName(apnType); - } - - public String getIpAddress(String apnType) { - return mActivePhone.getIpAddress(apnType); - } - - public String getGateway(String apnType) { - return mActivePhone.getGateway(apnType); - } - - public String[] getDnsServers(String apnType) { - return mActivePhone.getDnsServers(apnType); - } - - public String getDeviceId() { - return mActivePhone.getDeviceId(); - } - - public String getDeviceSvn() { - return mActivePhone.getDeviceSvn(); - } - - public String getSubscriberId() { - return mActivePhone.getSubscriberId(); - } - - public String getIccSerialNumber() { - return mActivePhone.getIccSerialNumber(); - } - - public String getEsn() { - return mActivePhone.getEsn(); - } - - public String getMeid() { - return mActivePhone.getMeid(); - } - - public PhoneSubInfo getPhoneSubInfo(){ - return mActivePhone.getPhoneSubInfo(); - } - - public IccSmsInterfaceManager getIccSmsInterfaceManager(){ - return mActivePhone.getIccSmsInterfaceManager(); - } - - public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ - return mActivePhone.getIccPhoneBookInterfaceManager(); - } - - public void setTTYMode(int ttyMode, Message onComplete) { - mActivePhone.setTTYMode(ttyMode, onComplete); - } - - public void queryTTYMode(Message onComplete) { - mActivePhone.queryTTYMode(onComplete); - } - - public void activateCellBroadcastSms(int activate, Message response) { - mActivePhone.activateCellBroadcastSms(activate, response); - } - - public void getCellBroadcastSmsConfig(Message response) { - mActivePhone.getCellBroadcastSmsConfig(response); - } - - public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { - mActivePhone.setCellBroadcastSmsConfig(configValuesArray, response); - } - - public void notifyDataActivity() { - mActivePhone.notifyDataActivity(); - } - - public void getSmscAddress(Message result) { - mActivePhone.getSmscAddress(result); - } - - public void setSmscAddress(String address, Message result) { - mActivePhone.setSmscAddress(address, result); - } - - public int getCdmaEriIconIndex() { - return mActivePhone.getCdmaEriIconIndex(); - } - - public String getCdmaEriText() { - return mActivePhone.getCdmaEriText(); - } - - public int getCdmaEriIconMode() { - return mActivePhone.getCdmaEriIconMode(); - } - - public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete){ - mActivePhone.sendBurstDtmf(dtmfString, on, off, onComplete); - } - - public void exitEmergencyCallbackMode(){ - mActivePhone.exitEmergencyCallbackMode(); - } - - public boolean isOtaSpNumber(String dialStr){ - return mActivePhone.isOtaSpNumber(dialStr); - } - - public void registerForCallWaiting(Handler h, int what, Object obj){ - mActivePhone.registerForCallWaiting(h,what,obj); - } - - public void unregisterForCallWaiting(Handler h){ - mActivePhone.unregisterForCallWaiting(h); - } - - public void registerForSignalInfo(Handler h, int what, Object obj) { - mActivePhone.registerForSignalInfo(h,what,obj); - } - - public void unregisterForSignalInfo(Handler h) { - mActivePhone.unregisterForSignalInfo(h); - } - - public void registerForDisplayInfo(Handler h, int what, Object obj) { - mActivePhone.registerForDisplayInfo(h,what,obj); - } - - public void unregisterForDisplayInfo(Handler h) { - mActivePhone.unregisterForDisplayInfo(h); - } - - public void registerForNumberInfo(Handler h, int what, Object obj) { - mActivePhone.registerForNumberInfo(h, what, obj); - } - - public void unregisterForNumberInfo(Handler h) { - mActivePhone.unregisterForNumberInfo(h); - } - - public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) { - mActivePhone.registerForRedirectedNumberInfo(h, what, obj); - } - - public void unregisterForRedirectedNumberInfo(Handler h) { - mActivePhone.unregisterForRedirectedNumberInfo(h); - } - - public void registerForLineControlInfo(Handler h, int what, Object obj) { - mActivePhone.registerForLineControlInfo( h, what, obj); - } - - public void unregisterForLineControlInfo(Handler h) { - mActivePhone.unregisterForLineControlInfo(h); - } - - public void registerFoT53ClirlInfo(Handler h, int what, Object obj) { - mActivePhone.registerFoT53ClirlInfo(h, what, obj); - } - - public void unregisterForT53ClirInfo(Handler h) { - mActivePhone.unregisterForT53ClirInfo(h); - } - - public void registerForT53AudioControlInfo(Handler h, int what, Object obj) { - mActivePhone.registerForT53AudioControlInfo( h, what, obj); - } - - public void unregisterForT53AudioControlInfo(Handler h) { - mActivePhone.unregisterForT53AudioControlInfo(h); - } - - public void setOnEcbModeExitResponse(Handler h, int what, Object obj){ - mActivePhone.setOnEcbModeExitResponse(h,what,obj); - } - - public void unsetOnEcbModeExitResponse(Handler h){ - mActivePhone.unsetOnEcbModeExitResponse(h); - } -} diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk new file mode 100644 index 000000000000..b02c1cb13b63 --- /dev/null +++ b/tools/obbtool/Android.mk @@ -0,0 +1,30 @@ +# +# Copyright 2010 The Android Open Source Project +# +# Opaque Binary Blob (OBB) Tool +# + +# This tool is prebuilt if we're doing an app-only build. +ifeq ($(TARGET_BUILD_APPS),) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + Main.cpp + +#LOCAL_C_INCLUDES += + +LOCAL_STATIC_LIBRARIES := \ + libutils \ + libcutils + +ifeq ($(HOST_OS),linux) +LOCAL_LDLIBS += -lpthread +endif + +LOCAL_MODULE := obbtool + +include $(BUILD_HOST_EXECUTABLE) + +endif # TARGET_BUILD_APPS diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp new file mode 100644 index 000000000000..2a9bf0420102 --- /dev/null +++ b/tools/obbtool/Main.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <utils/ObbFile.h> +#include <utils/String8.h> + +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> + +using namespace android; + +static const char* gProgName = "obbtool"; +static const char* gProgVersion = "1.0"; + +static int wantUsage = 0; +static int wantVersion = 0; + +#define ADD_OPTS "n:v:f:c:" +static const struct option longopts[] = { + {"help", no_argument, &wantUsage, 1}, + {"version", no_argument, &wantVersion, 1}, + + /* Args for "add" */ + {"name", required_argument, NULL, 'n'}, + {"version", required_argument, NULL, 'v'}, + {"filesystem", required_argument, NULL, 'f'}, + {"crypto", required_argument, NULL, 'c'}, + + {NULL, 0, NULL, '\0'} +}; + +struct package_info_t { + char* packageName; + int packageVersion; + char* filesystem; + char* crypto; +}; + +/* + * Print usage info. + */ +void usage(void) +{ + fprintf(stderr, "Opaque Binary Blob (OBB) Tool\n\n"); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, + " %s a[dd] [ OPTIONS ] FILENAME\n" + " Adds an OBB signature to the file.\n\n", gProgName); + fprintf(stderr, + " %s r[emove] FILENAME\n" + " Removes the OBB signature from the file.\n\n", gProgName); + fprintf(stderr, + " %s i[nfo] FILENAME\n" + " Prints the OBB signature information of a file.\n\n", gProgName); +} + +void doAdd(const char* filename, struct package_info_t* info) { + ObbFile *obb = new ObbFile(); + if (obb->readFrom(filename)) { + fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename); + return; + } + + obb->setPackageName(String8(info->packageName)); + obb->setVersion(info->packageVersion); + + if (!obb->writeTo(filename)) { + fprintf(stderr, "ERROR: %s: couldn't write OBB signature: %s\n", + filename, strerror(errno)); + return; + } + + fprintf(stderr, "OBB signature successfully written\n"); +} + +void doRemove(const char* filename) { + ObbFile *obb = new ObbFile(); + if (!obb->readFrom(filename)) { + fprintf(stderr, "ERROR: %s: no OBB signature present\n", filename); + return; + } + + if (!obb->removeFrom(filename)) { + fprintf(stderr, "ERROR: %s: couldn't remove OBB signature\n", filename); + return; + } + + fprintf(stderr, "OBB signature successfully removed\n"); +} + +void doInfo(const char* filename) { + ObbFile *obb = new ObbFile(); + if (!obb->readFrom(filename)) { + fprintf(stderr, "ERROR: %s: couldn't read OBB signature\n", filename); + return; + } + + printf("OBB info for '%s':\n", filename); + printf("Package name: %s\n", obb->getPackageName().string()); + printf(" Version: %d\n", obb->getVersion()); +} + +/* + * Parse args. + */ +int main(int argc, char* const argv[]) +{ + const char *prog = argv[0]; + struct options *options; + int opt; + int option_index = 0; + struct package_info_t package_info; + + int result = 1; // pessimistically assume an error. + + if (argc < 2) { + wantUsage = 1; + goto bail; + } + + while ((opt = getopt_long(argc, argv, ADD_OPTS, longopts, &option_index)) != -1) { + switch (opt) { + case 0: + if (longopts[option_index].flag) + break; + fprintf(stderr, "'%s' requires an argument\n", longopts[option_index].name); + wantUsage = 1; + goto bail; + case 'n': + package_info.packageName = optarg; + break; + case 'v': + char *end; + package_info.packageVersion = strtol(optarg, &end, 10); + if (*optarg == '\0' || *end != '\0') { + fprintf(stderr, "ERROR: invalid version; should be integer!\n\n"); + wantUsage = 1; + goto bail; + } + break; + case 'f': + package_info.filesystem = optarg; + break; + case 'c': + package_info.crypto = optarg; + break; + case '?': + wantUsage = 1; + goto bail; + } + } + + if (wantVersion) { + fprintf(stderr, "%s %s\n", gProgName, gProgVersion); + } + + if (wantUsage) { + goto bail; + } + +#define CHECK_OP(name) \ + if (strncmp(op, name, opsize)) { \ + fprintf(stderr, "ERROR: unknown function '%s'!\n\n", op); \ + wantUsage = 1; \ + goto bail; \ + } + + if (optind < argc) { + const char* op = argv[optind++]; + const int opsize = strlen(op); + + if (optind >= argc) { + fprintf(stderr, "ERROR: filename required!\n\n"); + wantUsage = 1; + goto bail; + } + + const char* filename = argv[optind++]; + + switch (op[0]) { + case 'a': + CHECK_OP("add"); + if (package_info.packageName == NULL) { + fprintf(stderr, "ERROR: arguments required 'packageName' and 'version'\n"); + goto bail; + } + doAdd(filename, &package_info); + break; + case 'r': + CHECK_OP("remove"); + doRemove(filename); + break; + case 'i': + CHECK_OP("info"); + doInfo(filename); + break; + default: + fprintf(stderr, "ERROR: unknown command '%s'!\n\n", op); + wantUsage = 1; + goto bail; + } + } + +bail: + if (wantUsage) { + usage(); + result = 2; + } + + return result; +} diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java index 57e0bd2790c4..474bc4b198d0 100644 --- a/voip/java/android/net/sip/SipAudioCallImpl.java +++ b/voip/java/android/net/sip/SipAudioCallImpl.java @@ -343,8 +343,11 @@ public class SipAudioCallImpl extends SipSessionAdapter public synchronized void endCall() throws SipException { try { stopRinging(); - if (mSipSession != null) mSipSession.endCall(); stopCall(true); + mInCall = false; + + // perform the above local ops first and then network op + if (mSipSession != null) mSipSession.endCall(); } catch (Throwable e) { throwSipException(e); } |