Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BOT-320/Feature menu #321

Merged
merged 11 commits into from
Aug 30, 2017
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
import com.novoda.tpbot.controls.ControllerListener;
import com.novoda.tpbot.controls.ControllerView;
import com.novoda.tpbot.controls.ServerDeclarationView;
import com.novoda.tpbot.feature_selection.FeatureSelectionPersistence;
import com.novoda.tpbot.feature_selection.ServerConnectionSharedPreferencesPersistence;
import com.novoda.tpbot.feature_selection.VideoCallSharedPreferencesPersistence;

import java.util.HashMap;

Expand All @@ -45,9 +48,15 @@ public class BotActivity extends AppCompatActivity implements BotView {
private AutomationChecker automationChecker;
private BotServiceCreator botServiceCreator;

private FeatureSelectionPersistence videoCallFeature;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

videoCallFeature = VideoCallSharedPreferencesPersistence.newInstance(this);
FeatureSelectionPersistence serverConnectionFeature = ServerConnectionSharedPreferencesPersistence.newInstance(this);

setContentView(R.layout.activity_bot);

debugView = Views.findById(this, R.id.bot_controller_debug_view);
Expand All @@ -64,12 +73,16 @@ protected void onCreate(Bundle savedInstanceState) {

AccessibilityManager accessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
automationChecker = new AutomationChecker(accessibilityManager);

if (!serverConnectionFeature.isFeatureEnabled()) {
switchableView.setDisplayedChild(1);
}
}

@Override
protected void onResume() {
super.onResume();
if (!automationChecker.isHangoutJoinerAutomationServiceEnabled()) {
if (!automationChecker.isHangoutJoinerAutomationServiceEnabled() && videoCallFeature.isFeatureEnabled()) {
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
}
}
Expand Down Expand Up @@ -205,7 +218,9 @@ public void onConnect(String room, String serverAddress) {
debugView.showPermanently(getString(R.string.connected));
switchableView.setDisplayedChild(1);

joinHangoutRoom(room);
if (videoCallFeature.isFeatureEnabled()) {
joinHangoutRoom(room);
}
}

private void joinHangoutRoom(String room) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import android.os.Handler;
import android.os.Looper;

import com.novoda.tpbot.Direction;
import com.novoda.tpbot.Result;
import com.novoda.support.Observable;
import com.novoda.tpbot.ClientType;
import com.novoda.tpbot.Direction;
import com.novoda.tpbot.Event;
import com.novoda.tpbot.MalformedServerAddressException;
import com.novoda.support.Observable;
import com.novoda.tpbot.Result;
import com.novoda.tpbot.Room;
import com.novoda.tpbot.SocketConnectionObservable;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.novoda.tpbot.feature_selection;

public interface FeatureSelectionController<LIST, FEATURE> {

void attachFeatureSelectionTo(LIST toAttachTo);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to make the feature selection menu as generic as possible so that it can be swapped out if necessary. The goal is to have most code live in core and only expose android when we need to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of this interface, the LIST is the thing you want to attach each feature item to. FEATURE is the representation of the feature stored in the list. In android this will be the menuItem but could easily be an enum or anything else.


void handleFeatureToggle(FEATURE featureRepresentation);

boolean contains(FEATURE featureRepresentation);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.novoda.tpbot.feature_selection;

public interface FeatureSelectionPersistence {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ATM the persistence is SharedPreferences but we should be able to swap it out.


boolean isFeatureEnabled();

void setFeatureEnabled();

void setFeatureDisabled();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.novoda.tpbot.feature_selection;

import android.content.Context;
import android.support.annotation.MenuRes;
import android.util.SparseArray;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import com.novoda.tpbot.R;

public final class MenuFeatureSelectionController implements FeatureSelectionController<Menu, MenuItem> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handles the inflation of the Menu and the individual MenuItems. This class also handles the toggle of menu items.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want to try and remove as much code from the activity as possible.


@MenuRes
private static final int FEATURE_MENU_RESOURCE = R.menu.feature_menu;

private final MenuInflater menuInflater;
private final SparseArray<FeatureSelectionPersistence> features;

public static FeatureSelectionController<Menu, MenuItem> createFrom(Context context) {
MenuInflater menuInflater = new MenuInflater(context);

SparseArray<FeatureSelectionPersistence> features = new SparseArray<>();
features.put(R.id.video_call_menu_item, VideoCallSharedPreferencesPersistence.newInstance(context));
features.put(R.id.server_connection_menu_item, ServerConnectionSharedPreferencesPersistence.newInstance(context));

return new MenuFeatureSelectionController(menuInflater, features);
}

private MenuFeatureSelectionController(MenuInflater menuInflater, SparseArray<FeatureSelectionPersistence> features) {
this.menuInflater = menuInflater;
this.features = features;
}

@Override
public void attachFeatureSelectionTo(Menu toAttachTo) {
menuInflater.inflate(FEATURE_MENU_RESOURCE, toAttachTo);

for (int index = 0; index < features.size(); index++) {
int key = features.keyAt(index);

MenuItem menuItem = toAttachTo.findItem(key);
FeatureSelectionPersistence featureSelectionPersistence = features.get(key);
menuItem.setChecked(featureSelectionPersistence.isFeatureEnabled());
}
}

@Override
public void handleFeatureToggle(MenuItem featureRepresentation) {
FeatureSelectionPersistence featureSelectionPersistence = features.get(featureRepresentation.getItemId());

if (featureSelectionPersistence == null) {
throw new IllegalStateException("You must check if data is present before using handleFeatureToggle().");
}

if (featureSelectionPersistence.isFeatureEnabled()) {
featureRepresentation.setChecked(false);
featureSelectionPersistence.setFeatureDisabled();
} else {
featureRepresentation.setChecked(true);
featureSelectionPersistence.setFeatureEnabled();
}
}

@Override
public boolean contains(MenuItem featureRepresentation) {
return features.get(featureRepresentation.getItemId()) != null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.novoda.tpbot.feature_selection;

import android.content.Context;
import android.content.SharedPreferences;

public final class ServerConnectionSharedPreferencesPersistence implements FeatureSelectionPersistence {

private static final String SERVER_CONNECTION_PREF_NAME = "server_connection";
private static final String SERVER_CONNECTION_PREFERENCES_ON_OFF_KEY = "server_connection_preferences_on_off";
private static final boolean ON = true;
private static final boolean OFF = false;

private final SharedPreferences sharedPreferences;

public static ServerConnectionSharedPreferencesPersistence newInstance(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(SERVER_CONNECTION_PREF_NAME, Context.MODE_PRIVATE);
return new ServerConnectionSharedPreferencesPersistence(sharedPreferences);
}

private ServerConnectionSharedPreferencesPersistence(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
}

@Override
public boolean isFeatureEnabled() {
return sharedPreferences.getBoolean(SERVER_CONNECTION_PREFERENCES_ON_OFF_KEY, OFF);
}

@Override
public void setFeatureEnabled() {
sharedPreferences.edit()
.putBoolean(SERVER_CONNECTION_PREFERENCES_ON_OFF_KEY, ON)
.apply();
}

@Override
public void setFeatureDisabled() {
sharedPreferences.edit()
.putBoolean(SERVER_CONNECTION_PREFERENCES_ON_OFF_KEY, OFF)
.apply();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.novoda.tpbot.feature_selection;

import android.content.Context;
import android.content.SharedPreferences;

public final class VideoCallSharedPreferencesPersistence implements FeatureSelectionPersistence {

private static final String VIDEO_CALL_PREF_NAME = "video_call";
private static final String VIDEO_CALL_PREFERENCES_ON_OFF_KEY = "video_call_preferences_on_off";
private static final boolean ON = true;
private static final boolean OFF = false;

private final SharedPreferences sharedPreferences;

public static VideoCallSharedPreferencesPersistence newInstance(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(VIDEO_CALL_PREF_NAME, Context.MODE_PRIVATE);
return new VideoCallSharedPreferencesPersistence(sharedPreferences);
}

private VideoCallSharedPreferencesPersistence(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
}

@Override
public boolean isFeatureEnabled() {
return sharedPreferences.getBoolean(VIDEO_CALL_PREFERENCES_ON_OFF_KEY, OFF);
}

@Override
public void setFeatureEnabled() {
sharedPreferences.edit()
.putBoolean(VIDEO_CALL_PREFERENCES_ON_OFF_KEY, ON)
.apply();
}

@Override
public void setFeatureDisabled() {
sharedPreferences.edit()
.putBoolean(VIDEO_CALL_PREFERENCES_ON_OFF_KEY, OFF)
.apply();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ protected void onCreate(Bundle savedInstanceState) {
ServerDeclarationView serverDeclarationView = Views.findById(switchableView, R.id.bot_server_declaration_view);
serverDeclarationView.setServerDeclarationListener(serverDeclarationListener);


Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just auto-formatting 😄

}

private final CommandRepeater.Listener commandRepeatedListener = new CommandRepeater.Listener() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import android.os.Handler;
import android.os.Looper;

import com.novoda.tpbot.Direction;
import com.novoda.tpbot.Result;
import com.novoda.support.Observable;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just auto-formatting 😄

import com.novoda.tpbot.ClientType;
import com.novoda.tpbot.Direction;
import com.novoda.tpbot.Event;
import com.novoda.tpbot.MalformedServerAddressException;
import com.novoda.support.Observable;
import com.novoda.tpbot.Result;
import com.novoda.tpbot.Room;
import com.novoda.tpbot.SocketConnectionObservable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import com.novoda.tpbot.R;
import com.novoda.tpbot.bot.BotActivity;
import com.novoda.tpbot.feature_selection.FeatureSelectionController;
import com.novoda.tpbot.feature_selection.MenuFeatureSelectionController;
import com.novoda.tpbot.human.HumanActivity;

public class LandingActivity extends AppCompatActivity {

private FeatureSelectionController<Menu, MenuItem> featureSelectionController;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
featureSelectionController = MenuFeatureSelectionController.createFrom(this);

setContentView(R.layout.activity_landing);

View humanSelection = findViewById(R.id.human_selection);
Expand All @@ -39,4 +47,19 @@ public void onClick(View v) {
}
};

@Override
public boolean onCreateOptionsMenu(Menu menu) {
featureSelectionController.attachFeatureSelectionTo(menu);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So little code in the activity now for MenuItems ✨

return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (featureSelectionController.contains(item)) {
featureSelectionController.handleFeatureToggle(item);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
}
19 changes: 19 additions & 0 deletions TelepresenceBot/mobile/src/main/res/menu/feature_menu.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/video_call_menu_item"
android:icon="@android:drawable/checkbox_on_background"
android:title="@string/automatically_join_video_call"
android:checkable="true"
app:showAsAction="never" />

<item
android:id="@+id/server_connection_menu_item"
android:icon="@android:drawable/checkbox_on_background"
android:title="@string/connect_to_server"
android:checkable="true"
app:showAsAction="never" />

</menu>
2 changes: 2 additions & 0 deletions TelepresenceBot/mobile/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<string name="bot">Bot</string>
<string name="human">Human</string>
<string name="list_connected_devices_menu_item_title">List connected devices</string>
<string name="automatically_join_video_call">Automatically join video call</string>
<string name="connect_to_server">Connect to server</string>
<string name="usb_device_name_vendor_product">%1$s, VendorId=%2$d, ProductId=%3$d</string>
<string name="no_connected_devices">No connected USB devices</string>
<string name="enter_server_address">Enter server address: </string>
Expand Down