Android通知欄增加快捷開關(guān)的技術(shù)實(shí)現(xiàn)

我們通常可以在通知欄上看到“飛行模式”、“移動(dòng)數(shù)據(jù)”趟薄、“屏幕錄制”等開關(guān)按鈕,這些按鈕都屬于通知欄上的快捷開關(guān)典徊,點(diǎn)擊快捷開關(guān)可以輕易調(diào)用某種系統(tǒng)能力或打開某個(gè)應(yīng)用程序的特定頁(yè)面杭煎。那是否可以在通知欄上自定義一個(gè)快捷開關(guān)呢?答案是可以的卒落,具體是通過(guò)TileService的方案實(shí)現(xiàn)羡铲。

TileService繼承自Service,所以它也是Android的四大組件之一儡毕,不過(guò)它是一個(gè)特殊的組件也切,開發(fā)者不需要手動(dòng)開啟調(diào)用,系統(tǒng)可以自動(dòng)識(shí)別并完成調(diào)用腰湾,系統(tǒng)會(huì)通過(guò)綁定服務(wù)(bindService)的方式調(diào)用雷恃。

創(chuàng)建使用:

快捷開關(guān)是Android 7(target 24)的新能力,因此在使用該能力前必須先判斷版本大蟹逊弧(大于等于target 24)倒槐。

1、自定義一個(gè)TileService類附井。

class MyQSTileService: TileService() {
  override fun onTileAdded() {    
      super.onTileAdded()  
  }

  override fun onStartListening() {    
      super.onStartListening()  
  }

  override fun onStopListening() {    
      super.onStopListening()  
  }

  override fun onClick() {    
      super.onClick()  
  }

  override fun onTileRemoved() {    
      super.onTileRemoved()  
  }
}

TileService是通過(guò)綁定服務(wù)(bindService)的方式被調(diào)用的讨越,因此两残,綁定服務(wù)生命周期包含的四種典型的回調(diào)方法(onCreate()、onBind()把跨、onUnbind()和 onDestroy())都會(huì)被調(diào)用磕昼。但是,TileService也包含了以下特殊的生命周期回調(diào)方法:

  • onTileAdded():當(dāng)用戶從編輯欄添加快捷開關(guān)到通知欄的快速設(shè)置中會(huì)調(diào)用节猿。
  • onTileRemoved():當(dāng)用戶從通知欄的快速設(shè)置移除快捷開關(guān)時(shí)調(diào)用。
  • onClick():當(dāng)用戶點(diǎn)擊快捷開關(guān)時(shí)調(diào)用漫雕。
  • onStartListening():當(dāng)用戶打開通知欄的快速設(shè)置時(shí)調(diào)用滨嘱。當(dāng)快捷開關(guān)并沒(méi)有從編輯欄拖到設(shè)置欄中不會(huì)調(diào)用。在TileAdded添加之后會(huì)調(diào)用一次浸间。
  • onStopListening():當(dāng)用戶打開通知欄的快速設(shè)置時(shí)調(diào)用太雨。當(dāng)快捷開關(guān)并沒(méi)有從編輯欄拖到設(shè)置欄中不會(huì)調(diào)用。在TileRemoved移除之前會(huì)調(diào)用一次魁蒜。

2囊扳、在應(yīng)用程序的清單文件中聲明TileService

