[android-auto] Add Screens
Add Settings, Bookmarks, Categories, Search screens. Signed-off-by: Andrew Shkrob <andrew.shkrob.social@yandex.by>
This commit is contained in:
parent
19ab52216b
commit
ba62a208c4
16 changed files with 915 additions and 100 deletions
5
android/res/drawable/ic_check_box.xml
Normal file
5
android/res/drawable/ic_check_box.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19,5v14H5V5h14m0,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
5
android/res/drawable/ic_check_box_checked.xml
Normal file
5
android/res/drawable/ic_check_box_checked.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.11,0 2,-0.9 2,-2L21,5c0,-1.1 -0.89,-2 -2,-2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
|
||||
</vector>
|
|
@ -7,11 +7,8 @@ import androidx.car.app.CarAppService;
|
|||
import androidx.car.app.Session;
|
||||
import androidx.car.app.validation.HostValidator;
|
||||
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class NavigationCarAppService extends CarAppService
|
||||
{
|
||||
@NonNull
|
||||
|
@ -34,13 +31,6 @@ public final class NavigationCarAppService extends CarAppService
|
|||
@Override
|
||||
public Session onCreateSession()
|
||||
{
|
||||
try
|
||||
{
|
||||
MwmApplication.from(getApplicationContext()).init();
|
||||
} catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new NavigationSession();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
package app.organicmaps.car;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.CarToast;
|
||||
import androidx.car.app.Screen;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.ActionStrip;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.NavigationTemplate;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.location.LocationHelper;
|
||||
import app.organicmaps.util.LocationUtils;
|
||||
|
||||
public class NavigationScreen extends Screen
|
||||
{
|
||||
private static final String TAG = NavigationScreen.class.getSimpleName();
|
||||
|
||||
@NonNull
|
||||
private final SurfaceRenderer mSurfaceRenderer;
|
||||
|
||||
protected NavigationScreen(@NonNull CarContext carContext, @NonNull SurfaceRenderer surfaceRenderer)
|
||||
{
|
||||
super(carContext);
|
||||
mSurfaceRenderer = surfaceRenderer;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
Log.d(TAG, "onGetTemplate");
|
||||
NavigationTemplate.Builder builder = new NavigationTemplate.Builder();
|
||||
ActionStrip.Builder actionStripBuilder = new ActionStrip.Builder();
|
||||
actionStripBuilder.addAction(new Action.Builder().setIcon(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_settings)).build())
|
||||
.setOnClickListener(this::settings)
|
||||
.build());
|
||||
|
||||
Action panAction = new Action.Builder(Action.PAN).build();
|
||||
Action location = new Action.Builder().setIcon(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_not_follow)).build())
|
||||
.setOnClickListener(this::location)
|
||||
.build();
|
||||
Action zoomIn = new Action.Builder().setIcon(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_plus)).build())
|
||||
.setOnClickListener(this::zoomIn)
|
||||
.build();
|
||||
Action zoomOut = new Action.Builder().setIcon(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_minus)).build())
|
||||
.setOnClickListener(this::zoomOut)
|
||||
.build();
|
||||
|
||||
ActionStrip mapActionStrip = new ActionStrip.Builder().addAction(location)
|
||||
.addAction(zoomIn)
|
||||
.addAction(zoomOut)
|
||||
.addAction(panAction)
|
||||
.build();
|
||||
builder.setMapActionStrip(mapActionStrip);
|
||||
builder.setActionStrip(actionStripBuilder.build());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void location()
|
||||
{
|
||||
CarToast.makeText(getCarContext(), "Location", CarToast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void zoomOut()
|
||||
{
|
||||
mSurfaceRenderer.onZoomOut();
|
||||
}
|
||||
|
||||
private void zoomIn()
|
||||
{
|
||||
mSurfaceRenderer.onZoomIn();
|
||||
}
|
||||
|
||||
private void settings()
|
||||
{
|
||||
CarToast.makeText(getCarContext(), "Settings", CarToast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
|
@ -1,22 +1,122 @@
|
|||
package app.organicmaps.car;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.car.app.CarToast;
|
||||
import androidx.car.app.Screen;
|
||||
import androidx.car.app.ScreenManager;
|
||||
import androidx.car.app.Session;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.ActionStrip;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.navigation.model.MapController;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
||||
public final class NavigationSession extends Session
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.car.screens.ErrorScreen;
|
||||
import app.organicmaps.car.screens.NavigationScreen;
|
||||
import app.organicmaps.car.screens.settings.SettingsScreen;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class NavigationSession extends Session implements DefaultLifecycleObserver
|
||||
{
|
||||
@Nullable
|
||||
private SurfaceRenderer mNavigationSurface;
|
||||
private static final String TAG = NavigationSession.class.getSimpleName();
|
||||
|
||||
|
||||
private OMController mMapController;
|
||||
|
||||
boolean mInitFailed = false;
|
||||
|
||||
public NavigationSession()
|
||||
{
|
||||
getLifecycle().addObserver(this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Screen onCreateScreen(@NonNull Intent intent)
|
||||
{
|
||||
mNavigationSurface = new SurfaceRenderer(getCarContext(), getLifecycle());
|
||||
return new NavigationScreen(getCarContext(), mNavigationSurface);
|
||||
Log.d(TAG, "onCreateScreen()");
|
||||
if (mInitFailed)
|
||||
return new ErrorScreen(getCarContext());
|
||||
|
||||
createMapController();
|
||||
return new NavigationScreen(getCarContext(), mMapController);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@NonNull LifecycleOwner owner)
|
||||
{
|
||||
Log.d(TAG, "onCreate()");
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(@NonNull LifecycleOwner owner)
|
||||
{
|
||||
Log.d(TAG, "onResume()");
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
mInitFailed = false;
|
||||
MwmApplication app = MwmApplication.from(getCarContext());
|
||||
try
|
||||
{
|
||||
app.init();
|
||||
} catch (IOException e)
|
||||
{
|
||||
mInitFailed = true;
|
||||
Log.e(TAG, "Failed to initialize the app.");
|
||||
}
|
||||
}
|
||||
|
||||
private void createMapController()
|
||||
{
|
||||
final CarIcon iconPlus = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_plus)).build();
|
||||
final CarIcon iconMinus = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_minus)).build();
|
||||
final CarIcon iconLocation = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_not_follow)).build();
|
||||
final CarIcon iconSettings = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_settings)).build();
|
||||
|
||||
SurfaceRenderer surfaceRenderer = new SurfaceRenderer(getCarContext(), getLifecycle());
|
||||
|
||||
Action panAction = new Action.Builder(Action.PAN).build();
|
||||
Action location = new Action.Builder().setIcon(iconLocation).setOnClickListener(this::location).build();
|
||||
Action zoomIn = new Action.Builder().setIcon(iconPlus).setOnClickListener(this::zoomIn).build();
|
||||
Action zoomOut = new Action.Builder().setIcon(iconMinus).setOnClickListener(this::zoomOut).build();
|
||||
ActionStrip mapActionStrip = new ActionStrip.Builder().addAction(location).addAction(zoomIn).addAction(zoomOut).addAction(panAction).build();
|
||||
MapController mapController = new MapController.Builder().setMapActionStrip(mapActionStrip).build();
|
||||
|
||||
Action settings = new Action.Builder().setIcon(iconSettings).setOnClickListener(this::openSettings).build();
|
||||
ActionStrip actionStrip = new ActionStrip.Builder().addAction(settings).build();
|
||||
|
||||
mMapController = new OMController(surfaceRenderer, mapController, actionStrip);
|
||||
}
|
||||
|
||||
private void location()
|
||||
{
|
||||
CarToast.makeText(getCarContext(), "Location", CarToast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void zoomOut()
|
||||
{
|
||||
mMapController.getSurfaceRenderer().onZoomOut();
|
||||
}
|
||||
|
||||
private void zoomIn()
|
||||
{
|
||||
mMapController.getSurfaceRenderer().onZoomIn();
|
||||
}
|
||||
|
||||
private void openSettings()
|
||||
{
|
||||
getCarContext().getCarService(ScreenManager.class).push(new SettingsScreen(getCarContext(), mMapController));
|
||||
}
|
||||
}
|
||||
|
|
40
android/src/app/organicmaps/car/OMController.java
Normal file
40
android/src/app/organicmaps/car/OMController.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package app.organicmaps.car;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.model.ActionStrip;
|
||||
import androidx.car.app.navigation.model.MapController;
|
||||
|
||||
public class OMController
|
||||
{
|
||||
@NonNull
|
||||
private final SurfaceRenderer mSurfaceRenderer;
|
||||
@NonNull
|
||||
private final MapController mMapController;
|
||||
@NonNull
|
||||
private final ActionStrip mActionStrip;
|
||||
|
||||
public OMController(@NonNull SurfaceRenderer surfaceRenderer, @NonNull MapController mapController, @NonNull ActionStrip actionStrip)
|
||||
{
|
||||
mSurfaceRenderer = surfaceRenderer;
|
||||
mMapController = mapController;
|
||||
mActionStrip = actionStrip;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SurfaceRenderer getSurfaceRenderer()
|
||||
{
|
||||
return mSurfaceRenderer;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MapController getMapController()
|
||||
{
|
||||
return mMapController;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ActionStrip getActionStrip()
|
||||
{
|
||||
return mActionStrip;
|
||||
}
|
||||
}
|
80
android/src/app/organicmaps/car/UiHelpers.java
Normal file
80
android/src/app/organicmaps/car/UiHelpers.java
Normal file
|
@ -0,0 +1,80 @@
|
|||
package app.organicmaps.car;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.ScreenManager;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.routing.RoutingOptions;
|
||||
import app.organicmaps.settings.RoadType;
|
||||
|
||||
public final class UiHelpers
|
||||
{
|
||||
public interface PrefsGetter
|
||||
{
|
||||
boolean get();
|
||||
}
|
||||
|
||||
public interface PrefsSetter
|
||||
{
|
||||
void set(boolean newValue);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static CarIcon mCheckboxIcon;
|
||||
@Nullable
|
||||
private static CarIcon mCheckboxSelectedIcon;
|
||||
|
||||
@NonNull
|
||||
public static Row createSharedPrefsCheckbox(
|
||||
@NonNull CarContext context, @StringRes int titleRes, PrefsGetter getter, PrefsSetter setter)
|
||||
{
|
||||
if (mCheckboxIcon == null || mCheckboxSelectedIcon == null)
|
||||
initCheckboxIcons(context);
|
||||
Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(context.getString(titleRes));
|
||||
builder.setOnClickListener(() -> {
|
||||
setter.set(!getter.get());
|
||||
context.getCarService(ScreenManager.class).getTop().invalidate();
|
||||
});
|
||||
if (getter.get())
|
||||
builder.setImage(mCheckboxSelectedIcon);
|
||||
else
|
||||
builder.setImage(mCheckboxIcon);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Row createDrivingOptionCheckbox(
|
||||
@NonNull CarContext context, RoadType roadType, @StringRes int titleRes)
|
||||
{
|
||||
if (mCheckboxIcon == null || mCheckboxSelectedIcon == null)
|
||||
initCheckboxIcons(context);
|
||||
Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(context.getString(titleRes));
|
||||
builder.setOnClickListener(() -> {
|
||||
if (RoutingOptions.hasOption(roadType))
|
||||
RoutingOptions.removeOption(roadType);
|
||||
else
|
||||
RoutingOptions.addOption(roadType);
|
||||
context.getCarService(ScreenManager.class).getTop().invalidate();
|
||||
});
|
||||
if (RoutingOptions.hasOption(roadType))
|
||||
builder.setImage(mCheckboxSelectedIcon);
|
||||
else
|
||||
builder.setImage(mCheckboxIcon);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static void initCheckboxIcons(@NonNull CarContext context)
|
||||
{
|
||||
mCheckboxIcon = new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_check_box)).build();
|
||||
mCheckboxSelectedIcon = new CarIcon.Builder(IconCompat.createWithResource(context, R.drawable.ic_check_box_checked)).build();
|
||||
}
|
||||
}
|
140
android/src/app/organicmaps/car/screens/BookmarksScreen.java
Normal file
140
android/src/app/organicmaps/car/screens/BookmarksScreen.java
Normal file
|
@ -0,0 +1,140 @@
|
|||
package app.organicmaps.car.screens;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.constraints.ConstraintManager;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapTemplate;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.bookmarks.data.BookmarkCategory;
|
||||
import app.organicmaps.bookmarks.data.BookmarkInfo;
|
||||
import app.organicmaps.bookmarks.data.BookmarkManager;
|
||||
import app.organicmaps.car.OMController;
|
||||
import app.organicmaps.util.Graphics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BookmarksScreen extends MapScreen
|
||||
{
|
||||
private final int MAX_CATEGORIES_SIZE;
|
||||
|
||||
@Nullable
|
||||
private BookmarkCategory mBookmarkCategory;
|
||||
|
||||
public BookmarksScreen(@NonNull CarContext carContext, @NonNull OMController mapController)
|
||||
{
|
||||
super(carContext, mapController);
|
||||
MAX_CATEGORIES_SIZE = getCarContext().getCarService(ConstraintManager.class).getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_LIST);
|
||||
}
|
||||
|
||||
private BookmarksScreen(@NonNull CarContext carContext, @NonNull OMController mapController, @NonNull BookmarkCategory bookmarkCategory)
|
||||
{
|
||||
this(carContext, mapController);
|
||||
mBookmarkCategory = bookmarkCategory;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
|
||||
MapTemplate.Builder builder = new MapTemplate.Builder();
|
||||
builder.setHeader(createHeader());
|
||||
builder.setMapController(getMapController());
|
||||
builder.setActionStrip(getActionStrip());
|
||||
if (mBookmarkCategory == null)
|
||||
builder.setItemList(createBookmarkCategoriesList());
|
||||
else
|
||||
builder.setItemList(createBookmarksList());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Header createHeader()
|
||||
{
|
||||
Header.Builder builder = new Header.Builder();
|
||||
builder.setStartHeaderAction(Action.BACK);
|
||||
if (mBookmarkCategory == null)
|
||||
builder.setTitle(getCarContext().getString(R.string.bookmarks));
|
||||
else
|
||||
builder.setTitle(mBookmarkCategory.getName());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ItemList createBookmarkCategoriesList()
|
||||
{
|
||||
final List<BookmarkCategory> bookmarkCategories = getBookmarks();
|
||||
final int categoriesSize = Math.min(bookmarkCategories.size(), MAX_CATEGORIES_SIZE);
|
||||
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
for (int i = 0; i < categoriesSize; ++i)
|
||||
{
|
||||
final BookmarkCategory bookmarkCategory = bookmarkCategories.get(i);
|
||||
|
||||
Row.Builder itemBuilder = new Row.Builder();
|
||||
itemBuilder.setTitle(bookmarkCategory.getName());
|
||||
itemBuilder.addText(bookmarkCategory.getDescription());
|
||||
itemBuilder.setOnClickListener(() -> getScreenManager().push(new BookmarksScreen(getCarContext(), getOMController(), bookmarkCategory)));
|
||||
itemBuilder.setBrowsable(true);
|
||||
builder.addItem(itemBuilder.build());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ItemList createBookmarksList()
|
||||
{
|
||||
final long bookmarkCategoryId = mBookmarkCategory.getId();
|
||||
final int bookmarkCategoriesSize = Math.min(mBookmarkCategory.getBookmarksCount(), MAX_CATEGORIES_SIZE);
|
||||
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
for (int i = 0; i < bookmarkCategoriesSize; ++i)
|
||||
{
|
||||
final long bookmarkId = BookmarkManager.INSTANCE.getBookmarkIdByPosition(bookmarkCategoryId, i);
|
||||
final BookmarkInfo bookmarkInfo = new BookmarkInfo(bookmarkCategoryId, bookmarkId);
|
||||
|
||||
Row.Builder itemBuilder = new Row.Builder();
|
||||
itemBuilder.setTitle(bookmarkInfo.getName());
|
||||
if (!bookmarkInfo.getAddress().isEmpty())
|
||||
itemBuilder.addText(bookmarkInfo.getAddress());
|
||||
if (!bookmarkInfo.getFeatureType().isEmpty())
|
||||
itemBuilder.addText(bookmarkInfo.getFeatureType());
|
||||
final Drawable icon = Graphics.drawCircleAndImage(bookmarkInfo.getIcon().argb(),
|
||||
R.dimen.track_circle_size,
|
||||
bookmarkInfo.getIcon().getResId(),
|
||||
R.dimen.bookmark_icon_size,
|
||||
getCarContext());
|
||||
itemBuilder.setImage(new CarIcon.Builder(IconCompat.createWithBitmap(Graphics.drawableToBitmap(icon))).build());
|
||||
builder.addItem(itemBuilder.build());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static List<BookmarkCategory> getBookmarks()
|
||||
{
|
||||
List<BookmarkCategory> bookmarkCategories = new ArrayList<>(BookmarkManager.INSTANCE.getCategories());
|
||||
|
||||
List<BookmarkCategory> toRemove = new ArrayList<>();
|
||||
for (BookmarkCategory bookmarkCategory : bookmarkCategories)
|
||||
{
|
||||
if (bookmarkCategory.getBookmarksCount() == 0)
|
||||
toRemove.add(bookmarkCategory);
|
||||
}
|
||||
bookmarkCategories.removeAll(toRemove);
|
||||
|
||||
return bookmarkCategories;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package app.organicmaps.car.screens;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.constraints.ConstraintManager;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapTemplate;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.car.OMController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CategoriesScreen extends MapScreen
|
||||
{
|
||||
private static class CategoryData
|
||||
{
|
||||
@StringRes
|
||||
public final int nameResId;
|
||||
|
||||
@DrawableRes
|
||||
public final int iconResId;
|
||||
|
||||
public CategoryData(int nameResId, int iconResId)
|
||||
{
|
||||
this.nameResId = nameResId;
|
||||
this.iconResId = iconResId;
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<CategoryData> CATEGORIES = Arrays.asList(
|
||||
new CategoryData(R.string.fuel, R.drawable.ic_category_fuel),
|
||||
new CategoryData(R.string.parking, R.drawable.ic_category_parking),
|
||||
new CategoryData(R.string.eat, R.drawable.ic_category_eat),
|
||||
new CategoryData(R.string.food, R.drawable.ic_category_food),
|
||||
new CategoryData(R.string.hotel, R.drawable.ic_category_hotel),
|
||||
new CategoryData(R.string.toilet, R.drawable.ic_category_toilet),
|
||||
new CategoryData(R.string.rv, R.drawable.ic_category_rv)
|
||||
);
|
||||
|
||||
private final int MAX_CATEGORIES_SIZE;
|
||||
|
||||
public CategoriesScreen(@NonNull CarContext carContext, @NonNull OMController mapController)
|
||||
{
|
||||
super(carContext, mapController);
|
||||
MAX_CATEGORIES_SIZE = getCarContext().getCarService(ConstraintManager.class).getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_LIST);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
MapTemplate.Builder builder = new MapTemplate.Builder();
|
||||
builder.setHeader(createHeader());
|
||||
builder.setMapController(getMapController());
|
||||
builder.setActionStrip(getActionStrip());
|
||||
builder.setItemList(createCategoriesList());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Header createHeader()
|
||||
{
|
||||
Header.Builder builder = new Header.Builder();
|
||||
builder.setStartHeaderAction(Action.BACK);
|
||||
builder.setTitle(getCarContext().getString(R.string.categories));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ItemList createCategoriesList()
|
||||
{
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
int categoriesSize = Math.min(CATEGORIES.size(), MAX_CATEGORIES_SIZE);
|
||||
for (int i = 0; i < categoriesSize; ++i)
|
||||
{
|
||||
Row.Builder itemBuilder = new Row.Builder();
|
||||
itemBuilder.setTitle(getCarContext().getString(CATEGORIES.get(i).nameResId));
|
||||
itemBuilder.setImage(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), CATEGORIES.get(i).iconResId)).build());
|
||||
builder.addItem(itemBuilder.build());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
32
android/src/app/organicmaps/car/screens/ErrorScreen.java
Normal file
32
android/src/app/organicmaps/car/screens/ErrorScreen.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
package app.organicmaps.car.screens;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.Screen;
|
||||
import androidx.car.app.model.LongMessageTemplate;
|
||||
import androidx.car.app.model.Template;
|
||||
|
||||
import app.organicmaps.R;
|
||||
|
||||
public class ErrorScreen extends Screen
|
||||
{
|
||||
private static final String TAG = ErrorScreen.class.getSimpleName();
|
||||
|
||||
public ErrorScreen(@NonNull CarContext carContext)
|
||||
{
|
||||
super(carContext);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
Log.d(TAG, "onGetTemplate");
|
||||
LongMessageTemplate.Builder builder = new LongMessageTemplate.Builder(getCarContext().getString(R.string.dialog_error_storage_message));
|
||||
builder.setTitle(getCarContext().getString(R.string.dialog_error_storage_title));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
46
android/src/app/organicmaps/car/screens/MapScreen.java
Normal file
46
android/src/app/organicmaps/car/screens/MapScreen.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
package app.organicmaps.car.screens;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.Screen;
|
||||
import androidx.car.app.model.ActionStrip;
|
||||
import androidx.car.app.navigation.model.MapController;
|
||||
|
||||
import app.organicmaps.car.OMController;
|
||||
import app.organicmaps.car.SurfaceRenderer;
|
||||
|
||||
public abstract class MapScreen extends Screen
|
||||
{
|
||||
@NonNull
|
||||
private final OMController mMapController;
|
||||
|
||||
public MapScreen(@NonNull CarContext carContext, @NonNull OMController mapController)
|
||||
{
|
||||
super(carContext);
|
||||
mMapController = mapController;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public OMController getOMController()
|
||||
{
|
||||
return mMapController;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SurfaceRenderer getSurfaceRenderer()
|
||||
{
|
||||
return mMapController.getSurfaceRenderer();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MapController getMapController()
|
||||
{
|
||||
return mMapController.getMapController();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ActionStrip getActionStrip()
|
||||
{
|
||||
return mMapController.getActionStrip();
|
||||
}
|
||||
}
|
103
android/src/app/organicmaps/car/screens/NavigationScreen.java
Normal file
103
android/src/app/organicmaps/car/screens/NavigationScreen.java
Normal file
|
@ -0,0 +1,103 @@
|
|||
package app.organicmaps.car.screens;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.Item;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapTemplate;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.car.OMController;
|
||||
|
||||
public class NavigationScreen extends MapScreen
|
||||
{
|
||||
public NavigationScreen(@NonNull CarContext carContext, @NonNull OMController mapController)
|
||||
{
|
||||
super(carContext, mapController);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
MapTemplate.Builder builder = new MapTemplate.Builder();
|
||||
builder.setHeader(createHeader());
|
||||
builder.setMapController(getMapController());
|
||||
builder.setActionStrip(getActionStrip());
|
||||
builder.setItemList(createList());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Header createHeader()
|
||||
{
|
||||
Header.Builder builder = new Header.Builder();
|
||||
builder.setStartHeaderAction(new Action.Builder(Action.APP_ICON).build());
|
||||
builder.setTitle(getCarContext().getString(R.string.app_name));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ItemList createList()
|
||||
{
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
builder.addItem(createSearchItem());
|
||||
builder.addItem(createCategoriesItem());
|
||||
builder.addItem(createBookmarksItem());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createSearchItem()
|
||||
{
|
||||
final CarIcon iconSearch = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_search)).build();
|
||||
|
||||
Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(getCarContext().getString(R.string.search));
|
||||
builder.setImage(iconSearch);
|
||||
builder.setBrowsable(true);
|
||||
builder.setOnClickListener(this::openSearch);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createCategoriesItem()
|
||||
{
|
||||
Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(getCarContext().getString(R.string.categories));
|
||||
builder.setBrowsable(true);
|
||||
builder.setOnClickListener(this::openCategories);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createBookmarksItem()
|
||||
{
|
||||
Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(getCarContext().getString(R.string.bookmarks));
|
||||
builder.setBrowsable(true);
|
||||
builder.setOnClickListener(this::openBookmarks);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void openSearch()
|
||||
{
|
||||
getScreenManager().push(new SearchScreen(getCarContext()));
|
||||
}
|
||||
|
||||
private void openCategories()
|
||||
{
|
||||
getScreenManager().push(new CategoriesScreen(getCarContext(), getOMController()));
|
||||
}
|
||||
|
||||
private void openBookmarks()
|
||||
{
|
||||
getScreenManager().push(new BookmarksScreen(getCarContext(), getOMController()));
|
||||
}
|
||||
}
|
61
android/src/app/organicmaps/car/screens/SearchScreen.java
Normal file
61
android/src/app/organicmaps/car/screens/SearchScreen.java
Normal file
|
@ -0,0 +1,61 @@
|
|||
package app.organicmaps.car.screens;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.Screen;
|
||||
import androidx.car.app.constraints.ConstraintManager;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.CarIcon;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.SearchTemplate;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.search.SearchRecents;
|
||||
|
||||
public class SearchScreen extends Screen implements SearchTemplate.SearchCallback
|
||||
{
|
||||
private final int MAX_RESULTS_SIZE;
|
||||
private ItemList mResults;
|
||||
private String mSearchText = "";
|
||||
|
||||
public SearchScreen(@NonNull CarContext carContext)
|
||||
{
|
||||
super(carContext);
|
||||
MAX_RESULTS_SIZE = getCarContext().getCarService(ConstraintManager.class).getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_LIST);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
SearchTemplate.Builder builder = new SearchTemplate.Builder(this);
|
||||
builder.setHeaderAction(Action.BACK);
|
||||
builder.setShowKeyboardByDefault(false);
|
||||
if (mSearchText.isEmpty() || mResults == null)
|
||||
loadRecents();
|
||||
builder.setItemList(mResults);
|
||||
builder.setInitialSearchText(mSearchText);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void loadRecents()
|
||||
{
|
||||
final CarIcon iconRecent = new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_search_recent)).build();
|
||||
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
builder.setNoItemsMessage(getCarContext().getString(R.string.search_history_text));
|
||||
SearchRecents.refresh();
|
||||
int recentsSize = Math.min(SearchRecents.getSize(), MAX_RESULTS_SIZE);
|
||||
for (int i = 0; i < recentsSize; ++i)
|
||||
{
|
||||
Row.Builder itemBuilder = new Row.Builder();
|
||||
itemBuilder.setTitle(SearchRecents.get(i));
|
||||
itemBuilder.setImage(iconRecent);
|
||||
builder.addItem(itemBuilder.build());
|
||||
}
|
||||
mResults = builder.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package app.organicmaps.car.screens.settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapTemplate;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.car.OMController;
|
||||
import app.organicmaps.car.UiHelpers;
|
||||
import app.organicmaps.car.screens.MapScreen;
|
||||
import app.organicmaps.settings.RoadType;
|
||||
|
||||
public class DrivingOptionsScreen extends MapScreen
|
||||
{
|
||||
public DrivingOptionsScreen(@NonNull CarContext carContext, @NonNull OMController mapController)
|
||||
{
|
||||
super(carContext, mapController);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
MapTemplate.Builder builder = new MapTemplate.Builder();
|
||||
builder.setHeader(createHeader());
|
||||
builder.setMapController(getMapController());
|
||||
builder.setItemList(createDrivingOptionsList());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Header createHeader()
|
||||
{
|
||||
Header.Builder builder = new Header.Builder();
|
||||
builder.setStartHeaderAction(Action.BACK);
|
||||
builder.setTitle(getCarContext().getString(R.string.driving_options_subheader));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ItemList createDrivingOptionsList()
|
||||
{
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
builder.addItem(UiHelpers.createDrivingOptionCheckbox(getCarContext(), RoadType.Toll, R.string.avoid_tolls));
|
||||
builder.addItem(UiHelpers.createDrivingOptionCheckbox(getCarContext(), RoadType.Dirty, R.string.avoid_unpaved));
|
||||
builder.addItem(UiHelpers.createDrivingOptionCheckbox(getCarContext(), RoadType.Ferry, R.string.avoid_ferry));
|
||||
builder.addItem(UiHelpers.createDrivingOptionCheckbox(getCarContext(), RoadType.Motorway, R.string.avoid_motorways));
|
||||
return builder.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package app.organicmaps.car.screens.settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.Item;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapTemplate;
|
||||
|
||||
import app.organicmaps.BuildConfig;
|
||||
import app.organicmaps.Framework;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.car.OMController;
|
||||
import app.organicmaps.car.screens.MapScreen;
|
||||
import app.organicmaps.util.DateUtils;
|
||||
|
||||
public class HelpScreen extends MapScreen
|
||||
{
|
||||
public HelpScreen(@NonNull CarContext carContext, @NonNull OMController mapController)
|
||||
{
|
||||
super(carContext, mapController);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
MapTemplate.Builder builder = new MapTemplate.Builder();
|
||||
builder.setHeader(createHeader());
|
||||
builder.setMapController(getMapController());
|
||||
builder.setItemList(createSettingsList());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Header createHeader()
|
||||
{
|
||||
Header.Builder builder = new Header.Builder();
|
||||
builder.setStartHeaderAction(Action.BACK);
|
||||
builder.setTitle(getCarContext().getString(R.string.help));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ItemList createSettingsList()
|
||||
{
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
builder.addItem(createVersionInfo());
|
||||
builder.addItem(createDataVersionInfo());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createVersionInfo()
|
||||
{
|
||||
return new Row.Builder()
|
||||
.setTitle(getCarContext().getString(R.string.app_name))
|
||||
.addText(BuildConfig.VERSION_NAME)
|
||||
.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createDataVersionInfo()
|
||||
{
|
||||
return new Row.Builder()
|
||||
.setTitle(getCarContext().getString(R.string.data_version, ""))
|
||||
.addText(DateUtils.getLocalDate(Framework.nativeGetDataVersion()))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package app.organicmaps.car.screens.settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.car.app.CarContext;
|
||||
import androidx.car.app.model.Action;
|
||||
import androidx.car.app.model.Header;
|
||||
import androidx.car.app.model.Item;
|
||||
import androidx.car.app.model.ItemList;
|
||||
import androidx.car.app.model.Row;
|
||||
import androidx.car.app.model.Template;
|
||||
import androidx.car.app.navigation.model.MapTemplate;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.car.OMController;
|
||||
import app.organicmaps.car.UiHelpers;
|
||||
import app.organicmaps.car.screens.MapScreen;
|
||||
import app.organicmaps.util.Config;
|
||||
|
||||
public class SettingsScreen extends MapScreen
|
||||
{
|
||||
|
||||
public SettingsScreen(@NonNull CarContext carContext, @NonNull OMController mapController)
|
||||
{
|
||||
super(carContext, mapController);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Template onGetTemplate()
|
||||
{
|
||||
MapTemplate.Builder builder = new MapTemplate.Builder();
|
||||
builder.setHeader(createHeader());
|
||||
builder.setMapController(getMapController());
|
||||
builder.setItemList(createSettingsList());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Header createHeader()
|
||||
{
|
||||
Header.Builder builder = new Header.Builder();
|
||||
builder.setStartHeaderAction(Action.BACK);
|
||||
builder.setTitle(getCarContext().getString(R.string.settings));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ItemList createSettingsList()
|
||||
{
|
||||
ItemList.Builder builder = new ItemList.Builder();
|
||||
builder.addItem(createRoutingOptionsItem());
|
||||
builder.addItem(UiHelpers.createSharedPrefsCheckbox(getCarContext(), R.string.big_font, Config::isLargeFontsSize, Config::setLargeFontsSize));
|
||||
builder.addItem(UiHelpers.createSharedPrefsCheckbox(getCarContext(), R.string.transliteration_title, Config::isTransliteration, Config::setTransliteration));
|
||||
builder.addItem(createHelpItem());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createRoutingOptionsItem()
|
||||
{
|
||||
Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(getCarContext().getString(R.string.driving_options_title));
|
||||
builder.setOnClickListener(() -> getScreenManager().push(new DrivingOptionsScreen(getCarContext(), getOMController())));
|
||||
builder.setBrowsable(true);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Item createHelpItem()
|
||||
{
|
||||
Row.Builder builder = new Row.Builder();
|
||||
builder.setTitle(getCarContext().getString(R.string.help));
|
||||
builder.setOnClickListener(() -> getScreenManager().push(new HelpScreen(getCarContext(), getOMController())));
|
||||
builder.setBrowsable(true);
|
||||
return builder.build();
|
||||
}
|
||||
}
|
Reference in a new issue