MTK F&Q

adb shell getopt中的option是如何生成和使用的
1. 系统初始化时init调用 property_service.c 中的start_property_service,该接口从/default.prop, /system/default.prop, /system/build.prop等文件中获取property,并存入到内容中。Java层代码通过 system.getproperty()通过JNI层获取这些property。
2. start_property_service()-》property_patch() 还会动态生成ro.sf.lcd_density 这个属性,该接口从驱动接口中获取设备的density。
3. 可以用adb shell登录到手机,然后用getprop, setprop 命令查看和修改这些property
4. 编译脚本中PRODUCT_PROPERTY_OVERRIDES (在common.mk中常见)这个宏用来定制property
5. build.prop 是如何生成的?
    Build/core/Makefile  将mediatek/sysytem.prop 还有product_property_overrides中的属性写到build.prop文件中。
    还会调用mtk_buildinfo.pl文件 生成一些额外的property属性,比如ro.build.XXX.version.release 等


APP及framework替换资源(asset)的方法
1. 编译脚本common.mk中有PRODUCT_PACKAGE_OVERLAYS 宏,可以用来控制资源的替换。
2. 在a20.mk中增加了 PRODUCT_PACKAGE_OVERLAYS := vendor/XXX/resource/$(TARGET_XXX_PRODUCT), 表示可以将资源放到vendor/XXX/resource/a20/模块对应的目录中,在new/remake编译时,系统会自动替换资源。(参考vendor/XXX/resources/a20/XXX/source/package/目录下的几个目录)
   更简单的编译方法是:删除out/target/common/obj/APP/目录下该apk对应的临时文件夹,然后单独编译该apk即可。
3. 资源文件通常是res目录下的文件,可以是 png图片文件,也可以是xml配置文件等。


APP图标资源
1. APP图标资源由androidManiest.xml中的带有action为MAIN, category为LAUNCHER(在launcher中显示)的activity中的ICON属性来指定;
2. manifest文件的ICON属性有传递效应,比如application中指定的ICON,如果activity中没有制定ICON,则该activity默认的ICON为application中制定的ICON
3. phone, calllog, contacts 的图标资源都在Contacts目录下,具体参考contacts的AndroidManifest.xml文件


增加修改系统墙纸
1. 和墙纸相关的几个部分有wallpaperchooser, wallpaperservice,wallpapermanager,wallpapermanagerservice.
2.  Wallpaperchooser: 在luancher中选择/设置墙纸 时使用,主要是一个gallery,从launcher的资源中读取系统墙纸,并显示出来;
3.  Wallpaperservice:负责墙纸的decode? 还需要深入了解。
4.  wallpapermanager:提供接口给wallpaperchooser使用,基本上是对wallpapermanagerservice接口的封装;
                                      还提供一个获取系统默认墙纸的接口,从com.android.internel中获取系统默认的墙纸资源,
                                      所以如果要修改系统默认的墙纸,可以修改frame/base/core/res/res目录下的default_wallpaper 这个文件
5.  Wallpapermanagerservice: 提供设置墙纸,获取墙纸等底层接口
     设置墙纸的具体工作是由wallpapermanagerservice来完成,主要是打开一个文件,并将墙纸的数据写入该文件中。


CTA 需求:充电保护
1. 和充电相关的service有batteryservice, batterywarningservice,后者是MTK增加的service用以动态检测充电的状态(如充电电压过高,电流过大等)
2. batterywarningservice是InitBatteryObserverServiceReceiver 其中启动后的,
    后者是个receiver,监听BOOTCOMPLETE事件,事件到后启动warningservice
3. warningservice 有一个timer,每隔5s(CTA版本修改成3s)会检测电池充电状态,
   如果出现异常,会通过broadcastintent发intent,warningservice自身会监听这些intent,并提示dialog。


