質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

1回答

1041閲覧

通知をタップして呼び出すAcivityでの振動&音声の停止について

tokoroten_12

総合スコア24

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

0クリップ

投稿2022/03/23 07:48

開発・デバッグ環境

Android Studio:4.2.1
使用言語:Java
minSdkVersion:26
compileSdkVersion:31

デバッグ対象
HUAWEI P30
Androidバージョン 10

前提・実現したいこと

タイマーアプリを作成しており、Serviceを利用して以下のような動作を実現したいと考えています。
・MainActivityにて1秒ごとにカウントダウン表示
・60秒経過後に「1分経過」の通知を表示(この時通知と一緒に振動&音声動作)
・通知をタップするとSTOPボタンの配置されたActivity(StopActivity)呼び出し
・STOPボタンを押すと振動&音声停止

発生している問題・エラーメッセージ

Service内でVibratorSoundPoolを使って振動&音声の動作を行っていますが、この振動をStopActivityで止める事が出来ずに困っています。
Service内で起動した振動&音声を別Activityで止める方法はありませんでしょうか?
また、振動と音声の動作についてService内で起動する以外の方法がありましたら教えていただけますでしょうか。

試した事

StopActivity内でVibratorを取得してVibrator.cancel()を行いましたが振動は止まりませんでした。
Intentに対してintent.putExtraでVibratorを渡そうとしましたが構文エラーでNGでした。

また通知時に振動を制御すればいいのではと思いNotificationChannel .setVibrationPatternを設定してみましたがAndroid10では振動パターン制御はできませんでした(Android9ではパターン制御OK)

以下にソースコードを示します。

該当のソースコード

MainActivity
Serviceの起動とカウントダウン表示

java

1public class MainActivity extends AppCompatActivity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 // サービスを起動 8 Intent intentService = new Intent(MainActivity.this, ServiceTest.class); 9 intentService.putExtra("Init", 1); // 起動時は1を渡す 10 startService(intentService); 11 timerStart(60000); 12 } 13 14 public void timerStart(long time_msec) { 15 // 1秒毎に呼び出されるCountDownTimerを設定 16 CountDownTimer countDownTimer = new CountDownTimer(time_msec, 1000) { 17 @Override 18 public void onTick(long milliTillFinish) { 19 // 秒を計算する 20 int sec = (int) (milliTillFinish / 1000) % 60; 21 // テキストを更新 22 String timerLeftFormatted = String.format(Locale.getDefault(), "%02d", sec); 23 ((TextView) findViewById(R.id.tx_timer)).setText(timerLeftFormatted); 24 } 25 // 終了時の動作 26 public void onFinish() { 27 timerStart(60000); 28 } 29 }; 30 countDownTimer.start(); 31 } 32}

ServiceTest
60秒に1回通知と振動&音声動作作成

java

