diff options
Diffstat (limited to 'sdk/src/java/cyanogenmod/externalviews/KeyguardExternalView.java')
-rw-r--r-- | sdk/src/java/cyanogenmod/externalviews/KeyguardExternalView.java | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/sdk/src/java/cyanogenmod/externalviews/KeyguardExternalView.java b/sdk/src/java/cyanogenmod/externalviews/KeyguardExternalView.java new file mode 100644 index 0000000..9f4059a --- /dev/null +++ b/sdk/src/java/cyanogenmod/externalviews/KeyguardExternalView.java @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2015 The CyanogenMod 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 cyanogenmod.externalviews; + +import android.app.Activity; +import android.app.Application; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowManager; + +import java.util.LinkedList; + +/** + * This class provides a placeholder view for hosting an external view, provided by a + * {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService}, within the lock screen. + * + * <p>This class is intended to only be used within the SystemUi process.</p> + * @hide + */ +public class KeyguardExternalView extends View implements ViewTreeObserver.OnPreDrawListener, + IBinder.DeathRecipient { + private static final String TAG = KeyguardExternalView.class.getSimpleName(); + + /** + * An extra passed via an intent that provides a list of permissions that should be requested + * from the user. + */ + public static final String EXTRA_PERMISSION_LIST = "permissions_list"; + + /** + * Category defining an activity to call to request permissions that a + * {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} will need. Apps that + * provide a {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} should + * check that they have the required permission before making any method calls that would + * require a dangerous permission to be granted. + */ + public static final String CATEGORY_KEYGUARD_GRANT_PERMISSION + = "org.cyanogenmod.intent.category.KEYGUARD_GRANT_PERMISSION"; + + private LinkedList<Runnable> mQueue = new LinkedList<Runnable>(); + + private Context mContext; + private final ExternalViewProperties mExternalViewProperties; + private volatile IKeyguardExternalViewProvider mExternalViewProvider; + private IBinder mService; + private final Point mDisplaySize; + private boolean mIsInteractive; + + private KeyguardExternalViewCallbacks mCallback; + + private OnWindowAttachmentChangedListener mWindowAttachmentListener; + + public KeyguardExternalView(Context context, AttributeSet attrs) { + this(context, attrs, null); + } + + public KeyguardExternalView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs); + } + + public KeyguardExternalView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + this(context, attrs); + } + + /** + * @param context + * @param attributeSet + * @param componentName The component name for the + * {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} + * that will be bound to create the external view. + */ + public KeyguardExternalView(Context context, AttributeSet attributeSet, ComponentName componentName) { + super(context, attributeSet); + mContext = getContext(); + mExternalViewProperties = new ExternalViewProperties(this, mContext); + if (componentName != null) { + mContext.bindService(new Intent().setComponent(componentName), + mServiceConnection, Context.BIND_AUTO_CREATE); + } + mDisplaySize = new Point(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getRealSize(mDisplaySize); + } + + private ServiceConnection mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + try { + IExternalViewProviderFactory factory = IExternalViewProviderFactory.Stub.asInterface(service); + if (factory != null) { + mExternalViewProvider = IKeyguardExternalViewProvider.Stub.asInterface( + factory.createExternalView(null)); + if (mExternalViewProvider != null) { + mExternalViewProvider.registerCallback( + KeyguardExternalView.this.mKeyguardExternalViewCallbacks); + mService = service; + mService.linkToDeath(KeyguardExternalView.this, 0); + executeQueue(); + } else { + Log.e(TAG, "Unable to get external view provider"); + } + } else { + Log.e(TAG, "Unable to get external view provider factory"); + } + } catch (RemoteException e) { + e.printStackTrace(); + } + // We should unbind the service if we failed to connect to the provider + if (mService != service && service != null) { + mContext.unbindService(mServiceConnection); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (mExternalViewProvider != null) { + try { + mExternalViewProvider.unregisterCallback( + KeyguardExternalView.this.mKeyguardExternalViewCallbacks); + } catch (RemoteException e) { + } + mExternalViewProvider = null; + } + if (mService != null) { + mService.unlinkToDeath(KeyguardExternalView.this, 0); + mService = null; + } + } + }; + + private final IKeyguardExternalViewCallbacks mKeyguardExternalViewCallbacks = + new IKeyguardExternalViewCallbacks.Stub() { + @Override + public boolean requestDismiss() throws RemoteException { + if (mCallback != null) { + return mCallback.requestDismiss(); + } + + return false; + } + + @Override + public boolean requestDismissAndStartActivity(Intent intent) throws RemoteException { + if (mCallback != null) { + return mCallback.requestDismissAndStartActivity(intent); + } + + return false; + } + + @Override + public void collapseNotificationPanel() throws RemoteException { + if (mCallback != null) { + mCallback.collapseNotificationPanel(); + } + } + + @Override + public void setInteractivity(boolean isInteractive) { + mIsInteractive = isInteractive; + } + + @Override + public void onAttachedToWindow() { + if (mWindowAttachmentListener != null) { + mWindowAttachmentListener.onAttachedToWindow(); + } + } + + @Override + public void onDetachedFromWindow() { + if (mWindowAttachmentListener != null) { + mWindowAttachmentListener.onDetachedFromWindow(); + } + } + + @Override + public void slideLockscreenIn() { + if (mCallback != null) { + mCallback.slideLockscreenIn(); + } + } + }; + + private void executeQueue() { + while (!mQueue.isEmpty()) { + Runnable r = mQueue.pop(); + r.run(); + } + } + + protected void performAction(Runnable r) { + if (mExternalViewProvider != null) { + r.run(); + } else { + mQueue.add(r); + } + } + + // view overrides, for positioning + + @Override + public boolean onPreDraw() { + if (!mExternalViewProperties.hasChanged()) { + return true; + } + // keyguard views always take up the full screen when visible + final int x = mExternalViewProperties.getX(); + final int y = mExternalViewProperties.getY(); + final int width = mDisplaySize.x - x; + final int height = mDisplaySize.y - y; + final boolean visible = mExternalViewProperties.isVisible(); + final Rect clipRect = new Rect(x, y, width + x, height + y); + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.alterWindow(x, y, width, height, visible, + clipRect); + } catch (RemoteException e) { + } + } + }); + return true; + } + + // Placeholder callbacks + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onDetach(); + } catch (RemoteException e) { + } + } + }); + } + + @Override + public void onAttachedToWindow() { + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onAttach(null); + } catch (RemoteException e) { + } + } + }); + } + + @Override + public void binderDied() { + if (mCallback != null) { + mCallback.providerDied(); + } + } + + /** + * Sets the component of the {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} + * to be used for this ExternalView. If a provider is already connected to this view, it is + * first unbound before binding to the new provider. + * @param componentName The {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} + * to bind to. + */ + public void setProviderComponent(ComponentName componentName) { + // unbind any existing external view provider + if (mExternalViewProvider != null) { + mContext.unbindService(mServiceConnection); + } + if (componentName != null) { + mContext.bindService(new Intent().setComponent(componentName), + mServiceConnection, Context.BIND_AUTO_CREATE); + } + } + + /** + * Called from the host when the keyguard is being shown to the user. + * @param screenOn True if the screen is currently on. + */ + public void onKeyguardShowing(final boolean screenOn) { + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onKeyguardShowing(screenOn); + } catch (RemoteException e) { + } + } + }); + } + + /** + * Called from the host when the user has unlocked the device. Once this is called the lock + * lock screen should no longer displayed. + */ + public void onKeyguardDismissed() { + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onKeyguardDismissed(); + } catch (RemoteException e) { + } + } + }); + } + + /** + * Called from the host when the keyguard is displaying the security screen for the user to + * enter their pin, password, or pattern. + * @param showing True if the bouncer is being show or false when it is dismissed without the + * device being unlocked. + */ + public void onBouncerShowing(final boolean showing) { + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onBouncerShowing(showing); + } catch (RemoteException e) { + } + } + }); + } + + /** + * Called from the host when the screen is turned on. + */ + public void onScreenTurnedOn() { + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onScreenTurnedOn(); + } catch (RemoteException e) { + } + } + }); + } + + /** + * Called from the host when the screen is turned off. + */ + public void onScreenTurnedOff() { + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onScreenTurnedOff(); + } catch (RemoteException e) { + } + } + }); + } + + /** + * Called from the host when the user is swiping the lockscreen + * to transition into the live lock screen + * + * @param swipeProgress [0-1] represents the progress of the swipe + */ + public void onLockscreenSlideOffsetChanged(final float swipeProgress) { + performAction(new Runnable() { + @Override + public void run() { + try { + mExternalViewProvider.onLockscreenSlideOffsetChanged(swipeProgress); + } catch (RemoteException e) { + } + } + }); + } + + /** + * External views provided by a + * {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} can be either + * interactive or non-interactive. + * + * <p>A non-interactive component does not receive any input events and functions similar to a + * live wallpaper.</p> + * + * <p>An interactive component can receive input events and allows the user to interact with it + * when the notification panel is not being displayed on top of the external view.</p> + * + * @return True if the current external view is interactive. + */ + public boolean isInteractive() { + return mIsInteractive; + } + + /** + * Registers a {@link cyanogenmod.externalviews.KeyguardExternalView.KeyguardExternalViewCallbacks} + * for receiving events from the + * {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} + * @param callback The callback to register + */ + public void registerKeyguardExternalViewCallback(KeyguardExternalViewCallbacks callback) { + mCallback = callback; + } + + /** + * Unregister a previously registered + * {@link cyanogenmod.externalviews.KeyguardExternalView.KeyguardExternalViewCallbacks} + * @param callback The callback to unregister + */ + public void unregisterKeyguardExternalViewCallback(KeyguardExternalViewCallbacks callback) { + if (mCallback != callback) { + throw new IllegalArgumentException("Callback not registered"); + } + mCallback = null; + } + + /** + * Registers a {@link cyanogenmod.externalviews.KeyguardExternalView.OnWindowAttachmentChangedListener} + * for receiving events from the + * {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} + * @param listener The callback to register + * + * @hide + */ + public void registerOnWindowAttachmentChangedListener( + OnWindowAttachmentChangedListener listener) { + mWindowAttachmentListener = listener; + } + + /** + * Unregister a previously registered + * {@link cyanogenmod.externalviews.KeyguardExternalView.OnWindowAttachmentChangedListener} + * @param listener The callback to unregister + * + * @hide + */ + public void unregisterOnWindowAttachmentChangedListener( + OnWindowAttachmentChangedListener listener) { + if (mWindowAttachmentListener != listener) { + throw new IllegalArgumentException("Callback not registered"); + } + mWindowAttachmentListener = null; + } + + /** + * Callback interface for a {@link cyanogenmod.externalviews.KeyguardExternalViewProviderService} + * to send events to the host's registered + * {@link cyanogenmod.externalviews.KeyguardExternalView.KeyguardExternalViewCallbacks} + */ + public interface KeyguardExternalViewCallbacks { + boolean requestDismiss(); + boolean requestDismissAndStartActivity(Intent intent); + void collapseNotificationPanel(); + void providerDied(); + void slideLockscreenIn(); + } + + /** + * Callback interface for changes to the containing window being attached and detached from the + * window manager. + * @hide + */ + public interface OnWindowAttachmentChangedListener { + void onAttachedToWindow(); + void onDetachedFromWindow(); + } +} |