CTA PR:STK显示双卡
1. projectconfig.mk里面设定编译的是MTK的stk app,不是默认的stk app(GEMINI的和宏打开)
2. MTK的stk app分成3个部分: stkselection, stk1, stk2 
    stkselection:显示在lauancher当中,用于选择进入哪张卡的STK功能,会自动识别插入有几张卡,并进入相应卡的STK功能,
                           如果两张卡都插着,则会显示一个preference ui,让用户选择要进入哪张卡。
    stk1,stk2: 具体的stk功能,由stkservice和stkapp 两个部分,还有一个bootcompletereceiver,在系统启动后就会启动stkservice
                          stkservice动态检测卡的状态,并会动态enable/disable stk的activity
                        (通过packagemanager的接口动态enable/disable 某个component的功能需要掌握)




CTA PR:Data分区满,不能清除数据
1. DeviceStorageMonitorService 在activitymanager service启动后会启动,它负责检测系统内存空间的改变,当空间到有一定界限时发intent出来
2. storagemonitorservice每隔60*1000ms 会检测一下/data目录,/system目录,
    当/data 目录空间小于总空间的10%时,开始上报LOW_MEMORY_NOTIFICATION_ID 给notifictionmanagerservice,后者会在状态栏上显示一个图标
3. 并且发一个pendingintent: ACTION_MANAGE_PACKAGE_STORAGE, 当用户点击该notification时,将会启动manageapplication,要求用户卸载APP或者清除数据




平台PR:Alarm 静音但还是播放T卡中的歌曲
1. alarm相关的app代码主要在package/app/deskclock目录下,。
App层代码的主要功能是:
  a. 设置alarm(setalarm),设置的alarm保存在alarmprovider中,并调用alarmmanager的接口设置到alarmmanagerservice中。
  b. 响应alarm(alarmreceiver),alarmreceiver接收alarmmanagerservice 发送的broadcast intent(ALARM_ACTION), 并启动notification,且显示alarmalert界面
     并启动alarmklaxon service 调用media开始播放该alarm对应的铃音。注:alarmklaxon会判断alarm是否为slient,如果不是slient才会播放铃音。
  c. 在闹铃界面,如果用户选择cancel,则alarmalert会停止alarmklaxon service,后者调用media接口停止播放。
2.  framework里面还有一个alarmmanagerservice, 其中的接口在alarmmanager中封装可以直接调用.
Framework层的主要作用:
  a. 保存上层APP 设置的alarm,放到一个队列中。
  b. servie启动时调用scheduleTimeTickEvent接口-》调用native的set接口,向驱动设置一个1分钟的alarm,并启动一个AlarmThread,调用native的waitForAlarm
      等待驱动的alarm事件发生。当事件发生时,waitForAlarm接口返回,在AlarmThread中轮循队列中的alarm,如果匹配则将alarm带的broadcastintent发送出去。
  c. scheduleTimeTickEvent接口中设置的broadcastintent是ACTION_TIME_TICK,ClockReceiver接收到该intent后,再次调用scheduleTimeTickEvent接口再次设置
     1分钟的alarm。 也就是说,alarmmanagerservice是利用这个1分钟的alarm来实现了生层APP设置的alarm的轮循。


平台PR:Bluetooth opp当本地SD卡空间不足时提示错误
这里介绍 bluetooth opp server/client的工作机制。
1. android2.3 原生的bluetooth功能比较少,实现的profile有opp,hsp,hfp,a2dp。主要代码在package/apps/bluetooth目录下。
2. mtk重新实现了bluetooth,增加了很多profile,有opp,ftp, hid, pap,pan,sim access, sip, bpp等,基本上包括了常见的profile,代码在mediatk/source/package/bluetooth 目录下。
Mediatk/source/package/bluetooth 下的代码是profile的java实现,和bttask,bt chip的交互(包括native的service,jni代码都看不到)
从init.rc 文件中可以发现和bluetooth相关的native service主要有mtkbt 这个进程。而jni部分则每个profile都有一个libext*jni.so文件(比如针对opp的libextopp_jni.so 文件)
3. 每个profile都有一个sevice, 当通过bluetoothsetting enable bt(调用bluetooth apdater接口,adpater其实是bluetoothservice的一个封装,bluetooth service在systemserver中启动)后,系统会发一个ACTION_BLUETOOTH_STATE_CHANGED事件,bluetoothreceiver.java监听到这一事件后,调用startservice接口启动各profile的service
4. opp profile的service的代码主要在oppservice,oppmanager,oppservicenative中。
Oppservicenative 主要是对jni接口的封装,oncreate接口中会调用jni的接口启动opp server的sdp 服务,并创建一个MessageListener 线程接收jni上报的远程opp消息(比如push request, push data等). Jni 通过jniCallback 上报消息,该接口会把jni层的event 放到消息队列(queue)。
5. oppservice中主要实现了oppstaskthread,oppctaskthread。
   Oppstaskthread 的beforewait接口从oppservicenative的消息队列中取event, 并根据event的type(push request等)调用oppmanager的接口处理,比如弹出confirmation ui等。在等待用户的确认消息时,oppstaskthread进入wait状态,等待确认消息。(在进入等待前,会把jni上来的event封装成opptask放入数据库)
