现在的位置: 首页 > 综合 > 正文

修改Android解锁界面

2013年12月14日 ⁄ 综合 ⁄ 共 14214字 ⁄ 字号 评论关闭

背景  
 
   先说说背景吧,这是本人从WinCE系统转到Android之后,接到的第一个任务就是修改Android原生的解锁界面,之前看了两个星期的书和网络博客,Java的也有、Android应用开发的也有、Linux开发的也有、Android框架介绍的也有。然后写了几个APK试了了一下,觉得自己有能力了,便充满自信地找到组长接任务。组长没有说什么,拿出一个竞争对手公司的样机,玩了几下拿个我,说道:这是竞争对手公司的方案,他们的解锁效果不错,很方便,你看看能不能也做出来。
   说实话接到这个任务当时真的有点失望,心里面一直想,当初做WinCE做的几乎全是驱动,整天和寄存器、指针、协议打交道,现在转到Android,做这些应用的东西真的不太习惯。不过转头一想,不管什么东西,要做就要做好,慢慢来嘛,于是拿走样机回到工位上,安心开始研究。
   样机解锁界面效果类似如下

  其实这也是我后面做出的效果,样机因为没有ROOT不好调试截图,功能是将解锁的图标添加了最近运行的运用的图标,这样的话更方便用户去使用

1.分析 

1.1.Android锁屏功能分析

Android锁屏相关的代码在以下几个路径:

锁屏的具体实现:

 

\frameworks\base\policy\src\com\android\internal\policy\impl

其中的主要代码如下:

锁屏控件的View

\frameworks\base\core\java\com\android\internal\widget\multiwaveview

锁屏控件使用到的资源

\frameworks\base\core\res\res\values-sw600dp-land\arrays.xml

\frameworks\base\core\res\res\drawableXXX

Android上常用的锁屏方法有以下几种:默认锁屏方式(LockScreen)、SIM卡解锁方式(SimUnlockScreen)、图案解锁方式(PatternUnlockScreen)、密码解锁方式(PasswordUnlockScreen)、账号解锁方式(AccountUnlockScreen),这些解锁方式都有对应的源码实现,我们这里讨论的是最常用的默认解锁方式,在Android4.0之后,解锁控件变为“波纹解锁”,即如概述介绍的那样,通过控制中心的圆圈来实现解锁,这种解锁方式,实际上可以进一步增强。

1.1.1.  Android启动后从窗口管理器运行到解锁界面的动作

1.开机启动后执行到PhoneWindowManager.systemReady()

2.调用KeyguardViewMediator.onSystemReady()进行待机锁屏及解锁逻辑。

3.KeyguardViewMediator是整个待机解锁屏业务的调度器,负责调度锁屏界面的相关动作及查询解锁屏状态。

1.1.2.  KeyguardViewMediator的作用

1.查询锁屏状态,及当前处于锁屏状态还是已解锁状态,PhoneWindowManager持有KeyguardViewMediator的引用,当用户触摸屏幕或者按下某个键是,PhoneWindowManager会通过KeyguardViewMediator查询锁屏状态(锁定/解锁),进行不同的响应处理。如果处于锁定状态,系统输入事件会受到限制。

2.响应电源事件(黑/亮屏)。判断锁屏界面应该处于什么状态(显示或者重置)。手机黑屏后,锁屏界面马上就会显示出来,以便下一次亮屏后,马上就能显示锁屏界面,而不会出现闪烁或延时。

3.其他应用程序或者服务也可以请求禁止锁屏(通过调用KeyguardViewMediatorsetKeyguardEnabled(boolean)方法)。例如接听来电界面。

KeyguardViewMediator类在WindowManagerPolicy(在手机系统中是PhoneWindowManager实例)初始化时被创建,并运行在它的线程上,锁屏的UI界面也是在这个线程上创建及显示的。KeyguardViewMediator类提供的状态查询api可以被诸如android.view.WindowManagercom.android.server.InputManager等其它线程调用,所以,KeyguardViewMediator类上的这些api方法都是线程同步的(synchronized)。

1.1.3.  KeyguardViewMediator可以进行的调度操作

1) 点亮屏幕pokeWakelock();

2) 报告锁屏权限验证是否成功keyguardDone(boolean);

3) 响应SIM卡状态变化并对锁屏界面做相应的调整onSimStateChanged()。

4) 调度待机锁屏UI界面的管理,包括:

1.显示handleShow ()

2.隐藏handleHide ()

3.重置handleReset ()

4.点亮屏幕handleWakeWhenReady()等。

