Loading [MathJax]/extensions/tex2jax.js

2020年6月23日火曜日

Android 充電ケーブル挿す、抜くのイベントを拾う

やりたいこと
Android で充電ケーブルを挿したときと、抜いた時のイベントを拾う方法を勉強したので、手順をまとめておきます。

環境
Windows 10
Android Studio : 4.0

テスト環境
Nexus S API 22(emulator) : Android5.1
Pixel 3 API 26(emulator) : Android8.0

参考にしたサイト

[(1)ブロードキャストレシーバーについて]
https://developer.android.com/guide/components/broadcasts
[(2)電源管理について]
https://developer.android.com/training/monitoring-device-state/battery-monitoring?hl=ja

ざっくりと
ざっくり説明すると以下の手順となります。
(1)manifestにひろいたいイベントと関数をかく。(android7まで用)
(2)イベントを拾う用のクラスを作成する。そのクラスはBroadcastReceiverを継承させる。
(3)イベントを拾う用のクラスをnewして、レシーバーとして登録する。

Android7までなら(1)と(2)だけでイベントを拾うことができます。 アプリがいなくてもイベントが拾えます。

Android8以降は(1)と(2)だけではイベントを拾えなくなってるので、(3)の手順が必要になります。 しかもAndroid8以降はアプリが起きていないと拾えなくなってます。 この辺のことは参考にしたサイト(1)に詳しく記載されております。

以降は手順を細かく記載します。

Step1.Manifestの登録
AndroidManifest.xmlに下記の6行を追加します。
  1. <receiver android:name=".PowerConnectionReceiver">  
  2.     <intent-filter>  
  3.         <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>  
  4.         <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>  
  5.     </intent-filter>  
  6. </receiver>  
「PowerConnectionReceiver」はイベントをキャッチするクラスの名前です。
 任意の名前でOKです。
「ACTION_POWER_CONNECTED」は接続したときのイベントを拾うときのIntent、
「ACTION_POWER_DISCONNECTED」は抜いた時のイベントを拾うときのIntentとなります。

manifest全体ではこうなります。
  1.    
  2.   
  3. <manifest package="com.example" xmlns:android="http://schemas.android.com/apk/res/android">  
  4.   
  5.     <application android:allowbackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundicon="@mipmap/ic_launcher_round" android:supportsrtl="true" android:theme="@style/AppTheme">  
  6.         <activity android:label="@string/app_name" android:name=".MainActivity" android:theme="@style/AppTheme.NoActionBar">  
  7.             <intent-filter>  
  8.                 <action android:name="android.intent.action.MAIN" /&gt  
  9.   
  10.                 <category android:name="android.intent.category.LAUNCHER" /&gt  
  11.             </intent-filter>  
  12.         </activity>  
  13.           
  14.     <!--ここから追加-->  
  15.         <receiver android:name=".PowerConnectionReceiver">  
  16.             <intent-filter>  
  17.                 <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>  
  18.                 <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>  
  19.             </intent-filter>  
  20.         </receiver>  
  21.        <!--ここまで追加-->  
  22.          
  23.     </application>  
  24. </manifest>  

Step2.イベントをキャッチするクラスを追加
2-1.下図のようにクラスを追加します。クラス名はStep1で定義したものと同じ名前としてください。


2-2.BroadcastReceiverを継承します。
  1.    
  2. import android.content.BroadcastReceiver;  
  3.   
  4. public class PowerConnectionReceiver extends BroadcastReceiver {  
  5. }  
2-3.onReceiveメソッドを追加します。
  1.    
  2. import android.content.BroadcastReceiver;  
  3. import android.content.Context;  
  4. import android.content.Intent;  
  5.   
  6. public class PowerConnectionReceiver extends BroadcastReceiver {  
  7.     public void onReceive(Context context, Intent intent) {  
  8.           
  9.     }  
  10. }  
2-4.イベントを拾ったときに文字列を画面に表示するようにしておきました。
  1.    
  2. import android.content.BroadcastReceiver;  
  3. import android.content.Context;  
  4. import android.content.Intent;  
  5. import android.widget.Toast;  
  6.   
  7. public class PowerConnectionReceiver extends BroadcastReceiver {  
  8.     public void onReceive(Context context, Intent intent) {  
  9.   
  10.         if (intent.getAction() == Intent.ACTION_POWER_CONNECTED)  {  
  11.             Toast.makeText(context, "ケーブルを接続した", Toast.LENGTH_LONG ).show();  
  12.         }  
  13.         else if (intent.getAction() == Intent.ACTION_POWER_DISCONNECTED) {  
  14.             Toast.makeText(context, "ケーブルを抜いた", Toast.LENGTH_LONG ).show();  
  15.         }  
  16.     }  
  17. }  
Android 7以前が対象の場合は、Step1, Step2までで完了となります。Android5.1で動作することが確認できました。
さらにAndroid 7以前の場合はアプリが起動中でなくても、このイベントが発生するとアプリが起動します。
Step3.レシーバーを明示的に登録する
Android8以降はStep1のmanifestの方法でイベントがひろえなくなってます。
そこで、明示的にPowerConnectionReceiverをnewしてレシーバーとして登録しておきます。
以下のようなコードとなります。
  1. BroadcastReceiver br = new PowerConnectionReceiver();  
  2. IntentFilter filter = new IntentFilter(Intent.ACTION_POWER_CONNECTED);  
  3. filter.addAction(Intent.ACTION_POWER_DISCONNECTED);  
  4. this.registerReceiver(br, filter);  

これをMainActivityのonCreateメソッドに追加しました。
  1.    
  2. public class MainActivity extends AppCompatActivity {  
  3.   
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.activity_main);  
  8.         Toolbar toolbar = findViewById(R.id.toolbar);  
  9.         setSupportActionBar(toolbar);  
  10.   
  11.         FloatingActionButton fab = findViewById(R.id.fab);  
  12.         fab.setOnClickListener(new View.OnClickListener() {  
  13.             @Override  
  14.             public void onClick(View view) {  
  15.                 Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)  
  16.                         .setAction("Action"null).show();  
  17.             }  
  18.         });  
  19.   
  20.         // ここから追加  
  21.         BroadcastReceiver br = new PowerConnectionReceiver();  
  22.         IntentFilter filter = new IntentFilter(Intent.ACTION_POWER_CONNECTED);  
  23.         filter.addAction(Intent.ACTION_POWER_DISCONNECTED);  
  24.         this.registerReceiver(br, filter);  
  25.   
  26.     }  
※Googleのサイトの用語でいうと「コンテキスト登録されたレシーバー」というものになります。

Step4.テスト
emulatorで電源挿抜のテストをします。
emulatorの右の操作パネルの一番したのボタンをクリックします。

「Extended controls」ダイアログが表示されるので、Batteryを選択し、Charger connectionを操作します。

ここを操作すると電源ケーブルの挿抜の操作が仮想的にできます。
emulatorの下側に文字列が表示されたら成功です。

Android8でも確認。できました。

 
Step5.今後の課題
Android8以降は、アプリが生存していないとイベントを拾えないので、そこを解決したいです。 ヒントとなるのが、JobScheduler とserviceかなと考えてるので、この辺を勉強していきたいと思ってます。
0 件のコメント:
コメントを投稿