diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 86bdadc494..c1951169dd 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -83,6 +83,27 @@
android:manageSpaceActivity="${applicationId}.ManageSpaceActivity"
tools:targetApi="33">
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:exported="true"
+ android:windowSoftInputMode="stateAlwaysHidden|adjustPan">
+
+
+
+
+
NativeFramework();
+
+auto const mercatorPoint = mercator::FromLatLon(lat, lon);
+
+place_page::BuildInfo buildInfo;
+buildInfo.m_mercator = mercatorPoint;
+
+framework->BuildAndSetPlacePageInfo(buildInfo);
+
+if (framework->HasPlacePageInfo())
+{
+auto const & placePageInfo = framework->GetCurrentPlacePageInfo();
+if (placePageInfo.IsBookmark())
+{
+auto bookmarkId = placePageInfo.GetBookmarkId();
+return static_cast(bookmarkId);
+}
+}
+
+
+double const searchRadiusM = 2.0;
+auto const & bmManager = framework->GetBookmarkManager();
+
+auto const rect = mercator::RectByCenterXYAndSizeInMeters(mercatorPoint, searchRadiusM);
+m2::AnyRectD searchRect(rect);
+
+auto const * userMark = bmManager.FindNearestUserMark(searchRect);
+
+if (userMark && userMark->GetMarkType() == UserMark::Type::BOOKMARK)
+{
+auto const bookmarkId = userMark->GetId();
+return static_cast(bookmarkId);
+}
+
+return -1;
+}
+
JNIEXPORT jstring JNICALL
Java_app_organicmaps_Framework_nativeGetGe0Url(JNIEnv * env, jclass, jdouble lat, jdouble lon, jdouble zoomLevel, jstring name)
{
diff --git a/android/app/src/main/java/app/organicmaps/MwmActivity.java b/android/app/src/main/java/app/organicmaps/MwmActivity.java
index 416f528e24..376f41553e 100644
--- a/android/app/src/main/java/app/organicmaps/MwmActivity.java
+++ b/android/app/src/main/java/app/organicmaps/MwmActivity.java
@@ -45,6 +45,7 @@ import app.organicmaps.api.Const;
import app.organicmaps.base.BaseMwmFragmentActivity;
import app.organicmaps.base.OnBackPressListener;
import app.organicmaps.bookmarks.BookmarkCategoriesActivity;
+import app.organicmaps.bookmarks.data.BookmarkInfo;
import app.organicmaps.bookmarks.data.BookmarkManager;
import app.organicmaps.bookmarks.data.MapObject;
import app.organicmaps.display.DisplayChangedListener;
@@ -114,6 +115,7 @@ import app.organicmaps.widget.placepage.PlacePageViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
@@ -327,6 +329,29 @@ public class MwmActivity extends BaseMwmFragmentActivity
return;
}
+ if (intent != null && "app.organicmaps.action.SHOW_BOOKMARK".equals(intent.getAction()))
+ {
+
+ String bookmarkName = intent.getStringExtra("BOOKMARK_NAME");
+ double lat = intent.getDoubleExtra("BOOKMARK_LAT", Double.NaN);
+ double lon = intent.getDoubleExtra("BOOKMARK_LON", Double.NaN);
+ String categoryName = intent.getStringExtra("BOOKMARK_CATEGORY");
+
+ if (!Double.isNaN(lat) && !Double.isNaN(lon))
+ {
+ BookmarkInfo nearestBookmark = BookmarkManager.INSTANCE.findBookmarkByCoordinates(
+ lat, lon, bookmarkName, categoryName
+ );
+
+ if (nearestBookmark != null)
+ {
+ BookmarkManager.INSTANCE.showBookmarkOnMap(nearestBookmark.getBookmarkId());
+ return;
+ }
+ Framework.nativeZoomToPoint(lat, lon, 16, true);
+ }
+ }
+
final IntentProcessor[] mIntentProcessors = {
new Factory.UrlProcessor(),
new Factory.KmzKmlProcessor(),
diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/BookmarkWidgetCategoriesAdapter.java b/android/app/src/main/java/app/organicmaps/bookmarks/BookmarkWidgetCategoriesAdapter.java
new file mode 100644
index 0000000000..14785fa2df
--- /dev/null
+++ b/android/app/src/main/java/app/organicmaps/bookmarks/BookmarkWidgetCategoriesAdapter.java
@@ -0,0 +1,77 @@
+package app.organicmaps.bookmarks;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import app.organicmaps.R;
+import app.organicmaps.bookmarks.data.BookmarkCategory;
+import app.organicmaps.adapter.OnItemClickListener;
+
+import java.util.List;
+
+public class BookmarkWidgetCategoriesAdapter extends RecyclerView.Adapter
+{
+ private final Context context;
+ private final List categories;
+ private OnItemClickListener clickListener;
+
+ public BookmarkWidgetCategoriesAdapter(Context context, List categories)
+ {
+ this.context = context;
+ this.categories = categories;
+ }
+
+ public void setOnClickListener(OnItemClickListener listener)
+ {
+ this.clickListener = listener;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
+ {
+ View view = LayoutInflater.from(context).inflate(R.layout.item_widget_list, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position)
+ {
+ BookmarkCategory category = categories.get(position);
+ holder.categoryName.setText(category.getName());
+ holder.bookmarkCount.setText(String.valueOf(category.getBookmarksCount()));
+ String bookmarkText = context.getResources().getQuantityString(R.plurals.bookmarks_places, category.getBookmarksCount(), category.getBookmarksCount());
+ holder.bookmarkCount.setText(bookmarkText);
+ holder.itemView.setOnClickListener(v -> {
+ if (clickListener != null)
+ {
+ clickListener.onItemClick(v, category);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount()
+ {
+ return categories.size();
+ }
+
+ public static class ViewHolder extends RecyclerView.ViewHolder
+ {
+ TextView categoryName;
+ TextView bookmarkCount;
+
+ public ViewHolder(View itemView)
+ {
+ super(itemView);
+ categoryName = itemView.findViewById(R.id.name);
+ bookmarkCount = itemView.findViewById(R.id.size);
+ }
+ }
+}
diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/FavoriteBookmarkWidget.java b/android/app/src/main/java/app/organicmaps/bookmarks/FavoriteBookmarkWidget.java
new file mode 100644
index 0000000000..5093d3ae29
--- /dev/null
+++ b/android/app/src/main/java/app/organicmaps/bookmarks/FavoriteBookmarkWidget.java
@@ -0,0 +1,148 @@
+package app.organicmaps.bookmarks;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.widget.RemoteViews;
+
+import app.organicmaps.MwmActivity;
+import app.organicmaps.R;
+import app.organicmaps.bookmarks.data.BookmarkCategory;
+import app.organicmaps.bookmarks.data.BookmarkInfo;
+import app.organicmaps.bookmarks.data.BookmarkManager;
+
+public class FavoriteBookmarkWidget extends AppWidgetProvider
+{
+ private static final String TAG = "FavoriteBookmarkWidget";
+ private static final String PREFS_NAME = "FavoriteBookmarkWidget";
+ private static final String PREF_PREFIX_KEY = "favorite_bookmark_";
+
+ private static final String SUFFIX_LAT = "_latitude";
+ private static final String SUFFIX_LON = "_longitude";
+ private static final String SUFFIX_NAME = "_name";
+ private static final String SUFFIX_CATEGORY_NAME = "_category_name";
+ private static final String SUFFIX_COLOR = "_color";
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
+ {
+ for (int appWidgetId : appWidgetIds)
+ {
+ updateWidget(context, appWidgetManager, appWidgetId);
+ }
+ }
+
+ public static void updateWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId)
+ {
+ SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_favorite_bookmark);
+
+ double lat = prefs.getFloat(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LAT, 0);
+ double lon = prefs.getFloat(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LON, 0);
+ String categoryName = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_category_name", "");
+ String bookmarkName = prefs.getString(PREF_PREFIX_KEY + appWidgetId + SUFFIX_NAME, "");
+ int iconColor = prefs.getInt(PREF_PREFIX_KEY + appWidgetId + SUFFIX_COLOR, 0);
+
+ boolean validCoordinates = (lat != 0 || lon != 0);
+ BookmarkInfo bookmarkInfo = null;
+
+ if (validCoordinates)
+ {
+ bookmarkInfo = BookmarkManager.INSTANCE.findBookmarkByCoordinates(lat, lon, bookmarkName, categoryName);
+ }
+
+ String displayName = bookmarkInfo != null ? bookmarkInfo.getName() :
+ (bookmarkName != null && !bookmarkName.isEmpty() ? bookmarkName :
+ context.getString(R.string.select_bookmark));
+
+ views.setTextViewText(R.id.tv__bookmark_name, displayName);
+
+ if (bookmarkInfo != null)
+ {
+
+ int iconResId = BookmarkManager.INSTANCE.getBookmarkIcon(bookmarkInfo.getBookmarkId());
+ if (iconResId == 0)
+ {
+ iconResId = R.drawable.ic_bookmarks;
+ }
+
+ views.setImageViewResource(R.id.iv__bookmark_color, iconResId);
+
+ Intent intent = new Intent(context, MwmActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_CLEAR_TOP |
+ Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.setAction("app.organicmaps.action.SHOW_BOOKMARK");
+
+ intent.putExtra("FROM_WIDGET", true);
+ intent.putExtra("BOOKMARK_ID", bookmarkInfo.getBookmarkId());
+ intent.putExtra("BOOKMARK_NAME", bookmarkInfo.getName());
+ intent.putExtra("BOOKMARK_LAT", bookmarkInfo.getLat());
+ intent.putExtra("BOOKMARK_LON", bookmarkInfo.getLon());
+ intent.putExtra("BOOKMARK_CATEGORY",
+ BookmarkManager.INSTANCE.getCategoryById(bookmarkInfo.getCategoryId()).getName());
+
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ context,
+ appWidgetId,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+
+ views.setOnClickPendingIntent(R.id.widget_container, pendingIntent);
+ }
+ else
+ {
+ views.setImageViewResource(R.id.iv__bookmark_color, R.drawable.ic_bookmarks);
+
+ Intent intent = new Intent(context, FavoriteBookmarkWidgetConfigActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ context,
+ 0,
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+
+ views.setOnClickPendingIntent(R.id.widget_container, pendingIntent);
+ }
+
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
+
+ public static void saveBookmarkPref(Context context, int appWidgetId,
+ BookmarkInfo bookmarkInfo, BookmarkCategory category)
+ {
+ SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
+
+ prefs.putFloat(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LAT, (float) bookmarkInfo.getLat());
+ prefs.putFloat(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LON, (float) bookmarkInfo.getLon());
+ prefs.putString(PREF_PREFIX_KEY + appWidgetId + SUFFIX_NAME, bookmarkInfo.getName());
+ prefs.putString(PREF_PREFIX_KEY + appWidgetId + SUFFIX_CATEGORY_NAME, category.getName());
+ prefs.putLong(PREF_PREFIX_KEY + appWidgetId + "_bookmark_id", bookmarkInfo.getBookmarkId());
+ prefs.putLong(PREF_PREFIX_KEY + appWidgetId + "_category_id", category.getId());
+
+ prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_name_hash",
+ String.valueOf(bookmarkInfo.getName().hashCode()));
+ prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_lat_lon_hash",
+ String.valueOf((bookmarkInfo.getLat() + "," + bookmarkInfo.getLon()).hashCode()));
+
+ prefs.apply();
+ }
+
+ @Override
+ public void onDeleted(Context context, int[] appWidgetIds)
+ {
+ SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
+ for (int appWidgetId : appWidgetIds)
+ {
+ prefs.remove(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LAT);
+ prefs.remove(PREF_PREFIX_KEY + appWidgetId + SUFFIX_LON);
+ prefs.remove(PREF_PREFIX_KEY + appWidgetId + SUFFIX_NAME);
+ prefs.remove(PREF_PREFIX_KEY + appWidgetId + SUFFIX_CATEGORY_NAME);
+ prefs.remove(PREF_PREFIX_KEY + appWidgetId + SUFFIX_COLOR);
+ }
+ prefs.apply();
+ }
+}
diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/FavoriteBookmarkWidgetConfigActivity.java b/android/app/src/main/java/app/organicmaps/bookmarks/FavoriteBookmarkWidgetConfigActivity.java
new file mode 100644
index 0000000000..6914cc30ff
--- /dev/null
+++ b/android/app/src/main/java/app/organicmaps/bookmarks/FavoriteBookmarkWidgetConfigActivity.java
@@ -0,0 +1,199 @@
+package app.organicmaps.bookmarks;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import app.organicmaps.R;
+import app.organicmaps.adapter.OnItemClickListener;
+import app.organicmaps.bookmarks.data.BookmarkCategory;
+import app.organicmaps.bookmarks.data.BookmarkInfo;
+import app.organicmaps.bookmarks.data.BookmarkManager;
+import app.organicmaps.content.DataSource;
+import app.organicmaps.MwmApplication;
+import app.organicmaps.util.Config;
+import app.organicmaps.util.ThemeUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FavoriteBookmarkWidgetConfigActivity extends AppCompatActivity
+{
+ private static final String TAG = "BookmarkWidgetConfig";
+
+ private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
+ private TextView mSelectTextView;
+ private RecyclerView mCategoriesRecyclerView;
+ private RecyclerView mBookmarksRecyclerView;
+ private View mBackButton;
+
+ private List mCategories = new ArrayList<>();
+ private BookmarkCategory mCurrentCategory;
+ private boolean mShowingCategories = true;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState)
+ {
+ applyTheme();
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_widget_config);
+
+ mSelectTextView = findViewById(R.id.select_text);
+ mCategoriesRecyclerView = findViewById(R.id.categories_recycler);
+ mBookmarksRecyclerView = findViewById(R.id.bookmarks_recycler);
+ mBackButton = findViewById(R.id.back_button);
+
+ mCategoriesRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+ mBookmarksRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+
+ mBackButton.setOnClickListener(v -> onBackPressed());
+
+ setResult(RESULT_CANCELED);
+
+ Intent intent = getIntent();
+ Bundle extras = intent.getExtras();
+ if (extras != null)
+ {
+ mAppWidgetId = extras.getInt(
+ AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ }
+
+ if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID)
+ {
+ finish();
+ return;
+ }
+
+ try
+ {
+ MwmApplication app = MwmApplication.from(this);
+ if (!app.arePlatformAndCoreInitialized())
+ {
+ app.init(() -> {
+ runOnUiThread(this::loadCategories);
+ });
+ }
+ else
+ {
+ loadCategories();
+ }
+ } catch (IOException e)
+ {
+ Log.e(TAG, "Failed to initialize app", e);
+ finish();
+ }
+ }
+
+ private void applyTheme()
+ {
+ String currentTheme = Config.getCurrentUiTheme(this);
+ setTheme(ThemeUtils.getCardBgThemeResourceId(this, currentTheme));
+ }
+
+ private void loadCategories()
+ {
+ mShowingCategories = true;
+ mBookmarksRecyclerView.setVisibility(View.GONE);
+ mCategoriesRecyclerView.setVisibility(View.VISIBLE);
+ mSelectTextView.setText(R.string.select_list);
+
+ mCategories = BookmarkManager.INSTANCE.getCategories();
+ List nonEmptyCategories = new ArrayList<>();
+ for (BookmarkCategory category : mCategories)
+ {
+ if (category.getBookmarksCount() > 0)
+ {
+ nonEmptyCategories.add(category);
+ }
+ }
+ mCategories = nonEmptyCategories;
+
+ BookmarkWidgetCategoriesAdapter adapter = new BookmarkWidgetCategoriesAdapter(this, mCategories);
+
+ adapter.setOnClickListener(new OnItemClickListener()
+ {
+ @Override
+ public void onItemClick(View view, BookmarkCategory category)
+ {
+ mCurrentCategory = category;
+ showBookmarksForCategory(category);
+ }
+ });
+
+ mCategoriesRecyclerView.setAdapter(adapter);
+ }
+
+ private void showBookmarksForCategory(BookmarkCategory category)
+ {
+ mShowingCategories = false;
+ mCategoriesRecyclerView.setVisibility(View.GONE);
+ mBookmarksRecyclerView.setVisibility(View.VISIBLE);
+ mSelectTextView.setText(R.string.select_bookmark);
+
+ DataSource dataSource = new DataSource()
+ {
+ @Override
+ public BookmarkCategory getData()
+ {
+ return category;
+ }
+
+ @Override
+ public void invalidate()
+ {
+ }
+ };
+
+ BookmarkListAdapter adapter = new BookmarkListAdapter(dataSource);
+
+ adapter.setOnClickListener((view, position) -> {
+ Object item = adapter.getItem(position);
+ if (item instanceof BookmarkInfo)
+ {
+ BookmarkInfo bookmarkInfo = (BookmarkInfo) item;
+
+ FavoriteBookmarkWidget.saveBookmarkPref(
+ this,
+ mAppWidgetId,
+ bookmarkInfo,
+ mCurrentCategory);
+
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
+ FavoriteBookmarkWidget.updateWidget(this, appWidgetManager, mAppWidgetId);
+
+ Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
+ setResult(RESULT_OK, resultValue);
+
+ finish();
+ }
+ });
+
+ mBookmarksRecyclerView.setAdapter(adapter);
+ }
+
+ @Override
+ public void onBackPressed()
+ {
+ if (!mShowingCategories)
+ {
+ loadCategories();
+ }
+ else
+ {
+ setResult(RESULT_CANCELED);
+ super.onBackPressed();
+ }
+ }
+}
diff --git a/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java b/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java
index a7015715da..0eaece47f2 100644
--- a/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java
+++ b/android/app/src/main/java/app/organicmaps/bookmarks/data/BookmarkManager.java
@@ -147,6 +147,27 @@ public enum BookmarkManager
mOnElevationActivePointChangedListener = listener;
}
+ @Nullable
+ public BookmarkInfo findBookmarkByCoordinates(double lat, double lon, @Nullable String name, @Nullable String categoryName)
+ {
+ long bookmarkId = nativeFindBookmarkAtPoint(lat, lon);
+
+ if (bookmarkId == -1)
+ return null;
+
+ BookmarkInfo info = getBookmarkInfo(bookmarkId);
+
+ if (info != null &&
+ (name == null || name.isEmpty() || name.equals(info.getName())) &&
+ (categoryName == null || categoryName.isEmpty() ||
+ categoryName.equals(getCategoryById(info.getCategoryId()).getName())))
+ {
+ return info;
+ }
+
+ return null;
+ }
+
// Called from JNI.
@Keep
@SuppressWarnings("unused")
@@ -714,7 +735,7 @@ public enum BookmarkManager
!description.equals(getBookmarkDescription(bookmark.getBookmarkId())))
{
setBookmarkParams(bookmark.getBookmarkId(), name,
- icon != null ? icon.getColor() : getLastEditedColor(), description);
+ icon != null ? icon.getColor() : getLastEditedColor(), description);
}
}
@@ -730,7 +751,7 @@ public enum BookmarkManager
public double getElevationCurPositionDistance(long trackId)
{
- return nativeGetElevationCurPositionDistance(trackId);
+ return nativeGetElevationCurPositionDistance(trackId);
}
public void setElevationActivePoint(long trackId, double distance)
@@ -743,6 +764,8 @@ public enum BookmarkManager
return nativeGetElevationActivePointDistance(trackId);
}
+ private native long nativeFindBookmarkAtPoint(double lat, double lon);
+
@Nullable
private native Bookmark nativeUpdateBookmarkPlacePage(long bmkId);
diff --git a/android/app/src/main/res/drawable/widget_background.xml b/android/app/src/main/res/drawable/widget_background.xml
new file mode 100644
index 0000000000..e5b941258b
--- /dev/null
+++ b/android/app/src/main/res/drawable/widget_background.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/widget_preview.xml b/android/app/src/main/res/drawable/widget_preview.xml
new file mode 100644
index 0000000000..4b956bd2fe
--- /dev/null
+++ b/android/app/src/main/res/drawable/widget_preview.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/activity_widget_config.xml b/android/app/src/main/res/layout/activity_widget_config.xml
new file mode 100644
index 0000000000..394443dd48
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_widget_config.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/item_bookmark_category.xml b/android/app/src/main/res/layout/item_bookmark_category.xml
index ee8d743e65..d2e9da64fe 100644
--- a/android/app/src/main/res/layout/item_bookmark_category.xml
+++ b/android/app/src/main/res/layout/item_bookmark_category.xml
@@ -57,3 +57,4 @@
app:srcCompat="@drawable/ic_more"
app:tint="?secondary" />
+
diff --git a/android/app/src/main/res/layout/item_widget_list.xml b/android/app/src/main/res/layout/item_widget_list.xml
new file mode 100644
index 0000000000..570446c008
--- /dev/null
+++ b/android/app/src/main/res/layout/item_widget_list.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/layout/widget_favorite_bookmark.xml b/android/app/src/main/res/layout/widget_favorite_bookmark.xml
new file mode 100644
index 0000000000..a417af4afe
--- /dev/null
+++ b/android/app/src/main/res/layout/widget_favorite_bookmark.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 36eb211979..9047530175 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -933,4 +933,7 @@
No app installed that can open the location
Auto in navigation
+ Favorite Place
+ Select bookmark
+ Quick access to your favorite places
diff --git a/android/app/src/main/res/xml/favorite_bookmark_widget_info.xml b/android/app/src/main/res/xml/favorite_bookmark_widget_info.xml
new file mode 100644
index 0000000000..e3b645f908
--- /dev/null
+++ b/android/app/src/main/res/xml/favorite_bookmark_widget_info.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file