<service
     android:name=".MyQSTileService"
     android:label="@string/my_default_tile_label"  
     android:icon="@drawable/my_default_icon_label"
     android:exported="true"
     android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
     <intent-filter>
         <action android:name="android.service.quicksettings.action.QS_TILE" />
     </intent-filter>
 </service>
  • name:自定義的TileService的類名兜看。
  • label:快捷開關(guān)在通知欄上顯示的名稱锥咸。
  • icon:快捷開關(guān)在通知欄上顯示的圖標(biāo)。
  • exported:該服務(wù)能否被外部應(yīng)用調(diào)用细移。該屬性必須為true搏予。如果為false,那么快捷開關(guān)的功能將失效弧轧,原因是exported="false"時(shí)雪侥,TileService將不支持外部應(yīng)用調(diào)起,手機(jī)系統(tǒng)自然不能再和該快捷開關(guān)交互精绎。必須配置速缨。
  • permission:需要給service配置的權(quán)限,BIND_QUICK_SETTINGS_TILE即允許應(yīng)用程序綁定到第三方快速設(shè)置代乃。必須配置旬牲。
  • intent-filter:意圖過(guò)濾器,只有匹配內(nèi)部的action搁吓,才能調(diào)起該service引谜。必須配置员咽。

監(jiān)聽模式

TileService的監(jiān)聽模式(或理解為啟動(dòng)模式)有兩種滑频,一種是主動(dòng)模式银伟,另一種是標(biāo)準(zhǔn)模式。

  • 主動(dòng)模式

在主動(dòng)模式下,TileService被請(qǐng)求時(shí)該服務(wù)會(huì)被綁定,并且TileService的onStartListening也會(huì)被調(diào)用。該模式需要在AndroidManifeast清單文件中聲明:

<service ...>
    <meta-data android:name="android.service.quicksettings.ACTIVE_TILE"
         android:value="true" />
    ...
</service>

通過(guò)TileService.requestListeningState()這一靜態(tài)方法桂肌,就可以實(shí)現(xiàn)對(duì)TileService的請(qǐng)求佩耳,示例如下:

      TileService.requestListeningState(
            applicationContext, ComponentName(
                BuildConfig.APPLICATION_ID,
                MyQSTileService::class.java.name
            )
        )

主動(dòng)模式下值得注意的是:

  • 用戶在通知欄快速設(shè)置的地方點(diǎn)擊快捷開關(guān)時(shí)蛮瞄,TileService會(huì)自動(dòng)完成綁定闲先、TileService的onStartListening會(huì)被調(diào)用蒙谓。
  • TileService無(wú)論是通過(guò)點(diǎn)擊被綁定還是通過(guò)requestListeningState請(qǐng)求被綁定,TileService所在的進(jìn)程都會(huì)被調(diào)起训桶。

標(biāo)準(zhǔn)模式

 在標(biāo)準(zhǔn)模式下累驮,TileService可見時(shí)(即用戶下拉通知欄看見快捷開關(guān))該服務(wù)會(huì)被綁定,并且TileService的onStartListening也會(huì)被調(diào)用舵揭。標(biāo)準(zhǔn)模式不需要在AndroidManifeast清單文件中進(jìn)行額外的聲明谤专,默認(rèn)就是標(biāo)準(zhǔn)模式。

標(biāo)準(zhǔn)模式下值得注意的是:

  • 和主動(dòng)模式相同琉朽,TileService被綁定時(shí),TileService所在的進(jìn)程就會(huì)被調(diào)起稚铣。
  • 而和主動(dòng)模式不同的是箱叁,標(biāo)準(zhǔn)模式綁定TileService是通過(guò)用戶下拉通知欄實(shí)現(xiàn)的,這意味著TileService所在的進(jìn)程會(huì)被多次調(diào)起惕医。因此為了避免主進(jìn)程被頻繁調(diào)起耕漱、避免DAU等數(shù)據(jù)統(tǒng)計(jì)受到影響,我們還需要為TileService指定一個(gè)特定的子進(jìn)程抬伺,在Androidmanifest清單文件中設(shè)置:
      <service
            ......
            android:process="自定義子進(jìn)程的名稱">
            ......
        </service>

更新快捷開關(guān)

