[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:
Andrew Shkrob 2022-11-27 01:41:51 +01:00
parent 19ab52216b
commit ba62a208c4
16 changed files with 915 additions and 100 deletions

View 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>

View 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>

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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));
}
}

View 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;
}
}

View 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();
}
}

View 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;
}
}

View file

@ -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();
}
}

View 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();
}
}

View 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();
}
}

View 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()));
}
}

View 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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}