デフォルトアプリとパーミッション

 デフォルトアプリとパーミッション

Ac6f0faaab626a101cab97cab29f086f?s=128

katsuki-nakatani

November 09, 2017
Tweet

Transcript

  1. デフォルトアプリとパーミッション 2017/11/9 Osaka Mix Leap Study #1 - Android /

    iOS
  2. Speaker 中谷 克紀 仕事  Enterprise Server Engineer GDG 神戸スタッフ Twitter  @KatsukiNakatani

  3. 早速ですが皆さん 「android.permission.MODIFY_PHONE_STATE」知っていますか? Androidアプリにおけるパーミッション(権限)の一つです

  4. パーミッション? Androidのアプリを動かすための権限の仕組み ・アプリに「センサー」や「データ」を取得または更新を許可するもの(ユーザーが許諾するもの) ・AndroidManifest.xmlに定義をします <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.exampke.hogehoge" android:installLocation="auto"> <uses-permission android:name="android.permission.INTERNET"

    /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PROFILE" android:maxSdkVersion="22" /> </manifest>
  5. Android 6.0で仕組みが変わりました ストアからアプリをインストールする際に権限を許諾する 「Installed Permission」から アプリ側で必要な時に必要な権限を要求する 「Runtime Permission」に変更されました

  6. パーミッションには種類がある adb shell pm list permissions -f -g + permission:android.permission.READ_CONTACTS

    package:android label:read your contacts description:Allows the app ... protectionLevel:dangerous + permission:android.permission.MODIFY_PHONE_STATE package:android label:null description:null protectionLevel:signature|privileged 一般アプリで使用可能 Runtime Permission機能で権限を許可 一般アプリで使用不可能 システムアプリのみで許可
  7. MODIFY_PHONE_STATEで何が出来る? ・電話の発着信をフックして切断等が可能 ・不在着信の消去など

  8. Android 2.2では MODIFY_PHONE_STATEはユーザーアプリに許可されていた ただし、着信を切断したりすることが可能でリスキーな権限な為、 Android2.3以降はシステムアプリでしか使用できなくなってしまいました。

  9. Android 2.3以降では 不在通知のタップ処理は Intentで拾えるが、 不在通知が消せない 通知をタップ

  10. ちなみに 未読ログはWRITE_CALL_LOGの権限で消せる(フラグは更新できる) val content = context.contentResolver value.put(CallLog.Calls.NEW, 0) value.put(CallLog.Calls.IS_READ, 1)

    content.update(CallLog.Calls.CONTENT_URI, value, CallLog.Calls.TYPE + "=" + CallLog.Calls.MISSED_TYPE + " AND " + CallLog.Calls.NEW + "='1'" + " AND " + CallLog.Calls.IS_READ + "='0'", null) CallLogデータベース上は、未読は0件になるが、通知は消えなく、 通知に表示される未読件数も別のところ(TelecomManager)で管理されているため、 通話履歴の件数はずっと増え続けるし表示に不整合が起きる
  11. Lollipopで通話関連APIが整理 API Level21(Lollipop)で増えている これで通知が消せる!  

  12. Let’s Try! あかん

  13. Permissionを書いてみる やっぱりあかん

  14. 「MODIFY_PHONE_STATE」必要  

  15. Default Appsにしたら呼べる

  16. どうするか まずはデフォルトアプリとして選択できるようにしたい

  17. 必要なIntentFilterを登録すると選択できるよう になります PhoneAppとして登録出来る要件は 下記のDialerとして反応するIntentFilterをManifestに登録すること <intent-filter> <action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.DIAL"

    /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="tel" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.DIAL" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>
  18. 通話ログ消去の実装 val content = context.contentResolver ContentValues().apply{ put(CallLog.Calls.NEW, 0) put(CallLog.Calls.IS_READ, 1)

    }.also{ content.update(CallLog.Calls.CONTENT_URI, it, CallLog.Calls.TYPE + "=" + CallLog.Calls.MISSED_TYPE + " AND " + CallLog.Calls.NEW + "='1'" + " AND " + CallLog.Calls.IS_READ + "='0'", null) } val manager = context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager if (TextUtils.equals(manager.defaultDialerPackage, context.packageName)) { manager.cancelMissedCallsNotification() ・・・デフォルトアプリでない場合は落ちる } 通知ログDBの更新 デフォルトアプリとして登録 されているか判断し、通知を消去 HogeActivityやHogeService
  19. https://source.android.com/devices/tech/connect/call-notification Android 7.0で少し仕組みが変わる Android 6.0以前では左記の表の通りに 機能の住み分けが行われていた

  20. https://source.android.com/devices/tech/connect/call-notification Android 7.0 and later

  21. https://source.android.com/devices/tech/connect/call-notification Android 7.0で少し仕組みが変わる 不在着信通知がカスタマイズ できるんじゃ?

  22. Try!

  23. Manifestにレシーバとサービスを追加 <receiver android:name=".MissedCallNotificationReceiver" android:directBootAware="true"> <intent-filter> <action android:name="android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" /> </intent-filter> </receiver>

    不在着信を受け取るレシーバ レシーバから呼び出すサービス <service android:name=".MissedCallNotificationService" android:permission="android.permission.BIND_JOB_SERVICE" android:enabled="true" android:exported="true" />
  24. ManifestにPermissionを追加 //READ_PHONE_STATEが無いと、BroadcastReceiverでIntentを受け取れない <uses-permission android:name="android.permission.READ_PHONE_STATE" />

  25. レシーバの実装 class MissedCallNotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context,

    intent: Intent) { val action = intent.action if (ACTION_SHOW_MISSED_CALLS_NOTIFICATION != action) { return } val count = intent.getIntExtra(EXTRA_NOTIFICATION_COUNT, UNKNOWN_MISSED_CALL_COUNT) val number = intent.getStringExtra(EXTRA_NOTIFICATION_PHONE_NUMBER) if (count > 0) MissedCallNotificationService.enqueueWork(context, MissedCallNotificationService.createIntent(context, count, number)) } companion object { val ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" val EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT" val EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER" val UNKNOWN_MISSED_CALL_COUNT = -1 } }
  26. 通知を上げるサービスの実装 class MissedCallNotificationService : JobIntentService() { companion object { …

    fun enqueueWork(context: Context, work: Intent) { enqueueWork(context, MissedCallNotificationService::class.java, JOB_ID, work) } ... override fun onHandleWork(intent: Intent) { //通知処理を実装 }
  27. Run 自作アプリで不在着信通知を 受け取ることに成功

  28. 危険性は? デフォルトアプリはユーザーが選択(インストール+既定の設定)するもの。 (自動的にアプリで書き換えるものではない) ※ただし警告などが出るわけではないので、やはり開発元を信頼するしか無いのは  変わらず

  29. まとめ ・Android 6.0以降の「Default Apps」を使えば、システムにしか許可されていなかったパーミッション(API)を一部扱うことが出来ます ・Default Appの電話の機能については、Android7.0以降で更に整理が進み、TelecomアプリとDialerアプリで  機能の分離が行われ、開発者はより電話の機能を組み込んだアプリを作れるようになりました ・とにかく文献が無いのでソースを読むしか無い ・Android ThingsにSIM乗せて、特定の着信があったら何かアクションするとか、一昔前のギミックみたいで

     面白そうだなと思ったり
  30. おしまい 御清聴ありがとうございました 実際このアプリに実装済みなのでよければ試してみてください https://goo.gl/SHVRgC https://goo.gl/tqTKRB サンプルソース