如果需要對(duì)快捷開關(guān)的數(shù)據(jù)進(jìn)行更新螟够,可以通過(guò)getQsTile()獲取快捷開關(guān)的對(duì)象,然后通過(guò)setIcon(更新icon)峡钓、setLable(更新名稱)妓笙、setState(更新狀態(tài),包括STATE_ACTIVE——表示開啟或啟用狀態(tài)能岩、STATE_INACTIVE——表示關(guān)閉或暫停狀態(tài)寞宫、STATE_UNAVAILABLE:表示暫時(shí)不可用狀態(tài),在此狀態(tài)下拉鹃,用戶無(wú)法與您的磁貼交互)等方法設(shè)置快捷開關(guān)新的數(shù)據(jù)辈赋,最后調(diào)用updateTile()方法實(shí)現(xiàn)。

  override fun onStartListening() {
    super.onStartListening()
    if (qsTile.state === Tile.STATE_ACTIVE) {
        qsTile.label = "inactive"
        qsTile.icon = Icon.createWithResource(context, R.drawable.inactive)
        qsTile.state = Tile.STATE_INACTIVE
    } else {
        qsTile.label = "active"
        qsTile.icon = Icon.createWithResource(context, R.drawable.active)
        qsTile.state = Tile.STATE_ACTIVE
    }
    qsTile.updateTile()
  }

操作快捷開關(guān)

  • 如果想要實(shí)現(xiàn)點(diǎn)擊快捷開關(guān)時(shí)膏燕、關(guān)閉通知欄并跳轉(zhuǎn)到某個(gè)頁(yè)面钥屈,可以調(diào)用以下方法:
startActivityAndCollapse(Intent intent)
  • 如果想要在點(diǎn)擊快捷開關(guān)時(shí)彈出對(duì)話框進(jìn)行交互,可以調(diào)用以下方法:
override fun onClick() {
    super.onClick()
    if(!isLocked()) {
        showDialog()
    }
 }

因?yàn)榭旖蓍_關(guān)有可能在用戶鎖屏?xí)r出現(xiàn)坝辫,所以必須加上isLocked()的判斷篷就。只有非鎖屏的情況下,對(duì)話框才會(huì)出現(xiàn)近忙。

  • 如果快捷開關(guān)含有敏感信息腻脏,需要使用isSecure()進(jìn)行設(shè)備安全性判斷鸦泳,當(dāng)設(shè)備安全時(shí),才能執(zhí)行快捷開關(guān)相關(guān)的邏輯(如點(diǎn)擊的邏輯)永品。當(dāng)設(shè)備不安全時(shí)(手機(jī)處于鎖屏狀態(tài)時(shí))做鹰,可調(diào)用unlockAndRun(Runnable runnable),提示用戶解鎖屏幕并執(zhí)行自定義的runnable操作鼎姐。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末钾麸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子炕桨,更是在濱河造成了極大的恐慌饭尝,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件献宫,死亡現(xiàn)場(chǎng)離奇詭異钥平,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)姊途,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門涉瘾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人捷兰,你說(shuō)我怎么就攤上這事立叛。” “怎么了贡茅?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵秘蛇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我顶考,道長(zhǎng)赁还,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任驹沿,我火速辦了婚禮秽浇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甚负。我一直安慰自己柬焕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布梭域。 她就那樣靜靜地躺著斑举,像睡著了一般。 火紅的嫁衣襯著肌膚如雪病涨。 梳的紋絲不亂的頭發(fā)上富玷,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼赎懦。 笑死雀鹃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的励两。 我是一名探鬼主播黎茎,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼当悔!你這毒婦竟也來(lái)了傅瞻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盲憎,失蹤者是張志新(化名)和其女友劉穎嗅骄,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饼疙,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡溺森,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窑眯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屏积。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖伸但,靈堂內(nèi)的尸體忽然破棺而出肾请,到底是詐尸還是另有隱情留搔,我是刑警寧澤更胖,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站隔显,受9級(jí)特大地震影響却妨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜括眠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一彪标、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧掷豺,春花似錦捞烟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至德频,卻和暖如春苍息,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工竞思, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留表谊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓盖喷,卻偏偏與公主長(zhǎng)得像爆办,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子传蹈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容