KeyguardViewMediator实现这部分调度是通过持有一个KeyguardViewManager来实现的。总之KeyguardUpdateMonitor是所有会影响整个待机解/锁屏业务的事件的监控器。(除了作为监控器,它还发挥着类似上下文的作用,也许我们应该把这个类命名为(KeyguardContext)。它监控诸如时间改变、电池状态改变、时区改变、SIM卡状态变化、电话状态变化、电话信号变化等事件。它是一个观察者模式的被观察对象。观察者通过调用KeyguardUpdateMonitor的以下方法进行注册,观察自己感兴趣的变化。

registerInfoCallback(InfoCallback)registerSimStateCallback(SimStateCallback)

 

    KeyguardUpdateMonitor的观察者包括KeyguardViewMediatorLockScreenPatternUnlockScreenAccountUnlockScreenPasswordUnlockScreenSimUnlockScreen等。观察者通过调用KeyguardUpdateMonitorremoveCallback(Object)取消观察。

KeyguardViewManager负责管理待机屏UI界面的创建、显示、隐藏、重置以及通过一个回调KeyguardViewCallback通知调度器KeyguardViewMediator进行相关的调度。

LockPatternKeyguardViewKeyguardViewBase)是所有锁屏和解锁UI界面的宿主。它有2个模式Mode.
LockScreenMode. UnlockScreen。它负责根据当前上下文环境切换当前应该显示的待机屏。

它提供一个回调给当前显示的待机屏并处理其回调,如果回调动作是自己处理不了的,则继续报告给KeyguardViewMediator进行处理。

锁屏界面就是LockScreen;解锁界面包括SIM卡解锁SimUnlockScreen、图案解锁PatternUnlockScreen、密码解锁PasswordUnlockScreen、帐号解锁AccountUnlockScreen

解锁成功后,锁屏流程转到KeyguardViewMediatorkeyguardDone(boolean, boolean) 进行后续的流程(如转到Launcher桌面)。

1.2. 解锁界面布局

解锁界面布局在LockScreen类的构造函数中进行,LockScreen构造函数内容如下:

点击(此处)折叠或打开

  1. LockScreen(Context context, Configuration configuration, LockPatternUtils
    lockPatternUtils,
  2.             KeyguardUpdateMonitor updateMonitor,
  3.             KeyguardScreenCallback callback) {
  4.         super(context);
  5.         mLockPatternUtils = lockPatternUtils;
  6.         mUpdateMonitor = updateMonitor;
  7.         mCallback = callback;
  8.         mEnableMenuKeyInLockScreen = shouldEnableMenuKey();
  9.         mCreationOrientation = configuration.orientation;
  10.         mKeyboardHidden = configuration.hardKeyboardHidden;
  11.         if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
  12.             Log.v(TAG, "***** CREATING LOCK SCREEN", new RuntimeException());
  13.             Log.v(TAG, "Cur orient=" + mCreationOrientation
  14.                     + " res orient=" + context.getResources().getConfiguration().orientation);
  15.         }
  16.         final LayoutInflater inflater = LayoutInflater.from(context);
  17.         if (DBG) Log.v(TAG, "Creation
    orientation = "
     + mCreationOrientation);
  18.         if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) {
  19.             inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true);
  20.         } else {
  21.             inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true);
  22.         }
  23.         mStatusViewManager = new KeyguardStatusViewManager(this, mUpdateMonitor, mLockPatternUtils,
  24.                 mCallback, false);
  25.         setFocusable(true);
  26.         setFocusableInTouchMode(true);
  27.         setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
  28.         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
  29.         mSilentMode = isSilentMode();
  30.         mUnlockWidget = findViewById(R.id.unlock_widget);
  31.         if (mUnlockWidget instanceof SlidingTab) {
  32.             SlidingTab slidingTabView = (SlidingTab) mUnlockWidget;
  33.             slidingTabView.setHoldAfterTrigger(true, false);
  34.             slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label);
  35.             slidingTabView.setLeftTabResources(
  36.                     R.drawable.ic_jog_dial_unlock,
  37.                     R.drawable.jog_tab_target_green,
  38.                     R.drawable.jog_tab_bar_left_unlock,
  39.                     R.drawable.jog_tab_left_unlock);
  40.             SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView);
  41.             slidingTabView.setOnTriggerListener(slidingTabMethods);
  42.             mUnlockWidgetMethods = slidingTabMethods;
  43.         } else if (mUnlockWidget instanceof WaveView) {
  44.             WaveView waveView = (WaveView) mUnlockWidget;
  45.             WaveViewMethods waveViewMethods = new WaveViewMethods(waveView);
  46.             waveView.setOnTriggerListener(waveViewMethods);
  47.             mUnlockWidgetMethods = waveViewMethods;
  48.         } else if (mUnlockWidget instanceof MultiWaveView) {
  49.             MultiWaveView multiWaveView = (MultiWaveView) mUnlockWidget;
  50.             MultiWaveViewMethods multiWaveViewMethods = new MultiWaveViewMethods(multiWaveView);
  51.             multiWaveView.setOnTriggerListener(multiWaveViewMethods);
  52.             mUnlockWidgetMethods = multiWaveViewMethods;
  53.         } else {
  54.             throw new IllegalStateException("Unrecognized
    unlock widget: "
     + mUnlockWidget);
  55.         }
  56.         // Update widget with initial ring state
  57.         mUnlockWidgetMethods.updateResources(context);
  58.         if (DBG) Log.v(TAG, "***
    LockScreen accel is "
  59.                 + (mUnlockWidget.isHardwareAccelerated() ? "on":"off"));
  60.     }

