/* Copyright (C) 2015-2018 Andreas Shimokawa, Carsten Pfeiffer, Daniele Gobbetti, Frank Slezak, ivanovlev, Kasha, Lem Dulfo, Steffen Liebergeld This file is part of Gadgetbridge. Gadgetbridge is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gadgetbridge is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.activities; import android.app.AlertDialog; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.NavUtils; import android.support.v4.app.NotificationCompat; import android.support.v4.app.RemoteInput; import android.support.v4.content.LocalBroadcastManager; import android.view.MenuItem; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.util.ArrayList; import java.util.Objects; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.model.CallSpec; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes; import nodomain.freeyourgadget.gadgetbridge.util.GB; import static android.content.Intent.EXTRA_SUBJECT; import static nodomain.freeyourgadget.gadgetbridge.util.GB.NOTIFICATION_CHANNEL_ID; public class DebugActivity extends AbstractGBActivity { private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class); private static final String EXTRA_REPLY = "reply"; private static final String ACTION_REPLY = "nodomain.freeyourgadget.gadgetbridge.DebugActivity.action.reply"; private Spinner sendTypeSpinner; private EditText editContent; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (Objects.requireNonNull(intent.getAction())) { case ACTION_REPLY: { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); CharSequence reply = remoteInput.getCharSequence(EXTRA_REPLY); LOG.info("got wearable reply: " + reply); GB.toast(context, "got wearable reply: " + reply, Toast.LENGTH_SHORT, GB.INFO); break; } default: LOG.info("ignoring intent action " + intent.getAction()); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_debug); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_REPLY); filter.addAction(DeviceService.ACTION_HEARTRATE_MEASUREMENT); LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter); registerReceiver(mReceiver, filter); // for ACTION_REPLY editContent = findViewById(R.id.editContent); ArrayList spinnerArray = new ArrayList<>(); for (NotificationType notificationType : NotificationType.values()) { spinnerArray.add(notificationType.name()); } ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, spinnerArray); sendTypeSpinner = findViewById(R.id.sendTypeSpinner); sendTypeSpinner.setAdapter(spinnerArrayAdapter); Button sendButton = findViewById(R.id.sendButton); sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { NotificationSpec notificationSpec = new NotificationSpec(); String testString = editContent.getText().toString(); notificationSpec.phoneNumber = testString; notificationSpec.body = testString; notificationSpec.sender = testString; notificationSpec.subject = testString; notificationSpec.type = NotificationType.values()[sendTypeSpinner.getSelectedItemPosition()]; notificationSpec.pebbleColor = notificationSpec.type.color; notificationSpec.id = -1; GBApplication.deviceService().onNotification(notificationSpec); } }); Button incomingCallButton = findViewById(R.id.incomingCallButton); incomingCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { CallSpec callSpec = new CallSpec(); callSpec.command = CallSpec.CALL_INCOMING; callSpec.number = editContent.getText().toString(); GBApplication.deviceService().onSetCallState(callSpec); } }); Button outgoingCallButton = findViewById(R.id.outgoingCallButton); outgoingCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { CallSpec callSpec = new CallSpec(); callSpec.command = CallSpec.CALL_OUTGOING; callSpec.number = editContent.getText().toString(); GBApplication.deviceService().onSetCallState(callSpec); } }); Button startCallButton = findViewById(R.id.startCallButton); startCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { CallSpec callSpec = new CallSpec(); callSpec.command = CallSpec.CALL_START; GBApplication.deviceService().onSetCallState(callSpec); } }); Button endCallButton = findViewById(R.id.endCallButton); endCallButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { CallSpec callSpec = new CallSpec(); callSpec.command = CallSpec.CALL_END; GBApplication.deviceService().onSetCallState(callSpec); } }); Button rebootButton = findViewById(R.id.rebootButton); rebootButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GBApplication.deviceService().onReboot(); } }); Button heartRateButton = findViewById(R.id.HeartRateButton); heartRateButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GB.toast("Measuring heart rate, please wait...", Toast.LENGTH_LONG, GB.INFO); GBApplication.deviceService().onHeartRateTest(); } }); Button setMusicInfoButton = findViewById(R.id.setMusicInfoButton); setMusicInfoButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MusicSpec musicSpec = new MusicSpec(); String testString = editContent.getText().toString(); musicSpec.artist = testString + "(artist)"; musicSpec.album = testString + "(album)"; musicSpec.track = testString + "(track)"; musicSpec.duration = 10; musicSpec.trackCount = 5; musicSpec.trackNr = 2; GBApplication.deviceService().onSetMusicInfo(musicSpec); MusicStateSpec stateSpec = new MusicStateSpec(); stateSpec.position = 0; stateSpec.state = 0x01; // playing stateSpec.playRate = 100; stateSpec.repeat = 1; stateSpec.shuffle = 1; GBApplication.deviceService().onSetMusicState(stateSpec); } }); Button setTimeButton = findViewById(R.id.setTimeButton); setTimeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GBApplication.deviceService().onSetTime(); } }); Button testNotificationButton = findViewById(R.id.testNotificationButton); testNotificationButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { testNotification(); } }); Button fetchDebugLogsButton = findViewById(R.id.fetchDebugLogsButton); fetchDebugLogsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { GBApplication.deviceService().onFetchRecordedData(RecordedDataTypes.TYPE_DEBUGLOGS); } }); Button testNewFunctionalityButton = findViewById(R.id.testNewFunctionality); testNewFunctionalityButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { testNewFunctionality(); } }); Button shareLogButton = findViewById(R.id.shareLog); shareLogButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showWarning(); } }); } private void showWarning() { new AlertDialog.Builder(this) .setCancelable(true) .setTitle(R.string.warning) .setMessage(R.string.share_log_warning) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String fileName = GBApplication.getLogPath(); if (fileName != null && fileName.length() > 0) { Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); emailIntent.setType("*/*"); emailIntent.putExtra(EXTRA_SUBJECT, "Gadgetbridge log file"); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(fileName))); startActivity(Intent.createChooser(emailIntent, "Share File")); } } }) .setNegativeButton(R.string.Cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // do nothing } }) .show(); } private void testNewFunctionality() { GBApplication.deviceService().onTestNewFunction(); } private void shareLog() { String fileName = GBApplication.getLogPath(); if(fileName != null && fileName.length() > 0) { Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND); emailIntent.setType("*/*"); emailIntent.putExtra(EXTRA_SUBJECT, "Gadgetbridge log file"); emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(fileName))); startActivity(Intent.createChooser(emailIntent, "Share File")); } } private void testNotification() { Intent notificationIntent = new Intent(getApplicationContext(), DebugActivity.class); notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0); NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_REPLY) .build(); Intent replyIntent = new Intent(ACTION_REPLY); PendingIntent replyPendingIntent = PendingIntent.getBroadcast(this, 0, replyIntent, 0); NotificationCompat.Action action = new NotificationCompat.Action.Builder(android.R.drawable.ic_input_add, "Reply", replyPendingIntent) .addRemoteInput(remoteInput) .build(); NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender().addAction(action); NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) .setContentTitle(getString(R.string.test_notification)) .setContentText(getString(R.string.this_is_a_test_notification_from_gadgetbridge)) .setTicker(getString(R.string.this_is_a_test_notification_from_gadgetbridge)) .setSmallIcon(R.drawable.ic_notification) .setAutoCancel(true) .setContentIntent(pendingIntent) .extend(wearableExtender); if (nManager != null) { nManager.notify((int) System.currentTimeMillis(), ncomp.build()); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpFromSameTask(this); return true; } return super.onOptionsItemSelected(item); } @Override protected void onDestroy() { super.onDestroy(); LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver); unregisterReceiver(mReceiver); } }