Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit efeacf3

Browse files
chon219ryanisgrig
authored andcommitted
[Android] UI refactoring and bug fix (#2383)
* [Android] #2232 refactored navigation drawer and settings view * [Android] fixed #2235 default assistant app * [Android] #2238 keep screen on config * [Android] fixed #2235 start listening without showing app UI * [Android] fixed null pointer exception in speech service * [Android] #2233 default configuration provided by a configuration file
1 parent 2ccc211 commit efeacf3

File tree

38 files changed

+925
-533
lines changed

38 files changed

+925
-533
lines changed

samples/clients/android/VirtualAssistantClient/app/src/debug/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/configuration/DefaultConfiguration.java

Lines changed: 0 additions & 20 deletions
This file was deleted.

samples/clients/android/VirtualAssistantClient/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<uses-permission android:name="android.permission.INTERNET" />
1111
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- for ContextCompat.startForegroundService -->
1212
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
13+
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
1314
<!-- DANGEROUS -->
1415
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <!-- FOR SPEECH COMMANDS -->
1516
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -38,7 +39,8 @@
3839
</activity>
3940

4041
<activity
41-
android:name=".assistant.VoiceInteractionActivity">
42+
android:name=".assistant.VoiceInteractionActivity"
43+
android:theme="@android:style/Theme.NoDisplay">
4244
<intent-filter>
4345
<action android:name="android.intent.action.MAIN" />
4446
<category android:name="android.intent.category.DEFAULT" />
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"history_linecount": 2147483646,
3+
"show_full_conversation": true,
4+
"enable_dark_mode": false,
5+
"keep_screen_on": true
6+
}

samples/clients/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/MainApplication.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@
22

33
import android.app.Application;
44
import android.content.Intent;
5-
import android.content.SharedPreferences;
65
import android.support.v4.content.ContextCompat;
7-
import android.support.v7.app.AppCompatDelegate;
86

97
import com.microsoft.bot.builder.solutions.virtualassistant.service.SpeechService;
108

11-
import static com.microsoft.bot.builder.solutions.virtualassistant.activities.BaseActivity.SHARED_PREFS_NAME;
12-
import static com.microsoft.bot.builder.solutions.virtualassistant.activities.BaseActivity.SHARED_PREF_DARK_MODE;
13-
149
public class MainApplication extends Application {
1510

1611
// STATE
@@ -25,11 +20,6 @@ public void onCreate() {
2520
Intent intent = new Intent(this, SpeechService.class);
2621
intent.setAction(SpeechService.ACTION_START_FOREGROUND_SERVICE);
2722
ContextCompat.startForegroundService(this, intent);
28-
29-
// read the dark-mode setting (necessary because setDefaultNightMode() doesn't persist between app restarts)
30-
SharedPreferences sharedPreferences = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE);
31-
boolean darkModeEnabled = sharedPreferences.getBoolean(SHARED_PREF_DARK_MODE, false);
32-
AppCompatDelegate.setDefaultNightMode(darkModeEnabled?AppCompatDelegate.MODE_NIGHT_YES:AppCompatDelegate.MODE_NIGHT_NO);
3323
}
3424

