diff options
Diffstat (limited to 'core/java')
-rw-r--r-- | core/java/android/service/dreams/Dream.java | 392 | ||||
-rw-r--r-- | core/java/android/service/dreams/DreamManagerService.java | 182 | ||||
-rw-r--r-- | core/java/android/service/dreams/IDreamManager.aidl | 30 | ||||
-rw-r--r-- | core/java/android/service/dreams/IDreamService.aidl | 24 | ||||
-rw-r--r-- | core/java/android/view/WindowManager.java | 6 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 25 |
6 files changed, 659 insertions, 0 deletions
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java new file mode 100644 index 0000000..83464c9 --- /dev/null +++ b/core/java/android/service/dreams/Dream.java @@ -0,0 +1,392 @@ +/** + * + */ +package android.service.dreams; + +import com.android.internal.policy.PolicyManager; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.graphics.drawable.ColorDrawable; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Slog; +import android.view.ActionMode; +import android.view.IWindowManager; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager.LayoutParams; +import android.view.accessibility.AccessibilityEvent; +import android.view.WindowManager; +import android.view.WindowManagerImpl; + +/** + * @hide + * + */ +public class Dream extends Service implements Window.Callback { + private final static boolean DEBUG = true; + private final static String TAG = "Dream"; + + /** + * The {@link Intent} that must be declared as handled by the service. + * To be supported, the service must also require the + * {@link android.Manifest.permission#BIND_WALLPAPER} permission so + * that other applications can not abuse it. + */ + @SdkConstant(SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.service.dreams.Dream"; + + private Window mWindow; + + private WindowManager mWindowManager; + private IDreamManager mSandman; + + private boolean mInteractive; + + final Handler mHandler = new Handler(); + + boolean mFinished = false; + + // begin Window.Callback methods + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchKeyEvent(event); + } + + @Override + public boolean dispatchKeyShortcutEvent(KeyEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchKeyShortcutEvent(event); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchTouchEvent(event); + } + + @Override + public boolean dispatchTrackballEvent(MotionEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchTrackballEvent(event); + } + + @Override + public boolean dispatchGenericMotionEvent(MotionEvent event) { + if (!mInteractive) { + finish(); + return true; + } + return mWindow.superDispatchGenericMotionEvent(event); + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + return false; + } + + @Override + public View onCreatePanelView(int featureId) { + return null; + } + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + return false; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + return false; + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + return false; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + return false; + } + + @Override + public void onWindowAttributesChanged(LayoutParams attrs) { + + } + + @Override + public void onContentChanged() { + + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + + } + + @Override + public void onAttachedToWindow() { + mWindow.addFlags( + WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + ); + lightsOut(); + } + + @Override + public void onDetachedFromWindow() { + } + + @Override + public void onPanelClosed(int featureId, Menu menu) { + } + + @Override + public boolean onSearchRequested() { + return false; + } + + @Override + public ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback callback) { + return null; + } + + @Override + public void onActionModeStarted(ActionMode mode) { + } + + @Override + public void onActionModeFinished(ActionMode mode) { + } + // end Window.Callback methods + + public WindowManager getWindowManager() { + return mWindowManager; + } + + public Window getWindow() { + return mWindow; + } + + /** + * Called when this Dream is constructed. Place your initialization here. + * + * Subclasses must call through to the superclass implementation. + */ + @Override + public void onCreate() { + super.onCreate(); + + if (DEBUG) Slog.v(TAG, "Dream created on thread " + Thread.currentThread().getId()); + + mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams")); + } + + /** + * Called when this Dream is started. Place your initialization here. + * + * Subclasses must call through to the superclass implementation. + * + * XXX(dsandler) Might want to make this final and have a different method for clients to override + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return super.onStartCommand(intent, flags, startId); + } + + /** + * Inflate a layout resource and set it to be the content view for this Dream. + * Behaves similarly to {@link android.app.Activity#setContentView(int)}. + * + * @param layoutResID Resource ID to be inflated. + * + * @see #setContentView(android.view.View) + * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) + */ + public void setContentView(int layoutResID) { + getWindow().setContentView(layoutResID); + } + + /** + * Set a view to be the content view for this Dream. + * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)}, + * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view. + * + * @param view The desired content to display. + * + * @see #setContentView(int) + * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) + */ + public void setContentView(View view) { + getWindow().setContentView(view); + } + + /** + * Set a view to be the content view for this Dream. + * Behaves similarly to + * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}. + * + * @param view The desired content to display. + * @param params Layout parameters for the view. + * + * @see #setContentView(android.view.View) + * @see #setContentView(int) + */ + public void setContentView(View view, ViewGroup.LayoutParams params) { + getWindow().setContentView(view, params); + } + + /** + * Add a view to the Dream's window, leaving other content views in place. + * + * @param view The desired content to display. + * @param params Layout parameters for the view. + */ + public void addContentView(View view, ViewGroup.LayoutParams params) { + getWindow().addContentView(view, params); + } + + /** + * @param mInteractive the mInteractive to set + */ + public void setInteractive(boolean mInteractive) { + this.mInteractive = mInteractive; + } + + /** + * @return the mInteractive + */ + public boolean isInteractive() { + return mInteractive; + } + + /** Convenience method for setting View.SYSTEM_UI_FLAG_LOW_PROFILE on the content view. */ + protected void lightsOut() { + // turn the lights down low + final View v = mWindow.getDecorView(); + if (v != null) { + v.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + } + + /** + * Finds a view that was identified by the id attribute from the XML that + * was processed in {@link #onCreate}. + * + * @return The view if found or null otherwise. + */ + public View findViewById(int id) { + return getWindow().findViewById(id); + } + + /** + * Called when this Dream is being removed from the screen and stopped. + */ + @Override + public void onDestroy() { + super.onDestroy(); + mWindowManager.removeView(mWindow.getDecorView()); + } + + /** + * Creates a new dream window, attaches the current content view, and shows it. + * + * @param windowToken Binder to attach to the window to allow access to the correct window type. + * @hide + */ + final /*package*/ void attach(IBinder windowToken) { + if (DEBUG) Slog.v(TAG, "Dream attached on thread " + Thread.currentThread().getId()); + + mWindow = PolicyManager.makeNewWindow(this); + mWindow.setCallback(this); + mWindow.requestFeature(Window.FEATURE_NO_TITLE); + mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000)); + + if (DEBUG) Slog.v(TAG, "attaching window token: " + windowToken + + " to window of type " + WindowManager.LayoutParams.TYPE_DREAM); + + WindowManager.LayoutParams lp = mWindow.getAttributes(); + lp.type = WindowManager.LayoutParams.TYPE_DREAM; + lp.token = windowToken; + lp.windowAnimations = com.android.internal.R.style.Animation_Dream; + + //WindowManagerImpl.getDefault().addView(mWindow.getDecorView(), lp); + + if (DEBUG) Slog.v(TAG, "created and attached window: " + mWindow); + + mWindow.setWindowManager(null, windowToken, "dream", true); + mWindowManager = mWindow.getWindowManager(); + + // now make it visible + mHandler.post(new Runnable(){ + @Override + public void run() { + if (DEBUG) Slog.v(TAG, "Dream window added on thread " + Thread.currentThread().getId()); + + getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes()); + }}); + } + + /** + * Stop the dream and wake up. + * + * After this method is called, the service will be stopped. + */ + public void finish() { + if (mFinished) return; + try { + mSandman.awaken(); // assuming we were started by the DreamManager + stopSelf(); // if launched via any other means + mFinished = true; + } catch (RemoteException ex) { + // sigh + } + } + + class IDreamServiceWrapper extends IDreamService.Stub { + public IDreamServiceWrapper() { + } + + public void attach(IBinder windowToken) { + Dream.this.attach(windowToken); + } + } + + /** + * Implement to return the implementation of the internal accessibility + * service interface. Subclasses should not override. + */ + @Override + public final IBinder onBind(Intent intent) { + return new IDreamServiceWrapper(); + } +} diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java new file mode 100644 index 0000000..8712fa2 --- /dev/null +++ b/core/java/android/service/dreams/DreamManagerService.java @@ -0,0 +1,182 @@ +package android.service.dreams; + +import static android.provider.Settings.Secure.SCREENSAVER_COMPONENT; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +import com.android.internal.view.IInputMethod; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.provider.Settings; +import android.util.Log; +import android.util.Slog; +import android.view.IWindowManager; +import android.view.WindowManager; + +/** + * + * @hide + * + */ + +public class DreamManagerService + extends IDreamManager.Stub + implements ServiceConnection +{ + private static final boolean DEBUG = true; + private static final String TAG = "DreamManagerService"; + + final Object mLock = new Object[0]; + + private Context mContext; + private IWindowManager mIWindowManager; + + private ComponentName mCurrentDreamComponent; + private IDreamService mCurrentDream; + private Binder mCurrentDreamToken; + + public DreamManagerService(Context context) { + if (DEBUG) Slog.v(TAG, "DreamManagerService startup"); + mContext = context; + mIWindowManager = IWindowManager.Stub.asInterface( + ServiceManager.getService(Context.WINDOW_SERVICE)); + } + + private void checkPermission(String permission) { + if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) { + throw new SecurityException("Access denied to process: " + Binder.getCallingPid() + + ", must have permission " + permission); + } + } + + // IDreamManager method + public void dream() { + ComponentName name = getDreamComponent(); + if (name != null) { + synchronized (mLock) { + final long ident = Binder.clearCallingIdentity(); + try { + bindDreamComponentL(name, false); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + } + + // IDreamManager method + public void setDreamComponent(ComponentName name) { + Settings.Secure.putString(mContext.getContentResolver(), SCREENSAVER_COMPONENT, name.flattenToString()); + } + + // IDreamManager method + public ComponentName getDreamComponent() { + // TODO(dsandler) don't load this every time, watch the value + String component = Settings.Secure.getString(mContext.getContentResolver(), SCREENSAVER_COMPONENT); + if (component == null) { + component = mContext.getResources().getString( + com.android.internal.R.string.config_defaultDreamComponent); + } + if (component != null) { + return ComponentName.unflattenFromString(component); + } else { + return null; + } + } + + // IDreamManager method + public void testDream(ComponentName name) { + if (DEBUG) Slog.v(TAG, "startDream name=" + name + + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); +// checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT); + synchronized (mLock) { + final long ident = Binder.clearCallingIdentity(); + try { + bindDreamComponentL(name, true); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + // IDreamManager method + public void awaken() { + if (DEBUG) Slog.v(TAG, "awaken()"); + synchronized (mLock) { + if (mCurrentDream != null) { + mContext.unbindService(this); + } + } + } + + public void bindDreamComponentL(ComponentName componentName, boolean test) { + if (DEBUG) Slog.v(TAG, "bindDreamComponent: componentName=" + componentName + + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + + Intent intent = new Intent(Intent.ACTION_MAIN) + .setComponent(componentName) + .addFlags( + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + ) + .putExtra("android.dreams.TEST", test); + + if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) { + Slog.w(TAG, "unable to bind service: " + componentName); + return; + } + mCurrentDreamComponent = componentName; + mCurrentDreamToken = new Binder(); + try { + if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken + + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM); + mIWindowManager.addWindowToken(mCurrentDreamToken, + WindowManager.LayoutParams.TYPE_DREAM); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to add window token. Proceed at your own risk."); + } + + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) Slog.v(TAG, "connected to dream: " + name + " binder=" + service + " thread=" + Thread.currentThread().getId()); + + mCurrentDream = IDreamService.Stub.asInterface(service); + try { + if (DEBUG) Slog.v(TAG, "attaching with token:" + mCurrentDreamToken); + mCurrentDream.attach(mCurrentDreamToken); + } catch (RemoteException ex) { + Slog.w(TAG, "Unable to send window token to dream:" + ex); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (DEBUG) Slog.v(TAG, "disconnected: " + name + " service: " + mCurrentDream); + mCurrentDream = null; + mCurrentDreamToken = null; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Dreamland:"); + pw.print(" component="); pw.println(mCurrentDreamComponent); + pw.print(" token="); pw.println(mCurrentDreamToken); + pw.print(" dream="); pw.println(mCurrentDream); + } + + public void systemReady() { + if (DEBUG) Slog.v(TAG, "ready to dream!"); + } + +} diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl new file mode 100644 index 0000000..7225013 --- /dev/null +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2012, 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.service.dreams; + +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.content.ComponentName; + +/** @hide */ +interface IDreamManager { + void dream(); + void awaken(); + void setDreamComponent(in ComponentName componentName); + ComponentName getDreamComponent(); + void testDream(in ComponentName componentName); +}
\ No newline at end of file diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl new file mode 100644 index 0000000..1bb241a --- /dev/null +++ b/core/java/android/service/dreams/IDreamService.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2012 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.service.dreams; + +/** + * @hide + */ +oneway interface IDreamService { + void attach(IBinder windowToken); +} diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index f3ef329..bc310b0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -423,6 +423,12 @@ public interface WindowManager extends ViewManager { public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22; /** + * Window type: Dreams (screen saver) window, just above keyguard. + * @hide + */ + public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23; + + /** * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 491cd67..66bdc5d 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -1049,6 +1049,31 @@ public interface WindowManagerPolicy { public void lockNow(); /** + * Check to see if a screensaver should be run instead of powering off the screen on timeout. + * + * @return true if the screensaver should run, false if the screen should turn off. + * + * @hide + */ + public boolean isScreenSaverEnabled(); + + /** + * Start the screensaver (if it is enabled and not yet running). + * + * @return Whether the screensaver was successfully started. + * + * @hide + */ + public boolean startScreenSaver(); + + /** + * Stop the screensaver if it is running. + * + * @hide + */ + public void stopScreenSaver(); + + /** * Print the WindowManagerPolicy's state into the given stream. * * @param prefix Text to print at the front of each line. |