通过添加打印发现在480分辨率下采用的Layout文件为\layout-sw480dp\keyguard_screen_tab_unlock_land.xml,此文件的内容如下:

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!--
  3. **
  4. ** Copyright 2009, The Android Open Source Project
  5. **
  6. ** Licensed under the Apache License, Version 2.(the "License")
  7. ** you may not use this file except in compliance with the License.
  8. ** You may obtain a copy of the License at
  9. **
  10. ** http://www.apache.org/licenses/LICENSE-2.0
  11. **
  12. ** Unless required by applicable law or agreed to in writing, software
  13. ** distributed under the License is distributed on an "AS IS" BASIS,
  14. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. ** See the License for the specific language governing permissions and
  16. ** limitations under the License.
  17. */
  18. -->
  19. <!-- This is the general lock screen which shows information about the
  20.   state of the device, as well as instructions on how to get past it
  21.   depending on the state of the device.-->
  22. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  23.     xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock"
  24.     android:layout_width="match_parent"
  25.     android:layout_height="match_parent"
  26.     android:orientation="horizontal"
  27.     android:id="@+id/root">
  28.     <!-- left side: status and music -->
  29.     <RelativeLayout
  30.         android:layout_height="match_parent"
  31.         android:layout_weight="1"
  32.         android:layout_width="0dip"
  33.         android:gravity="center">
  34.         <RelativeLayout android:id="@+id/transport_bg_protect"
  35.             android:layout_width="512dip"
  36.             android:layout_height="wrap_content">
  37.             <!-- Music transport control underneath -->
  38.             <include android:id="@+id/transport"
  39.                 layout="@layout/keyguard_transport_control"
  40.                 android:layout_row="0"
  41.                 android:layout_column="0"
  42.                 android:layout_rowSpan="3"
  43.                 android:layout_columnSpan="1"
  44.                 android:layout_gravity="fill"
  45.                 android:layout_width="match_parent"
  46.                 android:layout_height="512dip"
  47.                 />
  48.             <include layout="@layout/keyguard_screen_status_land"
  49.                 android:layout_width="match_parent"
  50.                 android:layout_height="wrap_content"
  51.                 android:layout_marginLeft="50dip"
  52.                 android:layout_marginTop="50dip"
  53.                 android:layout_marginBottom="82dip"
  54.                 android:layout_marginRight="64dip"
  55.                 android:layout_alignParentTop="true"
  56.                 android:layout_alignParentLeft="true"/>
  57.         </RelativeLayout>
  58.     </RelativeLayout>
  59.     <!-- right side -->
  60.     <RelativeLayout
  61.         android:layout_height="match_parent"
  62.         android:layout_weight="1"
  63.         android:layout_width="0dip"
  64.         android:gravity="center_horizontal|center_vertical">
  65.         <TextView
  66.             android:id="@+id/screenLocked"
  67.             android:layout_width="wrap_content"
  68.             android:layout_height="wrap_content"
  69.             android:textAppearance="?android:attr/textAppearanceMedium"
  70.             android:gravity="center"
  71.             android:layout_marginTop="12dip"
  72.             android:layout_alignParentLeft="true"
  73.             android:layout_alignParentTop="true"
  74.             android:drawablePadding="4dip"/>
  75.         <com.android.internal.widget.multiwaveview.MultiWaveView
  76.             android:id="@+id/unlock_widget"
  77.             android:layout_width="match_parent"
  78.             android:layout_height="match_parent"
  79.             android:layout_rowSpan="7"
  80.             android:layout_gravity="center_vertical|center_horizontal"
  81.             android:targetDrawables="@array/lockscreen_targets_with_camera"
  82.             android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
  83.             android:directionDescriptions="@array/lockscreen_direction_descriptions"
  84.             android:handleDrawable="@drawable/ic_lockscreen_handle"
  85.             android:waveDrawable="@drawable/ic_lockscreen_outerring"
  86.             android:outerRadius="@dimen/multiwaveview_target_placement_radius"
  87.             android:snapMargin="@dimen/multiwaveview_snap_margin"
  88.             android:hitRadius="@dimen/multiwaveview_hit_radius"
  89.             android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
  90.             android:feedbackCount="3"
  91.             android:vibrationDuration="20"
  92.             android:horizontalOffset="0dip"
  93.             android:verticalOffset="0dip"
  94.         />
  95.         <!-- emergency call button shown when sim is PUKd and tab_selector is hidden -->
  96.         <Button
  97.             android:id="@+id/emergencyCallButton"
  98.             android:layout_width="wrap_content"
  99.             android:layout_height="wrap_content"
  100.             android:layout_marginRight="80dip"
  101.             android:layout_marginBottom="80dip"
  102.             android:layout_alignParentRight="true"
  103.             android:layout_alignParentBottom="true"
  104.             android:drawableLeft="@drawable/ic_emergency"
  105.             style="@style/Widget.Button.Transparent"
  106.             android:drawablePadding="8dip"
  107.             android:visibility="gone"/>
  108.     </RelativeLayout>>
  109. </LinearLayout>

   从文件中可以看出,解锁界面的数字时钟、充电状态、波纹解锁等控件均在其中布局,对解锁控件的大小修改也是通过修改该文件进行的。

