位置:platform/packages/apps/Contacts
位置:platform/packages/apps/ContactsCommon
1、观察者模式
com.android.contacts.ContactSaveService 事件源类集中处理联系人、用户组的增删改,处理这些数据Activity注册ContactSaveService.RegisterListener监听,当调用数据处理方法完毕后通知各自的监听器。
//定义接口 public interface Listener { //触发事件后通知方法 public void onServiceCompleted(Intent callbackIntent); } //监听器列表 private static final CopyOnWriteArrayList<Listener> sListeners = new CopyOnWriteArrayList<Listener>(); //注册监听 public static void registerListener(Listener listener) { if (!(listener instanceof Activity)) { throw new ClassCastException("Only activities can be registered to" + " receive callback from " + ContactSaveService.class.getName()); } sListeners.add(0, listener); } //解除监听 public static void unregisterListener(Listener listener) { sListeners.remove(listener); } ...... void deliverCallbackOnUiThread(final Intent callbackIntent) { for (Listener listener : sListeners) { if (callbackIntent.
根据AOSP的编译信息,12月5号Android4.4.1_r1已通过测试平台被发布出来。
Android4.4.1_r1的最新代码为KOT49E。
11月底,Nexus系列的设备包括Nexus4、Nexus7、Nexus10均已获得Android 4.4的OTA更新。但是很多网友随后发现,Nexus 4、Nexus7更新至4.4后并没有出现透明可隐藏的状态栏、导航栏(虚拟按键),通过ROM提取发现,Google没有将更新设备的Launcher切换到Android4.4后才发布的Launcher3而是继续使用原有Launcher2,仅将原厂ROM的Nexus5切换到了Launcher。不知道Google会不会在4.4.1更新中正式安装Launcher3.
小道消息称,Google Play版的HTC One将直接从Android 4.3升级至4.4.1,目前尚未得到Google或者HTC的官方确认。
其他手机制造商的Android 4.4可升级设备信息:
三星:
Samsung Galaxy S4 Active Samsung Galaxy S4 Zoom Samsung Galaxy S4 Mini Samsung Galaxy S4 Samsung Galaxy S3 Samsung Galaxy Note 3 Samsung Galaxy Note 2 Samsung Galaxy Tab 3 Samsung Galaxy Tab 2 Samsung Galaxy Mega (目前还不确定) HTC:
HTC J HTC Butterfly HTC Droid DNA HTC One X+ HTC One X HTC One HTC Desire系列 (2013年发布的设备) 索尼:
Android 4.4对UI的一大调整就是沉浸式设计,所谓沉浸式设计就是状态栏、虚拟按键可以动态隐藏,这使得开发者可以100%的使用屏幕,以Nexus 4为例,之前的竖屏可用空间为1084x768(顶部状态栏高度64px,底部虚拟按键132px)。这其中的好处也不止一点,在玩全屏游戏时一直受人诟病的虚拟按键问题通过这一设计也得到了解决。
最近几天Google自家的应用都开始陆续更新加入了这一设计,Google Play Book是最先更新使用这一设计风格的App。
图1-全屏幕的空间使用
图2-全屏后点击阅读区恢复状态栏、虚拟按键
Google Play Book在进入阅读界面是图2,当用户点击阅读区域,触发沉浸模式,与此同时ActionBar、SplitContentBar隐藏,完全实现全屏阅读。
但是在使用换另外一种情况,这一设计就显得有点捉襟见肘。与Google Play Book类似但在用户点击阅读区域时不隐藏ActionBar,但继续调用SystemUIVisiblablity()隐藏状态栏,在这个过程中界面会出现一个中间状态,如图。
此时顶部状态栏会被移除,但是ActionBar可能由于重新绘制的原因会有延迟,导致上部显示出Content Layout的背景颜色,影响UI效果。
所以如果App使用了ActionBar,要隐藏状态栏的同时也要隐藏ActionBar,这样才不会出现上述的UI惨状。
谷歌针对2013年10月28号之前购买谷歌眼镜的用户提供以旧换新。
详细信息:
新版本都有哪些改变?
外观一样,质感一样,但还是有稍许的改进,比如速度更快、更加耐用,同时兼容即将发布的眼镜框。镜片、耳塞都已经是为新版眼镜设计的了,这些马上就会发布。
哪些人有资格以旧换新?
每一位在2013年10月28号之前购买体验版的用户都有资格。按照我们的贸易条款,眼镜只能被寄送到美国的地址。包括之前已经返还眼镜的体验用户也可以重新加入。关于重新加入体验,请联系我们。
以旧换新计划需要等多久?
一旦计划开始执行,我们将会陆续给每一位用户发送邮件。在你收到邮件的60之内(截止到2014年1月5号)注册这个计划。在你收到回收盒的两周内,请将原眼镜尽快寄递给我们。
我可以换颜色吗?
可以,你有一次机会来更换其他颜色的眼镜。
什么时候能收到回收盒?
首先请确保你已经通过邮件的链接注册了这个计划,这个非常关键。当你想要的新版眼镜可以出货时,我们会通知你并且寄递给你一个放置老版眼镜的盒子。
以旧换新后保修时间会重新计算吗?
是的,新版眼镜会有一个1年的保修期。
如果我不想以旧换新,可以额外购买吗?
这是一个自愿的计划。你可以保留老版眼镜直到保修期结束。如果你想额外购买新版眼镜,请联系我们。
我已经换过一副眼镜了,能够参加以旧换新?
可以,如果你的设备是在2013年12月2号之前寄出的就可以以旧换新。
我的老版眼镜怎么处理?
虽然它已陪伴你许久,但还是比较遗憾的告诉你,我们必须在老版眼镜收悉的情况才会发送新版眼镜。
邮件截图:
原文链接:https://support.google.com/glass/answer/3501111
位置:packages/apps/Launcher2
1、图片数组定义、资源读取
如果有多张图片,这些图片的使用与顺序无关,可以采取这种方式。
drawable-nodpi中有3张图片,wallpaper_1.jpg、wallpaper_2.jpg、wallpaper_3.jpg
XML中定义数组ID
<string-array> <item>wallpaper_1</item> <item>wallpaper_2</item> <item>wallpaper_3</item> </string-array> Java代码获取图片资源ID
final Resources resources = context.getResources(); final String packageName = resources.getResourcePackageName(R.array.wallpaper); String[] wallPaperNames = resources.getStringArray(R.array.wallpaper); for(String wallPaperName : wallPaperNames){ //图片资源ID int res = resources.getIdentifier(wallPaperName, "drawable", packageName); } 注:context.getPackageName会返回original-package,resources.getPackageName会返回真正的包路径。
在mainfest文件中,activity标签有一个属性launchMode,它确定了当前Activity在Task栈中的运行模式,共分为四种模式:
standard 如果在Activity标签中没有指明运行模式的话,系统会默认采用此种方式运行。
系统按照Intent的定义创建新的Activity实例并置入Task栈中。这个Activity可以被实例化多次,每一个实例可以放入不同的Task栈,同一个Task栈也可以包含多个Activity实例。
singleTop 如果在当前Task栈的栈顶已经包含了这个Activity的实例,系统会将Intent信息通过onNewIntent()方法传入当前已经实例化的Activity中,而不是创建一个新的Activity实例。这个Activity可以被实例化多次,每一个实例也可以放入不同的Task栈,同一个Task栈也可以包含多个实例 (这必须满足一个条件,在Task栈的栈顶不存在一个Activity实例)。
举个例子,假设一个Task栈中包含根Activity A、Activity B、C以及位于栈顶的Activity D(在栈中自下而上的顺序为A-B-C-D; D在栈顶)。
1)此时一个Intent目标指向D,
如果Activity D的运行模式设置为”standard”,一个新的Activity D的实例会被创建出来,现在的栈就会变成A-B-C-D-D;
如果 Activity D的运行模式设置为“singleTop”,由于Activity D已经位于栈顶,被实例化的Activity D就会通过onNewIntent()方法接收Intent的信息而不是创建新的实例化,现在的栈还是原来的状态A-B-C-D。
2)此时一个Intent目标指向Activity B,一个实例化的Activity B就会被创建并置入栈顶,即便是它的运行模式被设置为“singleTop”。
注意:当一个Activity的实例被创建时,用户可以通过按下返回键返回到前一个Activity。如果已经被实例化的Activity接收新的Intent,用户再按下返回键是不会回到调用onNewIntent()方法之前的状态的。
singleTask 系统会创建一个新的Task并将实例化的Activity置入栈顶。如果在其他Task中已经存在这个Activity实例,系统不会创建新的Activity实例,而是将Intent信息通过onNewIntent()方法传入存在的Activity实例中,这种情况可以保证Activity只存在一个实例。
注意:由于Activity是在一个新的Task栈中启动,所以用户按下返回键依然可以返回到前一个Activity中。
singleInstance 与“singleTask”类似,唯一的区别就是在当前运行这个Activity实例的Task中不会再压入任何其他的Activity实例,它是这个Task中仅有的也是唯一的成员。其他Activity的实例化都会触发新Task的创建。
每一个Android应用都由多个activities组成,每一个Activity可以执行特定的action也可以打开其他的activity。举例说明,一个Email应用会有一个Activity来显示未读邮件列表,当用户点击其中一封邮件时,一个用来显示这封邮件内容的Activity就会被创建出来。
Activity甚至可以启动本机上其他应用的Activity。比如说,当你的应用要发送邮件时,你可以定义一个包含邮件地址征文等信息和发送消息action的Intent。与此同时另外一个应用的Activity被声明为可以执行这个Intent然后打开它。在这个过程中,Intent被定义为发送邮件,所以一个Email应用会启动并创建“写邮件”Activity,(当然,如果系统中包含多个可以支持此Intent的Activity,系统会弹出一个列表来供你选择)。当Email被发送出去后,启动这个Intent目标的Activity会被恢复,这就好像是发送Email的Activity是应用自身的一部分一样。通过将两个来自于不同的应用Activity放入同一个Task,Android完美实现了用户操作的无缝衔接。
回到主题,Task是为了完成用户某项任务的Activity集合。在这个集合中,Activity按照被打开的先后顺序存放在栈中。
设备主屏是大多数Task的起点。当用户点击启动器上的App图标或者App快捷方式图标时,这个应用的Task会被加载到前台。如果最近这个应用没有被启动,新的Task会被创建并将声明为”main”的Activity作为根Activity打开,添加到栈中。
如果此时Activity A去启动Activity B,Activity B会被压入栈顶并获得焦点。Activity A依然保持在栈中,但是已被中止(当一个Activity被中止时,系统只保留了当前UI的状态数据),当用户按下返回键时,Activity B会从栈顶推出(彻底被销毁),Activity A会被恢复(之前的UI状态资源会被还原),栈中Activity排序顺序是始终不变的,当Activity启动时被压入,用户按下返回键时被推出。这一操作遵循“后进先出”的原则。下图展示了每次操作时栈的状态。
如果用户一直按返回键的话,每一个Activity都会被推出栈直到返回到设备主屏。当所有Activity被从栈中移除时,Task也就随之消失了。
当用户开启一个新的Task或者是直接回到主屏,当前的Task就会被置入后台。Task中的所有Activity都被中止,但栈依然有效,只不过是焦点被其他Task把持着罢了。如下图所示。
用户从离开Task的位置返回时,后台的Task会被置前。举例说明,Task A中包含三个Activity(按照Task 栈的定义,当前运行的Activity位于栈顶,其他两个Activity位于当前Activity下面),假设用户此时回到主屏并从启动器中启动另外一个应用,主屏出现之后Task A就会被置入后台,新的应用启动后Android会为这个应用创建新的Task B来放置属于它的Activity,用户操作完Task B应用后再次切回主屏,选择启动Task A应用时Task A就会回到前台,在栈中的三个Activity会如前所述,栈顶的Activity被恢复,其他两个Activity仅保留状态资源置于顶部Activity下面。当然了,用户此时也可以通过回到主屏或者是点击“最近使用的应用”来切换到Task B。
注意:在Android系统可以同时存留多个后台任务,但是如果系统如果需要回收内存时就可能会销毁掉栈中的Activity,这就会导致Activity状态的丢失。详见 Activity state.
由于栈中的Activity从来不会被重新排列,你的应用如果允许从多个Activity中去启动某一特定Activity,特定的Activity在每一次启动时都会被实例化压入栈中而不是将之前已经实例化的Activity置入栈顶。这样的话,每一个实例化的Activity都拥有独立的UI状态资源,当用户按下返回键时按照栈中Activity顺序依次被推出。当然你也可以修改这些Activity的属性来满足你仅有一个特定Activity实例存在的要求。详见 Managing Tasks.
小结:
从Activity A启动Activity B,Activity A会被中止,但系统会保留它的UI状态资源(比如滚动位置、表单数据),如果用户在Activity B状态时按下返回键,Activity A就会被恢复到原始状态。 当用户从当前应用按下Home键时,当前Activity被中止,所属的Task被置入后台。系统会保留Task中所有Activity的状态资源. 用户再点击开始当前Task的应用图标时,Task会被前置并且恢复栈顶的Activity。 如果用户按下返回键,当前的Activity会被从栈中推出销毁,栈中下一Activity会被恢复。一个Activity被销毁时,系统就不会再保留它的状态资源。 Activitiy可以被实例化多次,当然在不同的Task中也是适用的。 原文
位置:platform/packages/apps/Bluetooth
位置:platform/packages/apps/Calendar
1、Bluetooth Profile
不同类型的蓝牙设备的通信依赖于各自Profile的定义。
Profile是在蓝牙通讯连接管理层之上为不同类型设备之间通讯而定义的一套描述规范。在Bluetooth 4.0之前主要有A2DP(Advanced Audio Distribution Profile)、HDP(Health Device Profile)、HFP(Hand-Free Profile)、HID(Human Interface Device Pro)、OPP(Object Push Profile)、PAN(Person Area Networking)、PBAP(Phone Book Access Profile),android原生系统的Bluetooth管理器均实现了上述Profile,在Bluetooth 4.0之后推出了一套新的Profile-GATT,它为低功耗的蓝牙设备而设计,能够兼容健身医疗、定位通知、时钟认证等蓝牙设备。
关于GATT、蓝牙传输协议工作机制、Bluetooth Profile的更多信息你参见Buletooth World 2013 大会资料
BW13_DayOne_Session2_NewEnhancProfiles
San Jose - AM3 - Bluetooth Technology Overview - Part1
2、Activity运行模式
参见Android Activity 运行模式
位置:platform/packages/apps/Calculator
1、TypeArray、AttributeSet
在XML布局中定义的每个组件定义以及属性值会在布局加载时读取出来通过Xml.asAttributeSet()转换为AttributeSet传递给UI组件的构造方法。
通过全局Resources来读取XML数据资源定义,根据传入资源ID来获取部分资源描述赋值给TypeArray。TypeArray类型的变量使用完毕后必须手动调用recycle()方法释放资源。
位置:platform/packages/apps/AlarmClock
1、同一应用中Toast调用多次,Toast消息叠加:
定义静态Toast对象,在新的Toast生成时关闭之前所有的Toast视图资源(包括正在显示的以及已加载但还在队列中没有显示的)。
public class ToastMaster { private static Toast sToast = null; private ToastMaster() { } public static void setToast(Toast toast) { if (sToast != null) sToast.cancel(); sToast = toast; } public static void cancelToast() { if (sToast != null) sToast.cancel(); sToast = null; } } 2、广播消息的接收注册
//广播消息过滤 IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); //注册广播监听以及Handler处理函数 mContext.registerReceiver(mIntentReceiver, filter, null, mHandler); 3、Content Provider
它主要用于App间的数据交换。
ContentValues是Content Provider的数据载体,它是对HashMap的一层封装,仅支持Byte、Short、Integer、Long、Float、Double、Boolean、Byte数组。