6. 当用户确认后,oppmanager发送ACTION_OPPS_START 消息给oppservice,后者发消息给oppstaskthread,让其退出wait状态,调用afterwait()接口开始从数据库中读出opptask,根据event type进行处理。


 拨号盘特殊号码
1. 特殊号码是如何处理的?
1).SpecialCharSequanceMgr.java -》handleChars()专门处理拨号盘的特殊号码
  特殊号码包括 *#*#3646633#*#* (进工程模式),*#8375*(查看版本号), *#837575* (查看svn号)等。
2).  handleChars()-》handleSecretCode(),判断是否begin with *#*# 且endwith #*#*, 如果是则表示是secret code,将发送SECRET_CODE_ACTION broadcast
3). TestingSettingsBroadcastReceiver()会监听SECRET_CODE_ACTION 消息,如果是3646633,则启动工程模式 activity;
2. 版本号和svn号等信息是从哪里获取的?
    Twelvekeydialer.java中收到sepcialcharsequencse.java发过来的消息后,产生相应的dialog,并显示版本号,svn号等信息。
      Svn号是通过build.java文件从ro.build.version.incremental 这个属性中获取,
      版本号是通过build.java文件从ro.build.XXX.version.release 这个属性中获取
     这些属性都在/system/build.prop 文件中。
3. 版本号和svn号是如何编到build.prop文件中的?
    Build/core/version_defaults.mk 文件中利用脚本生成SVN_ID,BUILD_NUMBER等信息
    Build/core/Makefile 中调用build/tools/buildinfo.sh脚本将属性都写到out/target/product/XXX73_gb/system/build.prop 文件中,
        Buildinfo.sh 内容举例:echo "ro.build.version.incremental=$BUILD_NUMBER"
    Build/core/Makefile中还会调用mtk_buildinfo.pl 脚本,将mtk的一些属性写到build.prop文件中,
        mtk_buildinfo.pl 内容距离:print "ro.build.XXX.version.release=$XXX_PROJECT_VERSION\n"; 


触屏声音/POWER键声音的播放
1. setting中可以打开触屏声音和POWER键声音
    setting-》情景模式-》声音设置-》反馈,将“操作音选择”,“屏幕锁定提示音” 勾上。
2. 触屏声音的播放:
   在listview.java, gridview.java, ExpandableListView.java->handleItemClick() 都会调用playSoundEffect(SoundEffectConstants.CLICK)接口;
   playsoundEffect()在view.java中实现--》调用viewroot.java中的playsoundEffect()-》调用audiomanager.java中的playSoundEffect();
   Audiomanager.java->playSoundEffect():
     a. Settings.System.getInt(Settings.System.SOUND_EFFECTS_ENABLED)判断触屏声音是否打开,如果打开则
     b. 调用audioservice的playSoundEffect(effect)接口播放声音。effect是固定值,主要有FX_KEY_CLICK,FX_FOCUS_NAVIGATION_UP,FX_FOCUS_NAVIGATION_DOWN等值
   
3.POWER键声音的播放:
   POWER键按下后,屏幕会关闭,keyguardviewmediator.java → onScreenTurnedOff() 接口会被调用,该接口判断屏幕关闭的原因,如OFF_BECAUSE_OF_USER,OFF_BECAUSE_OF_TIMEOUT等。
  OnScreenTurnedOff()->dokeyguard()->showLocked()->handleShow() -》 playSounds() ;
  PlaySounds() 调用Settings.System.getInt (Settings.System.LOCKSCREEN_SOUNDS_ENABLED)判断锁屏声音是否打开,如果打开则
    调用Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); 其中的sounduri为:/system/media/audio/ui/Lock.ogg (Unlock.ogg)
          sfx.setStreamType(AudioManager.STREAM_SYSTEM);
          Sfx.play();
  


