Skip to content

Commit

Permalink
Persistent notification (#177)
Browse files Browse the repository at this point in the history
* persistent notification finished

* fixed notification image not getting upcoming step

* combined linear layouts

* fixed checkstyle

* finished fixing checkstyle
  • Loading branch information
Cameron Mace authored Aug 29, 2017
1 parent a3dc212 commit dc67c5c
Show file tree
Hide file tree
Showing 49 changed files with 1,124 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@android:style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
Expand All @@ -20,7 +21,6 @@
android:layout_height="match_parent"
android:layout_margin="16dp"
android:contentDescription="@string/app_name"
android:src="@drawable/ic_maneuver_starting"
android:tint="#ffffff"/>

<LinearLayout
Expand All @@ -35,21 +35,21 @@
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="250 ft"
tools:text="250 ft"
android:textColor="#ffffff"/>

<TextView
android:id="@+id/notificationStreetNameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sherman Ave NW"
tools:text="Sherman Ave NW"
android:textColor="#ffffff"
android:textStyle="bold"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="11:13 AM ETA"
tools:text="11:13 AM ETA"
android:textColor="#ffffff"
android:textSize="12sp"/>
</LinearLayout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,14 @@ public class NavigationConstants {
* Maximum angle the user puck will be rotated when snapping the user's course to the route line.
*/
static final int MAX_MANIPULATED_COURSE_ANGLE = 25;

// Step Maneuver Modifiers
public static final String STEP_MANEUVER_MODIFIER_UTURN = "uturn";
public static final String STEP_MANEUVER_MODIFIER_SHARP_RIGHT = "sharp right";
public static final String STEP_MANEUVER_MODIFIER_RIGHT = "right";
public static final String STEP_MANEUVER_MODIFIER_SLIGHT_RIGHT = "slight right";
public static final String STEP_MANEUVER_MODIFIER_STRAIGHT = "straight";
public static final String STEP_MANEUVER_MODIFIER_SLIGHT_LEFT = "slight left";
public static final String STEP_MANEUVER_MODIFIER_LEFT = "left";
public static final String STEP_MANEUVER_MODIFIER_SHARP_LEFT = "sharp left";
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,24 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.LayoutRes;
import android.support.v4.app.NotificationCompat;
import android.text.SpannableStringBuilder;
import android.widget.RemoteViews;

import com.mapbox.services.android.navigation.R;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;
import com.mapbox.services.android.navigation.v5.utils.StringUtils;
import com.mapbox.services.android.navigation.v5.utils.DistanceUtils;
import com.mapbox.services.android.navigation.v5.utils.ManeuverUtils;
import com.mapbox.services.android.navigation.v5.utils.abbreviation.StringAbbreviator;
import com.mapbox.services.api.directions.v5.models.LegStep;

import java.util.Calendar;
import java.util.Locale;

import static com.mapbox.services.android.navigation.v5.navigation.NavigationConstants.NAVIGATION_NOTIFICATION_ID;

Expand All @@ -20,43 +29,117 @@
*/
class NavigationNotification {

private static final String ROUTE_PROGRESS_STRING_FORMAT = "%tl:%tM %tp%n";
private static final String END_NAVIGATION_BUTTON_TAG = "endNavigationButtonTag";

private NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager;
private MapboxNavigation mapboxNavigation;
private RemoteViews remoteViewsBig;
private EndNavigationReceiver receiver;
private RemoteViews remoteViews;
private Context context;

NavigationNotification(Context context) {
NavigationNotification(Context context, MapboxNavigation mapboxNavigation) {
this.context = context;
this.mapboxNavigation = mapboxNavigation;
initialize();
}

private void initialize() {
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}

Notification buildPersistentNotification(@LayoutRes int layout) {
Notification buildPersistentNotification(@LayoutRes int layout, @LayoutRes int bigLayout) {
remoteViewsBig = new RemoteViews(context.getPackageName(), bigLayout);
remoteViews = new RemoteViews(context.getPackageName(), layout);

remoteViewsBig.setOnClickPendingIntent(R.id.endNavigationButton,
getPendingSelfIntent(context, END_NAVIGATION_BUTTON_TAG));

// Sets up the top bar notification
notificationBuilder = new NotificationCompat.Builder(context)
.setContent(remoteViews)
.setCustomBigContentView(remoteViewsBig)
.setSmallIcon(R.drawable.ic_navigation)
.setContentIntent(PendingIntent.getActivity(context, 0,
new Intent(context, NavigationService.class), 0));

IntentFilter filter = new IntentFilter(END_NAVIGATION_BUTTON_TAG);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new EndNavigationReceiver();
context.registerReceiver(receiver, filter);

return notificationBuilder.build();
}

void onDestroy() {
try {
context.unregisterReceiver(receiver);
} catch (Exception exception) {
// Empty
}
}

void updateDefaultNotification(RouteProgress routeProgress) {
// Street name
remoteViews.setTextViewText(
R.id.notificationStreetNameTextView,
routeProgress.currentLegProgress().currentStep().getName()
StringAbbreviator.deliminator(
StringAbbreviator.abbreviate(routeProgress.currentLegProgress().currentStep().getName()))
);
remoteViews.setTextViewText(
R.id.notificationStepDistanceTextView,
StringUtils.distanceFormatter(routeProgress.currentLegProgress().currentStepProgress().distanceRemaining())
remoteViewsBig.setTextViewText(
R.id.notificationStreetNameTextView,
StringAbbreviator.deliminator(
StringAbbreviator.abbreviate(routeProgress.currentLegProgress().currentStep().getName()))
);
// remoteViews.setImageViewResource();

// Distance
SpannableStringBuilder distanceSpannableStringBuilder = DistanceUtils.distanceFormatterBold(
routeProgress.currentLegProgress().currentStepProgress().distanceRemaining()
);

remoteViewsBig.setTextViewText(R.id.notificationStepDistanceTextView, DistanceUtils.distanceFormatterBold(
routeProgress.currentLegProgress().currentStepProgress().distanceRemaining()));

if (routeProgress.currentLegProgress().currentStep().getName() != null) {
if (!routeProgress.currentLegProgress().currentStep().getName().isEmpty()) {
distanceSpannableStringBuilder.append(" - ");
}
}
remoteViews.setTextViewText(R.id.notificationStepDistanceTextView, distanceSpannableStringBuilder);

String arrivalTime = String.format(Locale.US, "Arrive at %s",
formatArrivalTime(routeProgress.durationRemaining()));
remoteViews.setTextViewText(R.id.estimatedArrivalTimeTextView, arrivalTime);
remoteViewsBig.setTextViewText(R.id.estimatedArrivalTimeTextView, arrivalTime);

LegStep step = routeProgress.currentLegProgress().upComingStep() == null
? routeProgress.currentLegProgress().currentStep() : routeProgress.currentLegProgress().upComingStep();

remoteViews.setImageViewResource(R.id.maneuverSignal, ManeuverUtils.getManeuverResource(step));
remoteViewsBig.setImageViewResource(R.id.maneuverSignal, ManeuverUtils.getManeuverResource(step));
notificationManager.notify(NAVIGATION_NOTIFICATION_ID, notificationBuilder.build());
}

private static String formatArrivalTime(double routeDuration) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, (int) routeDuration);

return String.format(Locale.US, ROUTE_PROGRESS_STRING_FORMAT,
calendar, calendar, calendar);
}

private PendingIntent getPendingSelfIntent(Context context, String action) {
Intent intent = new Intent(END_NAVIGATION_BUTTON_TAG);
intent.setAction(action);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}

public class EndNavigationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
mapboxNavigation.endNavigation();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
@Override
public void onDestroy() {
endNavigation();
notificationManager.onDestroy();
super.onDestroy();
}

Expand All @@ -95,9 +96,10 @@ void startNavigation(MapboxNavigation mapboxNavigation) {
* builds a new navigation notification instance and attaches it to this service.
*/
private void initializeNotification() {
notificationManager = new NavigationNotification(this);
notificationManager = new NavigationNotification(this, mapboxNavigation);
Notification notifyBuilder
= notificationManager.buildPersistentNotification(R.layout.layout_notification_default);
= notificationManager.buildPersistentNotification(R.layout.layout_notification_default,
R.layout.layout_notification_default_big);
startForeground(NAVIGATION_NOTIFICATION_ID, notifyBuilder);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.mapbox.services.android.navigation.v5.utils;

import android.text.Spannable;
import android.text.SpannableStringBuilder;

import com.mapbox.services.api.utils.turf.TurfConstants;
import com.mapbox.services.api.utils.turf.TurfHelpers;

import java.text.DecimalFormat;
import java.util.Locale;

public class DistanceUtils {

private static final String DECIMAL_FORMAT = "#.#";
private static final String MILE_FORMAT = "%s mi";
private static final String FEET_FORMAT = "%s ft";

public static SpannableStringBuilder distanceFormatterBold(double distance) {
SpannableStringBuilder formattedString;
if (longDistance(distance)) {
formattedString = roundToNearestMile(distance);
} else if (mediumDistance(distance)) {
formattedString = roundOneDecimalPlace(distance);
} else {
formattedString = roundByFiftyFeet(distance);
}
return formattedString;
}

private static SpannableStringBuilder roundByFiftyFeet(double distance) {
distance = TurfHelpers.convertDistance(distance, TurfConstants.UNIT_METERS, TurfConstants.UNIT_FEET);
int roundedNumber = ((int) Math.round(distance)) / 50 * 50;

SpannableStringBuilder formattedString
= new SpannableStringBuilder(String.format(Locale.US, FEET_FORMAT, roundedNumber));
formattedString.setSpan(
new android.text.style.StyleSpan(android.graphics.Typeface.BOLD),
0, String.valueOf(roundedNumber).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return formattedString;
}

private static SpannableStringBuilder roundOneDecimalPlace(double distance) {
distance = TurfHelpers.convertDistance(distance, TurfConstants.UNIT_METERS, TurfConstants.UNIT_MILES);
DecimalFormat df = new DecimalFormat(DECIMAL_FORMAT);
double roundedNumber = (distance / 100 * 100);
SpannableStringBuilder formattedString = new SpannableStringBuilder(String.format(Locale.US,
MILE_FORMAT, df.format(roundedNumber)));
formattedString.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD),
0, df.format(roundedNumber).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return formattedString;
}

private static boolean mediumDistance(double distance) {
return TurfHelpers.convertDistance(distance, TurfConstants.UNIT_METERS, TurfConstants.UNIT_MILES) < 10
&& TurfHelpers.convertDistance(distance, TurfConstants.UNIT_METERS, TurfConstants.UNIT_FEET) > 401;
}

private static SpannableStringBuilder roundToNearestMile(double distance) {
distance = TurfHelpers.convertDistance(distance, TurfConstants.UNIT_METERS, TurfConstants.UNIT_MILES);
SpannableStringBuilder formattedString
= new SpannableStringBuilder(String.format(Locale.US, MILE_FORMAT, (int) Math.round(distance)));
formattedString.setSpan(new android.text.style.StyleSpan(android.graphics.Typeface.BOLD),
0, String.valueOf((int) Math.round(distance)).length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return formattedString;
}

private static boolean longDistance(double distance) {
return TurfHelpers.convertDistance(distance, TurfConstants.UNIT_METERS, TurfConstants.UNIT_MILES) > 10;
}
}
Loading

0 comments on commit dc67c5c

Please sign in to comment.