1 2public class ServiceTest extends Service { 3 4 private Context _context; 5 6 @Override 7 public void onCreate() { 8 9 _context = getApplicationContext(); 10 } 11 12 @Override 13 public IBinder onBind(Intent intent) { 14 // TODO: Return the communication channel to the service. 15 throw new UnsupportedOperationException("Not yet implemented"); 16 } 17 18 @Override 19 public int onStartCommand(Intent intent, int flags, int startId) { 20 // デバイスがロックされていればフルスクリーン通知 21 String channelId = "default"; 22 String title = "TimerTest"; 23 String message = "1分経過"; 24 25 int init_flag = intent.getIntExtra("Init", 0); 26 27 28 // init_flagが立っているときは起動時なので通知を表示しない 29 if(init_flag != 1){ 30 // notificationManagers作成 31 NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 32 33 // Notification Channel 設定 34 NotificationChannel channel = new NotificationChannel(channelId, title, NotificationManager.IMPORTANCE_HIGH); 35 channel.setDescription(message); 36 channel.enableVibration(false); 37 channel.setSound(null, null); 38 39 // 通知をタップしたらStopActivityを起動する 40 Intent stopIntent = new Intent(this, StopActivity.class); 41 stopIntent.setFlags( 42 Intent.FLAG_ACTIVITY_SINGLE_TOP 43 ); 44 PendingIntent pendingIntent = 45 PendingIntent.getActivity(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT); 46 47 // 通知の作成 48 Notification notification = new NotificationCompat.Builder(this, channelId) 49 .setContentTitle(title) // 設定されるタイトル 50 .setSmallIcon(android.R.drawable.ic_lock_idle_alarm) // 通知に表示されるアイコン 51 .setContentText(message) // 本文テキスト 52 .setWhen(System.currentTimeMillis()) // タイムスタンプ 53 .setFullScreenIntent(pendingIntent, true) // FullScreen 54 .setAutoCancel(true) 55 .build(); 56 57 // API26以上の場合はチャンネル作るの必須 58 notificationManager.createNotificationChannel(channel); 59 // 通知 60 notificationManager.notify(R.string.app_name, notification); 61 62 // Vibrator作成 63 Vibrator vib = (Vibrator) getSystemService(VIBRATOR_SERVICE); 64 AudioAttributes audioAttributes = new AudioAttributes.Builder() 65 .setUsage(AudioAttributes.USAGE_ALARM) 66 .build(); 67 VibrationEffect ve = VibrationEffect.createWaveform(new long[]{0, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000, 500, 1000}, VibrationEffect.DEFAULT_AMPLITUDE); 68 vib.vibrate(ve, audioAttributes); 69 70 // 音楽作成 71 SoundPool soundPool; 72 int sound; 73 AudioAttributes attributes = new AudioAttributes.Builder() 74 .setUsage(AudioAttributes.USAGE_GAME) 75 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 76 .build(); 77 soundPool = new SoundPool.Builder() 78 .setAudioAttributes(attributes) 79 .setMaxStreams(1) 80 .build(); 81 sound = soundPool.load(this, R.raw.timer, 1); 82 83 // load が終わったら音声を流す 84 soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { 85 @Override 86 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 87 if(status == 0){ 88 soundPool.play(sound, 1.0F, 1.0F, 0, 0, 1.0F); 89 } 90 } 91 }); 92 } 93 // 60秒後にService呼び出すAlarmManager追加 94 setNextAlarmService(_context); 95 // 定数を返す。 96 return START_NOT_STICKY; 97 } 98 99 100 /** 101 60秒経過したらServiceを呼び出すAlarmManager 102 */ 103 private void setNextAlarmService(Context context){ 104 long timer = 60000; 105 // 10秒のアラーム設定 106 Calendar cal = Calendar.getInstance(); 107 cal.setTimeInMillis(System.currentTimeMillis()); 108 cal.add(Calendar.SECOND, (int) ( timer/ 1000)); 109 long startMillis = System.currentTimeMillis() + timer; 110 111 // ServiceTestを呼び出すIntent作成 112 Intent intent = new Intent(context, ServiceTest.class); 113 PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0); 114 AlarmManager alarmManager 115 = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 116 // AlarmManager設定 117 AlarmManager.AlarmClockInfo clockInfo = new AlarmManager.AlarmClockInfo(startMillis, null); 118 if(alarmManager != null){ 119 // AlarmManager設定 120 alarmManager.setAlarmClock(clockInfo, pendingIntent); 121 } 122 } 123}

StopActivity
STOPボタンを表示して振動&音声を止めたいが出来ない

java

1public class StopActivity extends AppCompatActivity { 2 3 @SuppressLint("MissingPermission") 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_stop); 8 9 // ストップボタンのリスナ作成 10 Button bt_timer = findViewById(R.id.bt_stop); 11 StopActivity.HelloListener listener = new StopActivity.HelloListener(); 12 bt_timer.setOnClickListener(listener); 13 } 14 15 16 private class HelloListener implements View.OnClickListener { 17 @Override 18 public void onClick(View view) { 19 int id = view.getId(); 20 switch (id) { 21 case R.id.bt_stop: 22 // 通知をキャンセルする 23 NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 24 notificationManager.cancel(1); 25 finish(); 26 break; 27 } 28 } 29 } 30} 31

xml

1<manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 package="com.timer.test"> 3 4 <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> 5 <uses-permission android:name="android.permission.VIBRATE" /> 6 <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> 7 <uses-permission android:name="android.permission.WAKE_LOCK" /> 8 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> 9 10 <application 11 android:allowBackup="true" 12 android:icon="@mipmap/ic_launcher" 13 android:label="@string/app_name" 14 android:roundIcon="@mipmap/ic_launcher_round" 15 android:supportsRtl="true" 16 android:theme="@style/Theme.BlogTest"> 17 <service 18 android:name=".ServiceTest" 19 android:enabled="true" 20 android:exported="true"></service> 21 22 <activity 23 android:name=".StopActivity" 24 android:showWhenLocked="true" 25 android:turnScreenOn="true" /> 26 <activity 27 android:name=".MainActivity" 28 android:exported="true"> 29 <intent-filter> 30 <action android:name="android.intent.action.MAIN" /> 31 32 <category android:name="android.intent.category.LAUNCHER" /> 33 </intent-filter> 34 </activity> 35 </application> 36 37</manifest> 38

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/03/23 08:42

サービスにバインドして停止させることが出来るような構造にしては如何でしょうか。
tokoroten_12

2022/03/24 06:52

おっしゃられている通りServiceTest内に停止処理を追加、StopActivityからバインドするようにしたら停止できました! ありがとうございます。
guest

回答1

0

自己解決

Service内にBindについての記述追加

java

1private MyBinder binder = new MyBinder(); 2 3public class MyBinder extends Binder { 4 //Serviceの取得 5 ServiceTest getService() { 6 return ServiceTest.this; 7 } 8} 9............... 10 11public void stopAlarm(){ 12 mVibrator.cancel(); 13 mSoundPool.stop(mStreamId); 14}

StopActivity内にServiceと接続する処理を追加する事で対応できた。

java

1public class StopActivity extends AppCompatActivity { 2 3 //取得したServiceの保存 4 private ServiceTest mBoundService; 5 private boolean mIsBound; 6 7 private ServiceConnection mConnection = new ServiceConnection() { 8 public void onServiceConnected(ComponentName className, IBinder service) { 9 10 // サービスとの接続確立時に呼び出される 11 Toast.makeText(StopActivity.this, "Activity:onServiceConnected", 12 Toast.LENGTH_SHORT).show(); 13 14 // サービスにはIBinder経由で#getService()してダイレクトにアクセス可能 15 mBoundService = ((ServiceTest.MyBinder)service).getService(); 16 //必要であればmBoundServiceを使ってバインドしたサービスへの制御を行う 17 } 18 19 public void onServiceDisconnected(ComponentName className) { 20 // サービスとの切断(異常系処理) 21 // プロセスのクラッシュなど意図しないサービスの切断が発生した場合に呼ばれる。 22 mBoundService = null; 23 Toast.makeText(StopActivity.this, "Activity:onServiceDisconnected", 24 Toast.LENGTH_SHORT).show(); 25 } 26 }; 27 28 29 @SuppressLint("MissingPermission") 30 @Override 31 protected void onCreate(Bundle savedInstanceState) { 32 super.onCreate(savedInstanceState); 33 setContentView(R.layout.activity_stop); 34 35 // ストップボタンのリスナ作成 36 Button bt_timer = findViewById(R.id.bt_stop); 37 StopActivity.HelloListener listener = new StopActivity.HelloListener(); 38 bt_timer.setOnClickListener(listener); 39 40 Intent intentService = new Intent(StopActivity.this, ServiceTest.class); 41 intentService.putExtra("Init", 1); // 起動時は1を渡す 42 bindService(intentService, mConnection, BIND_AUTO_CREATE); 43 } 44 45 void doBindService() { 46 //サービスとの接続を確立する。明示的にServiceを指定 47 //(特定のサービスを指定する必要がある。他のアプリケーションから知ることができない = ローカルサービス) 48 bindService(new Intent(StopActivity.this, 49 ServiceTest.class), mConnection, Context.BIND_AUTO_CREATE); 50 mIsBound = true; 51 } 52 53 /** 54 * コネクションの解除 55 */ 56 void doUnbindService() { 57 if (mIsBound) { 58 // コネクションの解除 59 unbindService(mConnection); 60 mIsBound = false; 61 } 62 } 63 64 private class HelloListener implements View.OnClickListener { 65 @Override 66 public void onClick(View view) { 67 int id = view.getId(); 68 switch (id) { 69 case R.id.bt_stop: 70 // 通知をキャンセルする 71 NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 72 notificationManager.cancel(1); 73 doBindService(); 74 mBoundService.stopAlarm(); 75 doUnbindService(); 76 finish(); 77 break; 78 } 79 } 80 } 81}

投稿2022/03/24 06:59

tokoroten_12

総合スコア24

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問