3525
public static MainApplication getInstance(){

samples/clients/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/BaseActivity.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.microsoft.bot.builder.solutions.directlinespeech.model.Configuration;
2727
import com.microsoft.bot.builder.solutions.virtualassistant.ISpeechService;
2828
import com.microsoft.bot.builder.solutions.virtualassistant.R;
29+
import com.microsoft.bot.builder.solutions.virtualassistant.utils.AppConfigurationManager;
2930

3031
/**
3132
* This base class provides functionality that is reusable in Activities of this app
@@ -37,14 +38,13 @@ public abstract class BaseActivity extends AppCompatActivity {
3738
private static final Integer PERMISSION_REQUEST_RECORD_AUDIO = 101;
3839
private static final Integer PERMISSION_REQUEST_FINE_LOCATION = 102;
3940
public static final String SHARED_PREFS_NAME = "my_shared_prefs";
40-
protected static final String SHARED_PREF_SHOW_FULL_CONVERSATION = "SHARED_PREF_SHOW_FULL_CONVERSATION";
41-
public static final String SHARED_PREF_DARK_MODE = "SHARED_PREF_DARK_MODE";
4241
protected static final String SHARED_PREF_ENABLE_KWS = "SHARED_PREF_ENABLE_KWS";
4342

4443
// STATE
4544
private SharedPreferences sharedPreferences;
4645
protected ISpeechService speechServiceBinder;
4746
protected ConfigurationManager configurationManager;
47+
protected AppConfigurationManager appConfigurationManager;
4848

4949
// OVERRIDE THESE
5050
protected void permissionDenied(String manifestPermission){}
@@ -57,6 +57,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
5757
sharedPreferences = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE);
5858
setupMainWindowDisplayMode();
5959
configurationManager = new ConfigurationManager(this);
60+
appConfigurationManager = new AppConfigurationManager(this);
6061
}
6162

6263
@Override

samples/clients/android/VirtualAssistantClient/app/src/main/java/com/microsoft/bot/builder/solutions/virtualassistant/activities/main/MainActivity.java

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import android.graphics.drawable.AnimationDrawable;
88
import android.media.AudioManager;
99
import android.media.MediaPlayer;
10+
import android.net.Uri;
1011
import android.os.Bundle;
1112
import android.os.Handler;
1213
import android.os.Looper;
@@ -28,6 +29,7 @@
2829
import android.view.KeyEvent;
2930
import android.view.MenuItem;
3031
import android.view.View;
32+
import android.view.WindowManager;
3133
import android.view.inputmethod.EditorInfo;
3234
import android.widget.CompoundButton;
3335
import android.widget.ImageView;
@@ -36,7 +38,6 @@
3638

3739
import com.google.gson.Gson;
3840
import com.google.gson.reflect.TypeToken;
39-
import com.microsoft.bot.builder.solutions.directlinespeech.model.Configuration;
4041
import com.microsoft.bot.builder.solutions.virtualassistant.R;
4142
import com.microsoft.bot.builder.solutions.virtualassistant.activities.BaseActivity;
4243
import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.actionslist.ActionsAdapter;
@@ -45,7 +46,7 @@
4546
import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist.ChatAdapter;
4647
import com.microsoft.bot.builder.solutions.virtualassistant.activities.main.chatlist.ItemOffsetDecoration;
4748
import com.microsoft.bot.builder.solutions.virtualassistant.activities.settings.SettingsActivity;
48-
import com.microsoft.bot.builder.solutions.virtualassistant.assistant.VoiceInteractionActivity;
49+
import com.microsoft.bot.builder.solutions.virtualassistant.utils.AppConfiguration;
4950

5051
import org.greenrobot.eventbus.EventBus;
5152
import org.greenrobot.eventbus.Subscribe;
@@ -87,26 +88,27 @@ public class MainActivity extends BaseActivity
8788
@BindView(R.id.textinput) TextInputEditText textInput;
8889
@BindView(R.id.drawer_layout) DrawerLayout drawer;
8990
@BindView(R.id.nav_view) NavigationView navigationView;
90-
@BindView(R.id.switch_show_full_conversation) SwitchCompat switchShowFullConversation;
91-
@BindView(R.id.switch_night_mode) SwitchCompat switchNightMode;
9291
@BindView(R.id.speech_detection) TextView detectedSpeechToText;
9392
@BindView(R.id.mic_image) ImageView micImage;
9493
@BindView(R.id.kbd_image) ImageView kbdImage;
9594
@BindView(R.id.animated_assistant) AppCompatImageView animatedAssistant;
9695
@BindView(R.id.switch_enable_kws) SwitchCompat switchEnableKws;
96+
@BindView(R.id.nav_menu_set_as_default_assistant) TextView setDefaultAssistant;
9797

9898
// CONSTANTS
9999
private static final int CONTENT_VIEW = R.layout.activity_main;
100100
private static final String LOGTAG = "MainActivity";
101+
private static final int REQUEST_CODE_SETTINGS = 256;
102+
private static final int REQUEST_CODE_OVERLAY_PERMISSION = 255;
101103

102104
// STATE
103105
private ChatAdapter chatAdapter;
104106
private ActionsAdapter suggActionsAdapter;
105-
private boolean showFullConversation;
106107
private Handler handler;
107-
private boolean launchedAsAssistant;
108108
private Gson gson;
109109
private SfxManager sfxManager;
110+
private boolean enableDarkMode;
111+
private boolean keepScreenOn;
110112
private boolean enableKws;
111113
private boolean isExpandedTextInput;
112114
private boolean isCreated;// used to identify when onCreate() is complete, used with SwitchCompat
@@ -124,9 +126,6 @@ protected void onCreate(Bundle savedInstanceState) {
124126
setupSuggestedActionsRecyclerView();
125127

126128
// Options hidden in the nav-drawer
127-
showFullConversation = getBooleanSharedPref(SHARED_PREF_SHOW_FULL_CONVERSATION);
128-
switchShowFullConversation.setChecked(showFullConversation);
129-
switchNightMode.setChecked(AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES);
130129
enableKws = getBooleanSharedPref(SHARED_PREF_ENABLE_KWS);
131130
switchEnableKws.setChecked(enableKws);
132131

@@ -148,21 +147,15 @@ protected void onCreate(Bundle savedInstanceState) {
148147
// make media volume the default
149148
setVolumeControlStream(AudioManager.STREAM_MUSIC);
150149

151-
// check if this activity was launched as an assistant
152-
Intent intent = getIntent();
153-
if (intent != null) {
154-
String originator = intent.getStringExtra(VoiceInteractionActivity.KEY_ORIGINATOR);
155-
if (originator != null && originator.equals(VoiceInteractionActivity.KEY_VALUE)) {
156-
launchedAsAssistant = true;//this flag can now be used, i.e. to automatically start microphone recording
157-
}
158-
}
159-
160150
sfxManager = new SfxManager();
161151
sfxManager.initialize(this);
162152

163153
// assign animation
164154
animatedAssistant.setBackgroundResource(R.drawable.agent_listening_animation);
165155

156+
// load configurations from shared preferences
157+
loadAppConfiguration();
158+
166159
isCreated = true;//keep this as last line in onCreate()
167160
}
168161

@@ -179,11 +172,15 @@ public void onStart() {
179172
@Override
180173
protected void onResume() {
181174
super.onResume();
182-
final Configuration configuration = configurationManager.getConfiguration();
183-
chatAdapter.setChatItemHistoryCount(configuration.historyLinecount==null?1:configuration.historyLinecount);
184-
chatAdapter.setChatBubbleColors(configuration.colorBubbleBot, configuration.colorBubbleUser);
185-
chatAdapter.setChatTextColors(configuration.colorTextBot, configuration.colorTextUser);
186-
chatAdapter.setShowFullConversation(showFullConversation);
175+
if (keepScreenOn) {
176+
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // to keep screen on
177+
}
178+
}
179+
180+
@Override
181+
protected void onPause() {
182+
super.onPause();
183+
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // to disable keeping screen on
187184
}
188185

189186
// Unregister EventBus messages and SpeechService
@@ -280,18 +277,15 @@ public boolean onNavigationItemSelected(MenuItem item) {
280277
try {
281278

282279
switch (id) {
283-
case R.id.nav_menu_configuration:
284-
startActivity(SettingsActivity.getNewIntent(this));
280+
case R.id.nav_menu_settings:
281+
startActivityForResult(SettingsActivity.getNewIntent(this), REQUEST_CODE_SETTINGS);
285282
break;
286-
case R.id.nav_menu_reset_bot:
283+
case R.id.nav_menu_restart_conversation:
287284
speechServiceBinder.resetBot();
288285
chatAdapter.resetChat();
289286
suggActionsAdapter.clear();
290287
speechServiceBinder.clearSuggestedActions();
291288
break;
292-
case R.id.nav_menu_show_assistant_settings:
293-
startActivity(new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS));
294-
break;
295289
}
296290

297291
} catch (RemoteException exception){
@@ -303,6 +297,27 @@ public boolean onNavigationItemSelected(MenuItem item) {
303297
return true;
304298
}
305299

300+
@Override
301+
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
302+
if (requestCode == REQUEST_CODE_SETTINGS && resultCode == RESULT_OK) {
303+
loadAppConfiguration();
304+
} else if (requestCode == REQUEST_CODE_OVERLAY_PERMISSION) {
305+
if (Settings.canDrawOverlays(this)) {
306+
startActivity(new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS));
307+
}
308+
}
309+
}
310+
311+
private void loadAppConfiguration() {
312+
AppConfiguration appConfiguration = appConfigurationManager.getConfiguration();
313+
setDarkMode(appConfiguration.enableDarkMode);
314+
keepScreenOn = appConfiguration.keepScreenOn;
315+
chatAdapter.setShowFullConversation(appConfiguration.showFullConversation);
316+
chatAdapter.setChatItemHistoryCount(appConfiguration.historyLinecount);
317+
chatAdapter.setChatBubbleColors(appConfiguration.colorBubbleBot, appConfiguration.colorBubbleUser);
318+
chatAdapter.setChatTextColors(appConfiguration.colorTextBot, appConfiguration.colorTextUser);
319+
}
320+
306321
private void showListeningAnimation(){
307322
Log.i(LOGTAG, "Listening again - showListeningAnimation()");
308323
animatedAssistant.setVisibility(View.VISIBLE);
@@ -336,6 +351,17 @@ public void onClickAssistant() {
336351
}
337352
}
338353

354+
@OnClick(R.id.nav_menu_set_as_default_assistant)
355+
public void onClickSetDefaultAssistant() {
356+
if (Settings.canDrawOverlays(this)) {
357+
startActivity(new Intent(Settings.ACTION_VOICE_INPUT_SETTINGS));
358+
} else {
359+
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
360+
intent.setData(Uri.parse("package:" + getPackageName()));
361+
startActivityForResult(intent, REQUEST_CODE_OVERLAY_PERMISSION);
362+
}
363+
}
364+
339365
@OnCheckedChanged(R.id.switch_enable_kws)
340366
public void onCheckedChangedEnableKws(CompoundButton button, boolean checked){
341367
if (isCreated) {
@@ -355,27 +381,18 @@ public void onCheckedChangedEnableKws(CompoundButton button, boolean checked){
355381
}
356382
}
357383

358-
@OnCheckedChanged(R.id.switch_show_full_conversation)
359-
public void OnCheckedChangedShowFullConversation(CompoundButton button, boolean checked){
360-
if (isCreated) {
361-
showFullConversation = checked;
362-
putBooleanSharedPref(SHARED_PREF_SHOW_FULL_CONVERSATION, checked);
363-
chatAdapter.setShowFullConversation(showFullConversation);
364-
}
365-
}
384+
public void setDarkMode(boolean enabled){
385+
if (enableDarkMode != enabled) {
386+
enableDarkMode = enabled;
366387

367-
@OnCheckedChanged(R.id.switch_night_mode)
368-
public void OnCheckedChangedEnableNightMode(CompoundButton button, boolean checked){
369-
if (isCreated) {
370388
// OutOfMemoryError can occur, try to free as many objects as possible 1st
371389
// note: the assistant animation might need to be unloaded prior to switching night mode
372390
sfxManager.reset();
373391
sfxManager = null;
374392
System.gc();
375393

376394
// now proceed with the night mode switch
377-
putBooleanSharedPref(SHARED_PREF_DARK_MODE, checked);
378-
AppCompatDelegate.setDefaultNightMode(checked ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
395+
AppCompatDelegate.setDefaultNightMode(enabled ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
379396
getDelegate().applyDayNight();
380397

381398
// re-init SFX manager

0 commit comments

Comments
 (0)