MP3/FM 和来电/闹钟的冲突处理
1. MP3 和来电的冲突处理(requestfocus,focuschangelistener机制):MP3播放时来电,MP3暂停,电话结束后,MP3恢复
   Mediaplaybackservice.java中的play()接口调用mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
                AudioManager.AUDIOFOCUS_GAIN);,注册focuschangelistener()回调函数;
   Audioservice.java中的oncreate()接口中注册了phonestatelistener(),当来电时会调用requestAudioFocus(AudioManager.STREAM_RING,
                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
                        null, null /* both allowed to be null only for this clientId */,
                        IN_VOICE_COMM_FOCUS_ID /*clientId*/);
  这会导致mediaplaybackservice注册的requestchangelistener被调用:        mMediaplayerHandler.sendMessageDelayed(mMediaplayerHandler.obtainMessage(FOCUSCHANGE, focusChange, 0), delay); (如果是FOCUS_GAIN, delay 1800ms)
  mMediaplayerHandler的handlemessage()处理FOCUSCHANGE事件,并调用pause/resume接口暂停和回复播放
2. MP3和闹钟的冲突处理:MP3播放时来闹钟,MP3的声音和闹钟的声音同时发声
    MP3没有处理alarm事件,MP3的声音和闹钟的声音同时发声
3. Fm和来电的冲突处理(phonetstatelistener机制):FM播放时来电,FM暂停,电话结束后,FM恢复
    Fmradioservice.java的onCreate()接口中注册了phonestatelistener():
    来电时调用powerdown(),停止FM播放,该接口还会调用enableFMAudio(false)-》mp.stop() 停止fm的声音通路;
     来电结束后调用powerup(),回复FM播放,该接口会调用enableFMAudio(true) → mp.start() 回复FM的声音通路;
4. Fm和闹钟的冲突处理:FM播放时来闹钟,FM停止,闹钟取消/停止后,FM恢复播放(如何实现的?)
5. 闹钟和来电的冲突处理(phonestatelistner机制):闹钟响应时来电,闹钟停止响铃,并且不再恢复
    闹钟播放时在alarmklaxon.java的oncreate()接口中注册了phonestatelistener():
    当来电时,会发送Alarms.ALARM_KILLED broadcast,alarmalertfullscreen.java(闹铃界面)会监听该消息,当收到该消息时调用dismiss()-》stopService(new Intent(Alarms.ALARM_ALERT_ACTION) 将alarmklaxon service停止,在alarmklaxon.java的ondestroy()接口中会调用mp->stop()接口停止铃音的播放;


MP3,FM,Camera,videoplay应用间的冲突
1. MP3和FM的冲突处理(MP3播放时,点击FM的play按钮,MP3暂停,FM开始播放;FM播放时,点击MP3的play按钮,FM暂停,MP3开始播放)
    Mediaplaybackservice.java的play()接口:
       Intent i = new Intent("com.mediatek.FMRadio.FMRadioService.ACTION_TOFMSERVICE_POWERDOWN");
       SendBroadcast(i);
    Fmradioservice.java onReceive()接口监听该消息,收到后停止FM的播放;




   Fmradioservice.java的powerup()接口:
    Intent it_music = new Intent("com.android.music.musicservicecommand.pause");
    sendBroadcast(it_music);
   Mediaplaybackserver.java onreceive()接口监听该消息,收到后暂停MP3的播放;


开关机动画开关机铃音Boot logo/kernel logo
1).init.rc 在启动时会启动system bootanim /system/bin/bootanimation, bootanimation代码在framework/base/cmds/bootanimation目录下:
   bootanimation_main.cpp, bootanimation.cpp 
2).bootanimation.cpp -》readytorun() 打开/system/media/bootanimation.zip文件,并调用android()接口开始播放动画(bootanimation.zip文件由desc.txt和folder1,folder2组成)
    Bootanimation.cpp->thredloop() 打开/system/media/bootaudio.mp3文件,调用mediaplay接口开始播放声音