1.3. MultiWaveView控件分析

对于Android4.0默认的LockScreen,采用的是MultiWaveView控件,LockScreen中创建该控件的代码如下:

点击(此处)折叠或打开

  1. mUnlockWidget = findViewById(R.id.unlock_widget);
  2.         if (mUnlockWidget instanceof SlidingTab) {
  3.             SlidingTab slidingTabView = (SlidingTab) mUnlockWidget;
  4.             slidingTabView.setHoldAfterTrigger(true, false);
  5.             slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label);
  6.             slidingTabView.setLeftTabResources(
  7.                     R.drawable.ic_jog_dial_unlock,
  8.                     R.drawable.jog_tab_target_green,
  9.                     R.drawable.jog_tab_bar_left_unlock,
  10.                     R.drawable.jog_tab_left_unlock);
  11.             SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView);
  12.             slidingTabView.setOnTriggerListener(slidingTabMethods);
  13.             mUnlockWidgetMethods = slidingTabMethods;
  14.         } else if (mUnlockWidget instanceof WaveView) {
  15.             WaveView waveView = (WaveView) mUnlockWidget;
  16.             WaveViewMethods waveViewMethods = new WaveViewMethods(waveView);
  17.             waveView.setOnTriggerListener(waveViewMethods);
  18.             mUnlockWidgetMethods = waveViewMethods;
  19.         } else if (mUnlockWidget instanceof MultiWaveView) {
  20.             MultiWaveView multiWaveView = (MultiWaveView) mUnlockWidget;
  21.             MultiWaveViewMethods multiWaveViewMethods = new MultiWaveViewMethods(multiWaveView);
  22.             multiWaveView.setOnTriggerListener(multiWaveViewMethods);
  23.             mUnlockWidgetMethods = multiWaveViewMethods;
  24.         } else {
  25.             throw new IllegalStateException("Unrecognized
    unlock widget: "
     + mUnlockWidget);
  26.         }

这是LockScreen的构造函数中的代码,函数根据R.id.unlock_widget定义的类型选择不同的控件类,其中第一种是Android2.3的滑动解锁类,第二种的简单的波纹解锁类,第三种才是我们使用的MultiWaveView类,函数并创建了一个MultiWaveViewMethods类,这个类实际上是为了更好地使用而进行的封装,它的代码如下:

点击(此处)折叠或打开

  1. class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
  2.             UnlockWidgetCommonMethods {
  3.         private final MultiWaveView mMultiWaveView;
  4.         private boolean mCameraDisabled;
  5.         MultiWaveViewMethods(MultiWaveView multiWaveView) {
  6.             mMultiWaveView = multiWaveView;
  7.             final boolean cameraDisabled = mLockPatternUtils.getDevicePolicyManager()
  8.                     .getCameraDisabled(null);
  9.             if (cameraDisabled) {
  10.                 Log.v(TAG, "Camera disabled by Device Policy");
  11.                 mCameraDisabled = true;
  12.             } else {
  13.                 // Camera is enabled if resource is initially defined for MultiWaveView
  14.                 // in the lockscreen layout file
  15.                 mCameraDisabled = mMultiWaveView.getTargetResourceId()
  16.                         != R.array.lockscreen_targets_with_camera;
  17.             }
  18.         }

抱歉!评论已关闭.