背景
先说说背景吧,这是本人从WinCE系统转到Android之后,接到的第一个任务就是修改Android原生的解锁界面,之前看了两个星期的书和网络博客,Java的也有、Android应用开发的也有、Linux开发的也有、Android框架介绍的也有。然后写了几个APK试了了一下,觉得自己有能力了,便充满自信地找到组长接任务。组长没有说什么,拿出一个竞争对手公司的样机,玩了几下拿个我,说道:这是竞争对手公司的方案,他们的解锁效果不错,很方便,你看看能不能也做出来。
说实话接到这个任务当时真的有点失望,心里面一直想,当初做WinCE做的几乎全是驱动,整天和寄存器、指针、协议打交道,现在转到Android,做这些应用的东西真的不太习惯。不过转头一想,不管什么东西,要做就要做好,慢慢来嘛,于是拿走样机回到工位上,安心开始研究。
其实这也是我后面做出的效果,样机因为没有ROOT不好调试截图,功能是将解锁的图标添加了最近运行的运用的图标,这样的话更方便用户去使用
1.分析
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.开机启动后执行到PhoneWindowManager.systemReady()。
2.调用KeyguardViewMediator.onSystemReady()进行待机锁屏及解锁逻辑。
3.KeyguardViewMediator是整个待机解锁屏业务的调度器,负责调度锁屏界面的相关动作及查询解锁屏状态。
1.1.2. KeyguardViewMediator的作用1.查询锁屏状态,及当前处于锁屏状态还是已解锁状态,PhoneWindowManager持有KeyguardViewMediator的引用,当用户触摸屏幕或者按下某个键是,PhoneWindowManager会通过KeyguardViewMediator查询锁屏状态(锁定/解锁),进行不同的响应处理。如果处于锁定状态,系统输入事件会受到限制。
2.响应电源事件(黑/亮屏)。判断锁屏界面应该处于什么状态(显示或者重置)。手机黑屏后,锁屏界面马上就会显示出来,以便下一次亮屏后,马上就能显示锁屏界面,而不会出现闪烁或延时。
3.其他应用程序或者服务也可以请求禁止锁屏(通过调用KeyguardViewMediator的setKeyguardEnabled(boolean)方法)。例如接听来电界面。
KeyguardViewMediator类在WindowManagerPolicy(在手机系统中是PhoneWindowManager实例)初始化时被创建,并运行在它的线程上,锁屏的UI界面也是在这个线程上创建及显示的。KeyguardViewMediator类提供的状态查询api可以被诸如android.view.WindowManager、com.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的观察者包括KeyguardViewMediator、LockScreen、PatternUnlockScreen、AccountUnlockScreen、PasswordUnlockScreen、SimUnlockScreen等。观察者通过调用KeyguardUpdateMonitor的removeCallback(Object)取消观察。
KeyguardViewManager负责管理待机屏UI界面的创建、显示、隐藏、重置以及通过一个回调KeyguardViewCallback通知调度器KeyguardViewMediator进行相关的调度。
LockPatternKeyguardView(KeyguardViewBase)是所有锁屏和解锁UI界面的宿主。它有2个模式Mode. LockScreen和Mode. UnlockScreen。它负责根据当前上下文环境切换当前应该显示的待机屏。
它提供一个回调给当前显示的待机屏并处理其回调,如果回调动作是自己处理不了的,则继续报告给KeyguardViewMediator进行处理。
锁屏界面就是LockScreen;解锁界面包括SIM卡解锁SimUnlockScreen、图案解锁PatternUnlockScreen、密码解锁PasswordUnlockScreen、帐号解锁AccountUnlockScreen
解锁成功后,锁屏流程转到KeyguardViewMediator的keyguardDone(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,此文件的内容如下:
<?xml version="1.0" encoding="utf-8"?> <!-- ** ** Copyright 2009, 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. */ --> <!-- This is the general lock screen which shows information about the state of the device, as well as instructions on how to get past it depending on the state of the device.--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tabunlock="http://schemas.android.com/apk/res/com.android.tabunlock" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:id="@+id/root"> <!-- left side: status and music --> <RelativeLayout android:layout_height="match_parent" android:layout_weight="1" android:layout_width="0dip" android:gravity="center"> <RelativeLayout android:id="@+id/transport_bg_protect" android:layout_width="512dip" android:layout_height="wrap_content"> <!-- Music transport control underneath --> <include android:id="@+id/transport" layout="@layout/keyguard_transport_control" android:layout_row="0" android:layout_column="0" android:layout_rowSpan="3" android:layout_columnSpan="1" android:layout_gravity="fill" android:layout_width="match_parent" android:layout_height="512dip" /> <include layout="@layout/keyguard_screen_status_land" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="50dip" android:layout_marginTop="50dip" android:layout_marginBottom="82dip" android:layout_marginRight="64dip" android:layout_alignParentTop="true" android:layout_alignParentLeft="true"/> </RelativeLayout> </RelativeLayout> <!-- right side --> <RelativeLayout android:layout_height="match_parent" android:layout_weight="1" android:layout_width="0dip" android:gravity="center_horizontal|center_vertical"> <TextView android:id="@+id/screenLocked" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:gravity="center" android:layout_marginTop="12dip" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:drawablePadding="4dip"/> <com.android.internal.widget.multiwaveview.MultiWaveView android:id="@+id/unlock_widget" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_rowSpan="7" android:layout_gravity="center_vertical|center_horizontal" android:targetDrawables="@array/lockscreen_targets_with_camera" android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera" android:directionDescriptions="@array/lockscreen_direction_descriptions" android:handleDrawable="@drawable/ic_lockscreen_handle" android:waveDrawable="@drawable/ic_lockscreen_outerring" android:outerRadius="@dimen/multiwaveview_target_placement_radius" android:snapMargin="@dimen/multiwaveview_snap_margin" android:hitRadius="@dimen/multiwaveview_hit_radius" android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right" android:feedbackCount="3" android:vibrationDuration="20" android:horizontalOffset="0dip" android:verticalOffset="0dip" /> <!-- emergency call button shown when sim is PUKd and tab_selector is hidden --> <Button android:id="@+id/emergencyCallButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="80dip" android:layout_marginBottom="80dip" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" android:drawableLeft="@drawable/ic_emergency" style="@style/Widget.Button.Transparent" android:drawablePadding="8dip" android:visibility="gone"/> </RelativeLayout>> </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 } 19 public void updateResources() { 20 int resId; 21 if (mCameraDisabled) { 22 // Fall back to showing ring/silence if camera is disabled by DPM... 23 resId = mSilentMode ? R.array.lockscreen_targets_when_silent 24 : R.array.lockscreen_targets_when_soundon; 25 } else { 26 resId = R.array.lockscreen_targets_with_camera; 27 } 28 mMultiWaveView.setTargetResources(resId); 29 } 30 public void onGrabbed(View v, int handle) { 31 } 32 public void onReleased(View v, int handle) { 33 } 34 public void onTrigger(View v, int target) { 35 if (target == 0 || target == 1) { // 0 = unlock/portrait, 1 = unlock/landscape 36 mCallback.goToUnlockScreen(); 37 } else if (target == 2 || target == 3) { // 2 = alt/portrait, 3 = alt/landscape 38 if (!mCameraDisabled) { 39 // Start the Camera 40 Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); 41 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 42 mContext.startActivity(intent); 43 mCallback.goToUnlockScreen(); 44 } else { 45 toggleRingMode(); 46 mUnlockWidgetMethods.updateResources(); 47 mCallback.pokeWakelock(); 48 } 49 } 50 } 51 public void onGrabbedStateChange(View v, int handle) { 52 // Don't poke the wake lock when returning to a state where the handle is 53 // not grabbed since that can happen when the system (instead of the user) 54 // cancels the grab. 55 if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) { 56 mCallback.pokeWakelock(); 57 } 58 }
这个类有两个方法特别重要,一个是更新MultiWaveView的资源,即public void updateResources(),另一个是对解锁后的响应,即public void onTrigger(View v, int target),这方法传入的第二个参数为解锁选择的图标编号,图标是从右向左逆时针编号的,即最右边的图标编号为0,在此函数中即可进行解锁的处理,选择是进入主界面还是启动其他的Activity。Android4.0默认target = 0对应的是进入主界面,
target = 2或者target = 3启动Camera,其解锁界面的图标是每次都是使用固定的资源,在完成解锁后按下Power键或者系统再次进入锁定状态,LockScreen都会再构造一次,会重新布局并加载资源,因此可以使每次解锁界面都不一样。
2. 实现2.1. 获取最近运行程序
在Android中可以通过ActivityManager获取到最近运行的Activity,详细的用法如下:
输入参数是需要查询的最大最近运行任务个数,查询的方式(默认采用ActivityManager.RECENT_IGNOR_UNAVAILABLE),返回ActivityManager.RecentTaskInfo对象,其定义如下:
其中的baseIntent为启动最近运行任务的Intent,通过它我们可以很方便地获取Activity的图标并启动最近运行的Activity。
相关的代码如下:
final ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RecentTaskInfo> recentLs = am.getRecentTasks(7, ActivityManager.RECENT_IGNORE_UNAVAILABLE); |
通过PackManager我们可以很方便地获取到Activity的图标,对应的代码如下:
final PackageManager pm = context.getPackageManager(); pm.getActivityIcon(recentLs.get(i).baseIntent) |
这个文件中包含了大量Android中的配置信息,其中也有和显示分辨率相关的,修改的方法如下:
1.通过ADB将文件获取到主机任意文件夹。
adb pull /system/build.prop |
2.用编辑软件打开build.prop,找到如下行
2.将ro.sf.lcd_density=120修改为=160或者直接删除掉这一行(这样就使用默认160)。
3.执行
adb push build.prop /system/ |
2.3. 修改MultiWaveView控件
修改以下位置的源文件:
Z:\exdroid\android4.0.1\frameworks\base\core\java\com\android\internal\widget\multiwaveview\MultiWaveView.java |
重载setTargetResources方法,重载后的方法如下:
1 public void setTargetResources(ArrayList<Drawable> drawables) 2 { 3 Resources res = getContext().getResources(); 4 int count = drawables.size(); 5 ArrayList<TargetDrawable> targetDrawables = new ArrayList<TargetDrawable>(count); 6 for (int i = 0; i < count; i++) { 7 Drawable drawable = drawables.get(i); 8 targetDrawables.add(new TargetDrawable(res, drawable)); 9 Log.v(TAG,"Add a Drawable"); 10 } 11 mTargetDrawables = targetDrawables; 12 updateTargetPositions(); 13 }
重载后的方法支持直接传入图片链表。这个方法是提供给LockScreen调用的
2.4.修改LockScreen.java文件
重载其中的MultiWaveViewMethods类的updateResources方法,重载后的方法如下:
1 public void updateResources(Context context) 2 { 3 ArrayList<Drawable> drawableAl = new ArrayList(); 4 final ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); 5 final PackageManager pm = context.getPackageManager(); 6 drawableAl.add(getView().getResources().getDrawable(R.drawable.ic_lockscreen_unlock)); 7 List<ActivityManager.RecentTaskInfo> recentLs = am.getRecentTasks(7, ActivityManager.RECENT_IGNORE_UNAVAILABLE); 8 for(int i=0;i<recentLs.size();i++) 9 { 10 try 11 { 12 drawableAl.add(pm.getActivityIcon(recentLs.get(i).baseIntent)); 13 mIntentList.add(recentLs.get(i).baseIntent); 14 } 15 catch(Exception e) 16 { 17 Log.v(TAG,"Catch Exception"); 18 } 19 } 20 mMultiWaveView.setTargetResources(drawableAl); 21 }
重载后的updateResources函数实际上先获取最近运行的任务列表,再获取任务图标,最后用获取的图标设置MultiWaveView控件。
修改解锁响应onTigger:
public void onTrigger(View v, int target) { Log.v(TAG,"onTrigger = " + target); if(target ==0) { mCallback.goToUnlockScreen(); } else { if(mIntentList.get(target-1)!=null) { Intent intent = mIntentList.get(target-1); mContext.startActivity(intent); mCallback.goToUnlockScreen(); } } }
这样解锁事件的响应被修改成0号图标解锁,其余启动对应的Activity。
2.5. 调整解锁圆圈大小
启动应用程序的功能实现了,但是解锁圆圈的大小还是太大,特别是在更改dpi之后,圆圈几乎占据了半个显示屏,显得并不雅观。
实际上,解锁圆圈的资源就是/framework/cors/res/res/drawable-xxx中的unlock_ring.png,对于不同分辨率的设备,会采用不同的大小。我们可以通过修改位图的大小来进行更改,但在实际测试中修改了所有的unlock_ring.png,也未见解锁图标变小。
决定采用代码配合更改图案大小的功能,如图:
mOuterRing为外圆圈的资源,mOuterRadius为解锁圆圈的活动半径,修改代码后直接从图片获取,这样将采用drawable-sw480dp-mdpi下的图片,通过PhotoShop等软件将圆圈图片缩小,最终显示出的圆圈就变小了。
3. 关于Android屏幕的知识(摘自网上)
density表示每英寸有多少个显示点(逻辑值),它的单位是dpi:dot per inch,通常屏幕大时,density就大,屏幕小时,density就小,通常:
屏幕实际分辨率为240px*400px时,density=120
屏幕实际分辨率为320px*533px,density=160
屏幕实际分辨率为480px*800px,density=240
3.2 分辨率
是整个屏是多少点,比如800x480,它是软件的显示单位,实际上会因为不同的显示屏的像素大小不同,造成density不同
3.3 资源目录名称
res/xxx-hdpi 当density为240时,使用此目录下的资源 res/xxx-mdpi 当density为160时,使用此目录下的资源 res/xxx-ldpi 当density为120时,使用此目录下的资源 res/xxx 不常后缀,为默认设置,同xxx-mdpi
3.4 资源单位(xml文件中定义大小的单位)
a)dp=dip=dx (Density independent pixel)
基于屏幕密度的抽象单位,设备无关的点,用于说明与密度无关的尺寸和位置。这些单位是相对于一个160dpi的屏幕,所有一个dp是160dpi屏幕上的一个点。
b)px (Pixel)
px指软件的单位点,设备相关的点
3.5 获取屏幕信息的相关代码片段
1 public static String getDisplayMetrics(Context cx) { 2 String str = ""; 3 DisplayMetrics dm = new DisplayMetrics(); 4 dm = cx.getApplicationContext().getResources().getDisplayMetrics(); 5 int screenWidth = dm.widthPixels; 6 int screenHeight = dm.heightPixels; 7 float density = dm.density; 8 float xdpi = dm.xdpi; 9 float ydpi = dm.ydpi; 10 str += "The absolute " + String.valueOf(screenWidth) + "pixels\n"; 11 str += "The absolute heightin:" + String.valueOf(screenHeight) 12 + "pixels\n"; 13 str += "The logical density of the display.:" + String.valueOf(density) 14 + "\n"; 15 str += "X dimension :" + String.valueOf(xdpi) + "pixels per inch\n"; 16 str += "Y dimension :" + String.valueOf(ydpi) + "pixels per inch\n"; 17 return str; 18 }
3.6 获取状态栏和标题栏的高度
1 TextView tv1; 2 @Override 3 protected void onCreate(Bundle savedInstanceState) { 4 super.onCreate(savedInstanceState); 5 setContentView(R.layout.layout_test2); 6 tv1 = (TextView) findViewById(R.id.TextView01); 7 tv1.post(new Runnable(){ 8 public void run() 9 { 10 processLayout(); 11 } 12 }); 13 } 14 private void processLayout(){ 15 Rect rect= new Rect(); 16 Window window= getWindow(); 17 tv1.getWindowVisibleDisplayFrame(rect); 18 //状态栏高度 19 int statusBarHeight= rect.top; 20 int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop(); 21 //标题栏高度 22 int titleBarHeight= contentViewTop - statusBarHeight; 23 //测试结果:ok之后 100多 ms 才运行了 24 Log.v("test", "=-init-= statusBarHeight="+statusBarHeight+ 25 " contentViewTop="+contentViewTop+ 26 " titleBarHeight="+titleBarHeight); 27 }
4.总结
也算是费了一些功夫,总算是把First Task完成得差不多了,毕业一年以来都是在做WinCE驱动,虽然在大学里面学过一点Linux的知识,但是初次转到Android还是有点不适应,好在有网络这个好东西,Android学习才不是那么难,但是感觉也不能太依靠网络。从长期来看,在消费电子这一块,智能系统的进化将会越来越快,这对我等的考验会越来越大。但是当今世界就是一个不断学习的世界,今后要多把自己的学习总结出来,这样进步才会更快。
转自:铸道的汉子