2. 从资源编译角度看:
1). 各项目的开关机动画和铃音 都在mediatk/custom/***/system/bootani/目录下,该目录下有:
    Bootanimation (用命令zip -r -X -Z store ../bootanimation part*/*.png desc.txt 生成bootanimation.zip 文件)
    Bootaudio
    Shutdownanimation
    Shutdownaudio
    Shutdownrotate
    分别用来定制生成开机动画,开机声音,关机动画,关机声音,关机旋转(不确定其用途)。每个目录下都有Android.mk 文件
2). Android.mk文件中 会根据当前的项目名PROJECT 来决定要编译的资源文件,(开机动画:bootanimation.zip,  开机声音:bootaudio.zip 等都放在image的/system/media目录下)
   LOCAL_MODULE := bootanimation.zip
   LOCAL_MODULE_TAGS := user
   LOCAL_MODULE_CLASS := media
   LOCAL_MODULE_PATH := $(TARGET_OUT)/media
   LOCAL_SRC_FILES := $(LOCAL_MODULE)




Boot logo:
1. 开机显示的顺序如下:
    boot logo(开机显示的第1张图片)  (logo.bin 中)
    Kernel logo(开机显示的第2张图片) (system/media/images/boot_logo 文件)
    Boot animation(开机动画)             (system/media/bootanimation.zip 文件)
2. boot logo和kernel log所用的图片资源在 mediatek/custom/common/uboot/logo 目录下,在ProjectConfig.mk中指定具体目录,比如BOOT_LOGO=wvga_XXX,
    表示用wvga_XXX目录下的资源,该目录下的资源都是bmp文件。在logo/update 文件中会调用tool/bmp_to_raw将bmp文件转换成raw文件。
    并且在make uboot时会将这些资源文件放到logo.bin 中。 Logo/update 针对wvga_XXX_kernel.bmp有特殊处理,将其转成raw文件并命名为/logo/boot_logo
    在mediatek/source/external/boot_logo_upater/Android.mk中会将boot_logo 文件放到out/target/product/system/media/images/boot_logo. 这样就放到了system.img中.
3. boot logo的显示: boot.img中加载logo.img中的boot 图片显示;
    Kernel logo的显示: init.rc 启动 service bootlogoupdater /system/bin/boot_logo_updater 
                                  boot_logo_updater这个可执行程序由boot_logo_updater.c 编译而成,其功能是从/system/media/images/boot_logo 中读出kernel_boot资源并通过framebuffer直接显示到LCD上。
    注:可以根据logo/update中的脚本单独生成boot_logo文件,然后用adb remount/adb push的方法直接放到手机里面观察效果。


如何开发静态库给其他APK使用
1.将代码编译生成静态库
1)Android.mk文件 (以utils为例)




LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:= com.***.utils
include $(BUILD_JAVA_LIBRARY) #编译生成java library(jar文件,放在out/target/product/***/system/framework目录下)




2)添加用户注册库的xml文件com.***.utils.xml
该文件放在utils的目录下,其内容如下:
<?xml version="1.0" encoding="utf-8"?>
<permissions>
    <library name="com.XXX.utils"
        file="/system/framework/com.XXX.utils.jar" />
</permissions>




修改Android.mk,将com.XXX.utils.xml编进img:
include $(CLEAR_VARS)
LOCAL_MODULE := com.XXX.utils.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions #放在out/target/produt/XXX73_gb/system/etc/permissions目录下)
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT) #prebuilt
2.其他APK中如何使用生成的静态库文件(jar文件)
1)修改APP的Android.mk文件需要添加如下语句:
LOCAL_JAVA_LABRARIES += com.XXX.utils
2)修改APP的AndroidMinifest.xml文件
<uses-library android:name=”com.XXX.utils”/>
3)Jar库中的类的调用
如果在库中有一个类为CallerLocation,则调用此类的代码中就可以通过com.XXX.utils.CallerLocaiton调用该类的public成员变量和成员函数。


