package net.osmand.plus.notifications;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.BigTextStyle;
import android.support.v4.app.NotificationCompat.Builder;
import android.view.View;
import net.osmand.plus.NavigationService;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.TargetPointsHelper.TargetPoint;
import net.osmand.plus.routing.RouteCalculationResult;
import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.TurnPathHelper;
import net.osmand.plus.views.mapwidgets.NextTurnInfoWidget.TurnDrawable;
import net.osmand.router.TurnType;
import net.osmand.util.Algorithms;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.NavigationService.USED_BY_NAVIGATION;
public class NavigationNotification extends OsmandNotification {
public final static String OSMAND_PAUSE_NAVIGATION_SERVICE_ACTION = "OSMAND_PAUSE_NAVIGATION_SERVICE_ACTION";
public final static String OSMAND_RESUME_NAVIGATION_SERVICE_ACTION = "OSMAND_RESUME_NAVIGATION_SERVICE_ACTION";
public final static String OSMAND_STOP_NAVIGATION_SERVICE_ACTION = "OSMAND_STOP_NAVIGATION_SERVICE_ACTION";
public final static String GROUP_NAME = "NAVIGATION";
private Map<TurnPathHelper.TurnResource, Bitmap> bitmapCache = new HashMap<>();
private Bitmap turnBitmap;
private boolean leftSide;
public NavigationNotification(OsmandApplication app) {
super(app, GROUP_NAME);
}
@Override
public void init() {
leftSide = app.getSettings().DRIVING_REGION.get().leftHandDriving;
app.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
RoutingHelper routingHelper = app.getRoutingHelper();
routingHelper.setRoutePlanningMode(true);
routingHelper.setFollowingMode(false);
routingHelper.setPauseNaviation(true);
}
}, new IntentFilter(OSMAND_PAUSE_NAVIGATION_SERVICE_ACTION));
app.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
RoutingHelper routingHelper = app.getRoutingHelper();
routingHelper.setRoutePlanningMode(false);
routingHelper.setFollowingMode(true);
}
}, new IntentFilter(OSMAND_RESUME_NAVIGATION_SERVICE_ACTION));
app.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
app.stopNavigation();
}
}, new IntentFilter(OSMAND_STOP_NAVIGATION_SERVICE_ACTION));
}
@Override
public NotificationType getType() {
return NotificationType.NAVIGATION;
}
@Override
public int getPriority() {
return NotificationCompat.PRIORITY_HIGH;
}
@Override
public boolean isActive() {
NavigationService service = app.getNavigationService();
return isEnabled()
&& service != null
&& (service.getUsedBy() & USED_BY_NAVIGATION) != 0;
}
@Override
public boolean isEnabled() {
RoutingHelper routingHelper = app.getRoutingHelper();
return routingHelper.isFollowingMode()
|| (routingHelper.isRoutePlanningMode() && routingHelper.isPauseNavigation());
}
@Override
public Builder buildNotification(boolean wearable) {
if (!isEnabled()) {
return null;
}
NavigationService service = app.getNavigationService();
String notificationTitle;
StringBuilder notificationText = new StringBuilder();
color = 0;
icon = R.drawable.ic_action_start_navigation;
turnBitmap = null;
ongoing = true;
RoutingHelper routingHelper = app.getRoutingHelper();
boolean followingMode = routingHelper.isFollowingMode() || app.getLocationProvider().getLocationSimulation().isRouteAnimating();
if (service != null && (service.getUsedBy() & USED_BY_NAVIGATION) != 0) {
color = app.getResources().getColor(R.color.osmand_orange);
String distanceStr = OsmAndFormatter.getFormattedDistance(app.getRoutingHelper().getLeftDistance(), app);
String timeStr = OsmAndFormatter.getFormattedDuration(app.getRoutingHelper().getLeftTime(), app);
String etaStr = SimpleDateFormat.getTimeInstance(DateFormat.SHORT)
.format(new Date(System.currentTimeMillis() + app.getRoutingHelper().getLeftTime() * 1000));
TurnType turnType = null;
boolean deviatedFromRoute;
int turnImminent = 0;
int nextTurnDistance = 0;
int nextNextTurnDistance = 0;
RouteDirectionInfo ri = null;
if (routingHelper.isRouteCalculated() && followingMode) {
deviatedFromRoute = routingHelper.isDeviatedFromRoute();
if (deviatedFromRoute) {
turnImminent = 0;
turnType = TurnType.valueOf(TurnType.OFFR, leftSide);
nextTurnDistance = (int) routingHelper.getRouteDeviation();
} else {
NextDirectionInfo calc1 = new NextDirectionInfo();
NextDirectionInfo r = routingHelper.getNextRouteDirectionInfo(calc1, true);
if (r != null && r.distanceTo > 0 && r.directionInfo != null) {
ri = r.directionInfo;
turnType = r.directionInfo.getTurnType();
nextTurnDistance = r.distanceTo;
turnImminent = r.imminent;
NextDirectionInfo next = routingHelper.getNextRouteDirectionInfoAfter(r, calc1, true);
nextNextTurnDistance = next.distanceTo;
}
}
if (turnType != null) {
TurnDrawable drawable = new TurnDrawable(app, false);
int height = (int) app.getResources().getDimension(android.R.dimen.notification_large_icon_height);
int width = (int) app.getResources().getDimension(android.R.dimen.notification_large_icon_width);
drawable.setBounds(0, 0, width, height);
drawable.setTurnType(turnType);
drawable.setTurnImminent(turnImminent, deviatedFromRoute);
turnBitmap = drawableToBitmap(drawable);
}
notificationTitle = OsmAndFormatter.getFormattedDistance(nextTurnDistance, app)
+ (turnType != null ? " • " + RouteCalculationResult.toString(turnType, app, true) : "");
if (ri != null && !Algorithms.isEmpty(ri.getDescriptionRoutePart())) {
notificationText.append(ri.getDescriptionRoutePart());
if (nextNextTurnDistance > 0) {
notificationText.append(" ").append(OsmAndFormatter.getFormattedDistance(nextNextTurnDistance, app));
}
notificationText.append("\n");
}
int distanceToNextIntermediate = routingHelper.getLeftDistanceNextIntermediate();
if (distanceToNextIntermediate > 0) {
int nextIntermediateIndex = routingHelper.getRoute().getNextIntermediate();
List<TargetPoint> intermediatePoints = app.getTargetPointsHelper().getIntermediatePoints();
if (nextIntermediateIndex < intermediatePoints.size()) {
TargetPoint nextIntermediate = intermediatePoints.get(nextIntermediateIndex);
notificationText.append(OsmAndFormatter.getFormattedDistance(distanceToNextIntermediate, app))
.append(" • ")
.append(nextIntermediate.getOnlyName());
notificationText.append("\n");
}
}
notificationText.append(distanceStr).append(" • ").append(timeStr).append(" • ").append(etaStr);
} else {
notificationTitle = app.getString(R.string.shared_string_navigation);
String error = routingHelper.getLastRouteCalcErrorShort();
if (Algorithms.isEmpty(error)) {
notificationText.append(app.getString(R.string.route_calculation)).append("...");
} else {
notificationText.append(error);
}
}
} else if (routingHelper.isRoutePlanningMode() && routingHelper.isPauseNavigation()) {
ongoing = false;
notificationTitle = app.getString(R.string.shared_string_navigation);
notificationText.append(app.getString(R.string.shared_string_paused));
} else {
return null;
}
final Builder notificationBuilder = createBuilder(wearable)
.setContentTitle(notificationTitle)
.setStyle(new BigTextStyle().bigText(notificationText))
.setLargeIcon(turnBitmap);
Intent stopIntent = new Intent(OSMAND_STOP_NAVIGATION_SERVICE_ACTION);
PendingIntent stopPendingIntent = PendingIntent.getBroadcast(app, 0, stopIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.addAction(R.drawable.ic_action_remove_dark,
app.getString(R.string.shared_string_control_stop), stopPendingIntent);
if (routingHelper.isRouteCalculated() && followingMode) {
Intent pauseIntent = new Intent(OSMAND_PAUSE_NAVIGATION_SERVICE_ACTION);
PendingIntent pausePendingIntent = PendingIntent.getBroadcast(app, 0, pauseIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.addAction(R.drawable.ic_pause,
app.getString(R.string.shared_string_pause), pausePendingIntent);
} else if (routingHelper.isRouteCalculated() && routingHelper.isPauseNavigation()) {
Intent resumeIntent = new Intent(OSMAND_RESUME_NAVIGATION_SERVICE_ACTION);
PendingIntent resumePendingIntent = PendingIntent.getBroadcast(app, 0, resumeIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.addAction(R.drawable.ic_play_dark,
app.getString(R.string.shared_string_continue), resumePendingIntent);
}
return notificationBuilder;
}
@Override
public void setupNotification(Notification notification) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int smallIconViewId = app.getResources().getIdentifier("right_icon", "id", android.R.class.getPackage().getName());
if (smallIconViewId != 0) {
if (notification.contentView != null)
notification.contentView.setViewVisibility(smallIconViewId, View.INVISIBLE);
if (notification.headsUpContentView != null)
notification.headsUpContentView.setViewVisibility(smallIconViewId, View.INVISIBLE);
if (notification.bigContentView != null)
notification.bigContentView.setViewVisibility(smallIconViewId, View.INVISIBLE);
}
}
}
public Bitmap drawableToBitmap(Drawable drawable) {
int height = (int) app.getResources().getDimension(android.R.dimen.notification_large_icon_height);
int width = (int) app.getResources().getDimension(android.R.dimen.notification_large_icon_width);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
@Override
public int getOsmandNotificationId() {
return NAVIGATION_NOTIFICATION_SERVICE_ID;
}
@Override
public int getOsmandWearableNotificationId() {
return WEAR_NAVIGATION_NOTIFICATION_SERVICE_ID;
}
}