调整默认系统语言
默认语言的选择实现是在build/core/Makefile里,从PRODUCT_LOCALES里选择第一个语言作为默认语言
define default-locale
$(subst _, , $(firstword $(1)))
endef
# Selects the first locale in the list given as the argument
# and returns the language (or the region)


define default-locale-language
$(word 2, 2, $(call default-locale, $(1)))
endef




define default-locale-region
$(word 3, 3, $(call default-locale, $(1)))
Endef




PRODUCT_DEFAULT_LANGUAGE="$(call default-locale-language,$(PRODUCT_LOCALES))" \
PRODUCT_DEFAULT_REGION="$(call default-locale-region,$(PRODUCT_LOCALES))" \


然后通过build/tool/buildinfo.sh文件将如下段写到文件build.prop,如下:


echo "ro.product.locale.language=$PRODUCT_DEFAULT_LANGUAGE"
echo "ro.product.locale.region=$PRODUCT_DEFAULT_REGION"


所以,要改变默认语言用下面两种 方法中的一种就行了:
1 、在PRODUCT_LOCALES字段里,将要选择的语言放在第一位,如:
PRODUCT_LOCALES := en_US zh_CN #默认语言是英语


2、在persist.sys.language 和persist.sys.country 里指定语言,如下:
PRODUCT_PROPERTY_OVERRIDES := \
persist.sys.language=zh \
persist.sys.country=CN


build.prop文件的处理是在system/core/init/property_service.c。




如何向launcher中添加快捷方式
当我们在应用程序Launcher的桌面空白处长按触摸时,会出现一个对话框,提示选择要添加的桌面组件
选择快捷方式后,会弹出一个对话框,显示出了可添加快捷方式的Activity所属的应用程序的图标和名称的列表。
当我们想把添加快捷方式的Activity添加到这一列表时,
只需要在这个Activity注册时添加一个Action为android.intent.action.CREATE_SHORTCUT的IntentFilter就可以了。


如何获取本地电话号码?
SIM卡存储的数据可分为四类:


第一类是固定存放的数据。这类数据在移动电话机被出售之前由SIM卡中心写入,包括国际移动用户识别号(IMSI)、鉴权密钥(KI)、鉴权和加密算法等等。
第二类是暂时存放的有关网络的数据。如位置区域识别码(LAI)、移动用户暂时识别码(TMSI)、禁止接入的公共电话网代码等。
第三类是相关的业务代码,如个人识别码(PIN)、解锁码(PUK)、计费费率等。
第四类是电话号码簿,是手机用户随时输入的电话号码。用户全部资料几乎都存储在SIM卡内,因此SIM卡又称为用户资料识别卡。


 IMSI是一个唯一的数字, 标识了GSM和UMTS 网络里的唯一一个用户. 它存储 在手机的SIM卡里,它会通过手机发送到网络上. IMSI 与 SIM唯一对应
IMEI也是一串唯一的数字, 标识了 GSM 和 UMTS网络里的唯一一个手机.它通常被打印在手机里电池下面的那一面,拨 *#06# 也能看到它. IMEI 与 设备唯一对应.
1。IMEI不存在于SIM卡中,它是手机本身的串号。
2。通常我们所说的手机号也不存在于SIM卡中,虽然SIM卡中有一个专门存储SIM卡本身号码的地方,但是此号码是通过手工设定的,而且是可以更改的。   SIM卡的识别通常使用IMSI号,这个对于SIM卡是唯一的。
3。使用SimGetRecordInfo之类的函数获得SIM卡的IMSI号码能否成功依赖于设备制造商是否实现了此函数,据我所知在DOPOD的机器上是可以获得,但是在联想的机器上却不行,其他机器没有。
4。获得IMEI以及IMSI可以通过RIL或者TAPI中的LINE操作的函数获得。
 
下面给出获取手机本机号码的代码:
        TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
      
        String deviceid = tm.getDeviceId();
        String tel = tm.getLine1Number();
        String  imei = tm.getSimSerialNumber();     
        String imsi = tm.getSubscriberId();




添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
注:上面的接口只能在activity的几个环境中调用:空间的onclick()接口中,activity的handler中等几个有限的activity环境中调用,不能在service/content provider中调用。




  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值