[android] Added permissions dialogs.

[android] Added permissions details dialog.
[android] Added welcome screen.
[android] Remove get accaunt permission.
[android] My position button location permission check.
[android] Add string storage reload method.
This commit is contained in:
Roman Romanov 2017-05-31 16:08:16 +04:00
parent 7fccf21fb5
commit e57bcf9efa
75 changed files with 1510 additions and 54 deletions

View file

@ -36,7 +36,6 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.BATTERY_STATS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<permission

View file

@ -116,4 +116,10 @@ extern "C"
frm()->SaveTransliteration(value);
frm()->AllowTransliteration(value);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_util_Config_nativeReload(JNIEnv * env, jclass thiz)
{
settings::Reload();
}
} // extern "C"

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View file

@ -0,0 +1,17 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/black_4"/>
<size
android:height="40dp"
android:width="40dp"/>
</shape>
</item>
<item
android:drawable="@drawable/ic_navigation_light_24_px"
android:left="@dimen/margin_half"
android:right="@dimen/margin_half"
android:top="@dimen/margin_half"
android:bottom="@dimen/margin_half"/>
</layer-list>

View file

@ -0,0 +1,17 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/black_4"/>
<size
android:height="40dp"
android:width="40dp"/>
</shape>
</item>
<item
android:drawable="@drawable/ic_storage_light_24_px"
android:left="@dimen/margin_half"
android:right="@dimen/margin_half"
android:top="@dimen/margin_half"
android:bottom="@dimen/margin_half"/>
</layer-list>

View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btn_frame">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base"
android:layout_gravity="center"
android:src="@drawable/img_permissions"
android:layout_weight="1"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Title"
android:fontFamily="@string/robotoMedium"
android:text="@string/onboarding_permissions_title"
tools:targetApi="jelly_bean"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body1.Secondary"
android:text="@string/onboarding_permissions_message"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@id/btn_frame"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_double_plus"
android:layout_alignParentBottom="true"
android:paddingTop="@dimen/margin_quarter_plus"
android:paddingBottom="@dimen/margin_quarter_plus"
android:paddingRight="@dimen/margin_half"
android:paddingLeft="@dimen/margin_half"
android:background="?accentButtonBackground"
android:gravity="center_vertical">
<TextView
android:id="@+id/btn__learn_more"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/learn_more"
android:gravity="center_vertical"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/btn__continue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/continue_download"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btn_frame">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base"
android:layout_gravity="center"
android:src="@drawable/img_no_storage_permission"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_vertical"
android:layout_weight="1">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Title"
android:fontFamily="@string/robotoMedium"
android:text="@string/onboarding_storage_permissions_title"
tools:targetApi="jelly_bean"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body1.Secondary"
android:text="@string/onboarding_storage_permissions_message"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@id/btn_frame"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_double_plus"
android:layout_alignParentBottom="true"
android:paddingTop="@dimen/margin_quarter_plus"
android:paddingBottom="@dimen/margin_quarter_plus"
android:paddingRight="@dimen/margin_half"
android:paddingLeft="@dimen/margin_half"
android:background="?accentButtonBackground"
android:gravity="center_vertical">
<TextView
android:id="@+id/btn__exit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/exit"
android:gravity="center_vertical"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/btn__settings"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/settings"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btn_frame">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base"
android:layout_gravity="center"
android:src="@drawable/img_welcome"
android:layout_weight="1"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Title"
android:fontFamily="@string/robotoMedium"
android:text="@string/onboarding_welcome_title"
tools:targetApi="jelly_bean"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body1.Secondary"
android:text="@string/onboarding_welcome_first_subtitle"/>
<TextView
android:id="@+id/tv__terms_and_privacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:linksClickable="true"
tools:text="@string/onboarding_welcome_second_subtitle"/>
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@id/btn_frame"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_double_plus"
android:layout_alignParentBottom="true"
android:paddingTop="@dimen/margin_quarter_plus"
android:paddingBottom="@dimen/margin_quarter_plus"
android:paddingRight="@dimen/margin_half"
android:paddingLeft="@dimen/margin_half"
android:background="?accentButtonBackground"
android:gravity="center_vertical">
<TextView
android:id="@+id/btn__continue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/accept_and_continue"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv__permissions"
android:layout_width="@dimen/permissions_details_width"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_above="@+id/btn_frame"/>
<RelativeLayout
android:id="@id/btn_frame"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_double_plus"
android:layout_alignParentBottom="true"
android:paddingTop="@dimen/margin_quarter_plus"
android:paddingBottom="@dimen/margin_quarter_plus"
android:paddingRight="@dimen/margin_half"
android:paddingLeft="@dimen/margin_half"
android:background="?accentButtonBackground"
android:gravity="center_vertical">
<TextView
android:id="@+id/btn__back"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/back"
android:gravity="center_vertical"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/btn__continue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/continue_download"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mapswithme.maps.widget.HeightLimitedFrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btn_frame">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base"
android:layout_gravity="center_horizontal"
android:tag="@string/tag_height_limited"
android:src="@drawable/img_permissions"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Title"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:fontFamily="@string/robotoMedium"
android:text="@string/onboarding_permissions_title"
tools:targetApi="jelly_bean"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body1.Secondary"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:text="@string/onboarding_permissions_message"/>
</LinearLayout>
</com.mapswithme.maps.widget.HeightLimitedFrameLayout>
<RelativeLayout
android:id="@id/btn_frame"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_double_plus"
android:layout_alignParentBottom="true"
android:paddingTop="@dimen/margin_quarter_plus"
android:paddingBottom="@dimen/margin_quarter_plus"
android:paddingRight="@dimen/margin_half"
android:paddingLeft="@dimen/margin_half"
android:background="?accentButtonBackground"
android:gravity="center_vertical">
<TextView
android:id="@+id/btn__learn_more"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/learn_more"
android:gravity="center_vertical"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/btn__continue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/continue_download"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mapswithme.maps.widget.HeightLimitedFrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btn_frame">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base"
android:layout_gravity="center_horizontal"
android:tag="@string/tag_height_limited"
android:src="@drawable/img_no_storage_permission"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Title"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:fontFamily="@string/robotoMedium"
android:text="@string/onboarding_storage_permissions_title"
tools:targetApi="jelly_bean"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body1.Secondary"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:text="@string/onboarding_storage_permissions_message"/>
</LinearLayout>
</com.mapswithme.maps.widget.HeightLimitedFrameLayout>
<RelativeLayout
android:id="@id/btn_frame"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_double_plus"
android:layout_alignParentBottom="true"
android:paddingTop="@dimen/margin_quarter_plus"
android:paddingBottom="@dimen/margin_quarter_plus"
android:paddingRight="@dimen/margin_half"
android:paddingLeft="@dimen/margin_half"
android:background="?accentButtonBackground"
android:gravity="center_vertical">
<TextView
android:id="@+id/btn__exit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/exit"
android:gravity="center_vertical"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
<TextView
android:id="@+id/btn__settings"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/settings"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mapswithme.maps.widget.HeightLimitedFrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btn_frame">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base"
android:layout_gravity="center_horizontal"
android:tag="@string/tag_height_limited"
android:src="@drawable/img_welcome"/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Title"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:fontFamily="@string/robotoMedium"
android:text="@string/onboarding_welcome_title"
tools:targetApi="jelly_bean"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body1.Secondary"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:text="@string/onboarding_welcome_first_subtitle"/>
<TextView
android:id="@+id/tv__terms_and_privacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginRight="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body3"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:linksClickable="true"
tools:text="@string/onboarding_welcome_second_subtitle"/>
</LinearLayout>
</com.mapswithme.maps.widget.HeightLimitedFrameLayout>
<RelativeLayout
android:id="@id/btn_frame"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/margin_double_plus"
android:layout_alignParentBottom="true"
android:paddingTop="@dimen/margin_quarter_plus"
android:paddingBottom="@dimen/margin_quarter_plus"
android:paddingRight="@dimen/margin_half"
android:paddingLeft="@dimen/margin_half"
android:background="?accentButtonBackground"
android:gravity="center_vertical">
<TextView
android:id="@+id/btn__continue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/margin_half"
android:paddingRight="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Button"
android:textColor="?accentButtonTextColor"
android:fontFamily="@string/robotoMedium"
android:text="@string/accept_and_continue"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="?clickableBackground"
tools:targetApi="jelly_bean"/>
</RelativeLayout>
</RelativeLayout>

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/margin_double"
android:paddingRight="@dimen/margin_double"
android:paddingTop="@dimen/permissions_items_margin"
android:paddingBottom="@dimen/permissions_items_margin">
<ImageView
android:id="@+id/iv__permission_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:src="@drawable/ic_storage_permission"/>
<TextView
android:id="@+id/tv__permission_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/iv__permission_icon"
android:layout_toRightOf="@id/iv__permission_icon"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body1"
tools:text="@string/onboarding_detail_permissions_storage_title"/>
<TextView
android:id="@+id/tv__permission_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/iv__permission_icon"
android:layout_toRightOf="@id/iv__permission_icon"
android:layout_below="@id/tv__permission_title"
android:layout_marginLeft="@dimen/margin_base"
android:layout_marginStart="@dimen/margin_base"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="@string/onboarding_detail_permissions_storage_message"/>
</RelativeLayout>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/margin_double"
android:paddingRight="@dimen/margin_double">
<TextView
android:id="@+id/tv__note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Body3"
tools:text="@string/onboarding_detail_permissions_storage_path_message"/>
</LinearLayout>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/margin_double"
android:paddingRight="@dimen/margin_double"
android:paddingTop="@dimen/permissions_title_top_margin">
<TextView
android:id="@+id/tv__title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MwmTextAppearance.Toolbar"
android:textColor="?android:textColorPrimary"
android:fontFamily="@string/robotoMedium"
tools:text="@string/onboarding_detail_permissions_title"
tools:targetApi="jelly_bean"/>
</LinearLayout>

View file

@ -18,4 +18,7 @@
<dimen name="altitude_chart_image_width">334dp</dimen>
<dimen name="start_button_width">128dp</dimen>
<dimen name="permissions_title_top_margin">52dp</dimen>
<dimen name="permissions_items_margin">@dimen/margin_base</dimen>
</resources>

View file

@ -7,4 +7,6 @@
<dimen name="margin_direction_side">40dp</dimen>
<dimen name="margin_direction_mid">36dp</dimen>
<dimen name="margin_direction_around_center">80dp</dimen>
<dimen name="permissions_details_width">480dp</dimen>
</resources>

View file

@ -20,6 +20,7 @@
<color name="black_primary">#DE000000</color> <!-- 87% black -->
<color name="black_secondary">#8A000000</color> <!-- 54% black -->
<color name="black_lightest">#61000000</color> <!-- 38% black -->
<color name="black_4">#0A000000</color> <!-- 4% black -->
<color name="black_8">#14000000</color> <!-- 8% black -->
<color name="black_11">#1E000000</color> <!-- 11% black -->
<color name="black_24">#3D000000</color> <!-- 24% black -->

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="match_parent" type="dimen">-1</item>
<dimen name="track_circle_size">40dp</dimen>
@ -188,4 +189,8 @@
<dimen name="margin_dialog_title">20dp</dimen>
<dimen name="action_bar_extended_height">72dp</dimen>
<dimen name="permissions_title_top_margin">80dp</dimen>
<dimen name="permissions_items_margin">@dimen/margin_double</dimen>
<dimen name="permissions_details_width">@dimen/match_parent</dimen>
</resources>

View file

@ -16,8 +16,9 @@ import android.view.View;
import android.view.ViewGroup;
import com.mapswithme.maps.base.BaseMwmFragment;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.util.UiUtils;
import com.mapswithme.util.statistics.PushwooshHelper;
import com.mapswithme.util.concurrency.UiThread;
public class MapFragment extends BaseMwmFragment
implements View.OnTouchListener,
@ -166,12 +167,25 @@ public class MapFragment extends BaseMwmFragment
getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
final float exactDensityDpi = metrics.densityDpi;
if (!nativeCreateEngine(surface, (int) exactDensityDpi, SplashActivity.isFirstStart()))
final boolean firstStart = SplashActivity.isFirstStart();
if (!nativeCreateEngine(surface, (int) exactDensityDpi, firstStart))
{
reportUnsupported();
return;
}
if (firstStart)
{
UiThread.runLater(new Runnable()
{
@Override
public void run()
{
LocationHelper.INSTANCE.onExitFromFirstRun();
}
});
}
mContextCreated = true;
onRenderingInitialized();
}

View file

@ -27,6 +27,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.Toast;
import com.mapswithme.maps.Framework.MapObjectListener;
import com.mapswithme.maps.activity.CustomNavigateUpListener;
@ -88,6 +89,7 @@ import com.mapswithme.util.Animations;
import com.mapswithme.util.BottomSheetHelper;
import com.mapswithme.util.Counters;
import com.mapswithme.util.InputUtils;
import com.mapswithme.util.PermissionsUtils;
import com.mapswithme.util.ThemeSwitcher;
import com.mapswithme.util.ThemeUtils;
import com.mapswithme.util.UiUtils;
@ -131,6 +133,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
private static final String STATE_MAP_OBJECT = "MapObject";
private static final String EXTRA_LOCATION_DIALOG_IS_ANNOYING = "LOCATION_DIALOG_IS_ANNOYING";
private static final int LOCATION_REQUEST = 1;
// Map tasks that we run AFTER rendering initialized
private final Stack<MapTask> mTasks = new Stack<>();
private final StoragePathManager mPathManager = new StoragePathManager();
@ -186,11 +190,23 @@ public class MwmActivity extends BaseMwmFragmentActivity
@Override
public void onClick(View v)
{
mLocationErrorDialogAnnoying = false;
LocationHelper.INSTANCE.switchToNextMode();
LocationHelper.INSTANCE.restart();
Statistics.INSTANCE.trackEvent(Statistics.EventName.TOOLBAR_MY_POSITION);
AlohaHelper.logClick(AlohaHelper.TOOLBAR_MY_POSITION);
boolean granted = PermissionsUtils.isLocationGranted();
if (!granted && PermissionsUtils.isLocationExplanationNeeded(MwmActivity.this))
{
PermissionsUtils.requestLocationPermission(MwmActivity.this, LOCATION_REQUEST);
return;
}
else if (!granted)
{
Toast.makeText(MwmActivity.this, R.string.location_permission_denied, Toast.LENGTH_SHORT)
.show();
return;
}
myPositionClick();
}
};
@ -309,6 +325,13 @@ public class MwmActivity extends BaseMwmFragmentActivity
runTasks();
}
private void myPositionClick()
{
mLocationErrorDialogAnnoying = false;
LocationHelper.INSTANCE.switchToNextMode();
LocationHelper.INSTANCE.restart();
}
private void runTasks()
{
while (!mTasks.isEmpty())
@ -961,6 +984,18 @@ public class MwmActivity extends BaseMwmFragmentActivity
mFilterController.onRestoreState(savedInstanceState);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode != LOCATION_REQUEST || grantResults.length == 0)
return;
if (PermissionsUtils.computePermissionsResult(permissions, grantResults).isLocationGranted())
myPositionClick();
}
@Override
protected void onNewIntent(Intent intent)
{

View file

@ -7,13 +7,16 @@ import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.mapswithme.maps.editor.ViralFragment;
import com.mapswithme.maps.news.BaseNewsFragment;
import com.mapswithme.maps.news.FirstStartFragment;
import com.mapswithme.maps.news.NewsFragment;
import com.mapswithme.maps.news.WelcomeDialogFragment;
import com.mapswithme.maps.permissions.PermissionsDialogFragment;
import com.mapswithme.maps.permissions.StoragePermissionsDialogFragment;
import com.mapswithme.util.Config;
import com.mapswithme.util.Counters;
import com.mapswithme.util.PermissionsUtils;
@ -27,6 +30,7 @@ public class SplashActivity extends AppCompatActivity
public static final String EXTRA_INTENT = "extra_intent";
private static final String EXTRA_ACTIVITY_TO_START = "extra_activity_to_start";
private static final int REQUEST_PERMISSIONS = 1;
private static final long FIRST_START_DELAY = 1000;
private static final long DELAY = 100;
// The first launch of application ever - onboarding screen will be shown.
@ -35,8 +39,24 @@ public class SplashActivity extends AppCompatActivity
private View mIvLogo;
private boolean mPermissionsGranted;
private boolean mNeedStoragePermission;
private boolean mCanceled;
@Nullable
private DialogFragment mPermissionsDialog;
@Nullable
private DialogFragment mStoragePermissionsDialog;
@NonNull
private final Runnable mPermissionsTask = new Runnable()
{
@Override
public void run()
{
mPermissionsDialog = PermissionsDialogFragment.show(SplashActivity.this, REQUEST_PERMISSIONS);
}
};
@NonNull
private final Runnable mDelayedTask = new Runnable()
{
@ -79,6 +99,7 @@ public class SplashActivity extends AppCompatActivity
protected void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
UiThread.cancelDelayedTasks(mPermissionsTask);
UiThread.cancelDelayedTasks(mDelayedTask);
UiThread.cancelDelayedTasks(mFinalTask);
Counters.initCounters(this);
@ -93,10 +114,37 @@ public class SplashActivity extends AppCompatActivity
mPermissionsGranted = PermissionsUtils.isExternalStorageGranted();
if (!mPermissionsGranted)
{
// TODO requestPermissions after Permissions dialog
PermissionsUtils.requestPermissions(this, REQUEST_PERMISSIONS);
mStoragePermissionsDialog = StoragePermissionsDialogFragment.find(this);
if (mNeedStoragePermission || mStoragePermissionsDialog != null)
{
if (mPermissionsDialog != null)
{
mPermissionsDialog.dismiss();
mPermissionsDialog = null;
}
if (mStoragePermissionsDialog == null)
mStoragePermissionsDialog = StoragePermissionsDialogFragment.show(this);
return;
}
mPermissionsDialog = PermissionsDialogFragment.find(this);
if (mPermissionsDialog == null)
UiThread.runLater(mPermissionsTask, FIRST_START_DELAY);
return;
}
else
{
if (mPermissionsDialog != null)
{
mPermissionsDialog.dismiss();
mPermissionsDialog = null;
}
if (mStoragePermissionsDialog != null)
{
mStoragePermissionsDialog.dismiss();
mStoragePermissionsDialog = null;
}
}
UiThread.runLater(mDelayedTask, DELAY);
}
@ -105,6 +153,7 @@ public class SplashActivity extends AppCompatActivity
protected void onPause()
{
mCanceled = true;
UiThread.cancelDelayedTasks(mPermissionsTask);
UiThread.cancelDelayedTasks(mDelayedTask);
UiThread.cancelDelayedTasks(mFinalTask);
super.onPause();
@ -112,18 +161,16 @@ public class SplashActivity extends AppCompatActivity
private void resumeDialogs()
{
// TODO show permissions dialog if Permissions is not granted
if (!mPermissionsGranted || mCanceled)
if (mCanceled)
return;
if (Counters.isMigrationNeeded())
{
Config.migrateCountersToSharedPrefs();
Counters.setMigrationExecuted();
Counters.initCounters(this);
}
sFirstStart = FirstStartFragment.showOn(this, this);
sFirstStart = WelcomeDialogFragment.showOn(this, this);
if (sFirstStart)
{
PushwooshHelper.nativeProcessFirstLaunch();
@ -175,16 +222,7 @@ public class SplashActivity extends AppCompatActivity
mPermissionsGranted = PermissionsUtils.computePermissionsResult(permissions, grantResults)
.isExternalStorageGranted();
if (mPermissionsGranted)
{
init();
resumeDialogs();
}
else
{
finish();
}
mNeedStoragePermission = !mPermissionsGranted;
}
@Override

View file

@ -67,13 +67,6 @@ public class FirstStartFragment extends BaseNewsFragment
return super.onCreateDialog(savedInstanceState);
}
@Override
protected void onDoneClick()
{
super.onDoneClick();
LocationHelper.INSTANCE.onExitFromFirstRun();
}
public static boolean showOn(@NonNull FragmentActivity activity,
@Nullable NewsDialogListener listener)
{

View file

@ -0,0 +1,109 @@
package com.mapswithme.maps.news;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.view.Window;
import android.widget.TextView;
import com.mapswithme.maps.BuildConfig;
import com.mapswithme.maps.R;
import com.mapswithme.maps.base.BaseMwmDialogFragment;
import com.mapswithme.maps.location.LocationHelper;
import com.mapswithme.util.Counters;
public class WelcomeDialogFragment extends BaseMwmDialogFragment implements View.OnClickListener
{
@Nullable
private BaseNewsFragment.NewsDialogListener mListener;
public static boolean showOn(@NonNull FragmentActivity activity,
@Nullable BaseNewsFragment.NewsDialogListener listener)
{
if (Counters.getFirstInstallVersion() < BuildConfig.VERSION_CODE)
return false;
FragmentManager fm = activity.getSupportFragmentManager();
if (fm.isDestroyed())
return false;
if (Counters.isFirstStartDialogSeen() &&
!recreate(activity))
return false;
create(activity, listener);
Counters.setFirstStartDialogSeen();
return true;
}
private static void create(@NonNull FragmentActivity activity,
@Nullable BaseNewsFragment.NewsDialogListener listener)
{
final WelcomeDialogFragment fragment = new WelcomeDialogFragment();
fragment.mListener = listener;
activity.getSupportFragmentManager()
.beginTransaction()
.add(fragment, WelcomeDialogFragment.class.getName())
.commitAllowingStateLoss();
}
private static boolean recreate(FragmentActivity activity)
{
FragmentManager fm = activity.getSupportFragmentManager();
Fragment f = fm.findFragmentByTag(WelcomeDialogFragment.class.getName());
if (f == null)
return false;
// If we're here, it means that the user has rotated the screen.
// We use different dialog themes for landscape and portrait modes on tablets,
// so the fragment should be recreated to be displayed correctly.
fm.beginTransaction().remove(f).commitAllowingStateLoss();
fm.executePendingTransactions();
return true;
}
@Override
protected int getCustomTheme()
{
return getFullscreenTheme();
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
LocationHelper.INSTANCE.onEnteredIntoFirstRun();
Dialog res = super.onCreateDialog(savedInstanceState);
res.requestWindowFeature(Window.FEATURE_NO_TITLE);
res.setCancelable(false);
View content = View.inflate(getActivity(), R.layout.fragment_welcome, null);
res.setContentView(content);
content.findViewById(R.id.btn__continue).setOnClickListener(this);
TextView terms = (TextView) content.findViewById(R.id.tv__terms_and_privacy);
terms.setText(Html.fromHtml(getString(R.string.onboarding_welcome_second_subtitle)));
terms.setMovementMethod(LinkMovementMethod.getInstance());
return res;
}
@Override
public void onClick(View v)
{
if (v.getId() != R.id.btn__continue)
return;
if (mListener != null)
mListener.onDialogDone();
dismiss();
}
}

View file

@ -0,0 +1,128 @@
package com.mapswithme.maps.permissions;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.view.View;
import android.view.Window;
import com.mapswithme.maps.base.BaseMwmDialogFragment;
import com.mapswithme.util.PermissionsUtils;
abstract class BasePermissionsDialogFragment extends BaseMwmDialogFragment
implements View.OnClickListener
{
private static final String REQUEST_ID = "arg_request_id";
private int mRequestId;
@SuppressWarnings("TryWithIdenticalCatches")
@Nullable
public static DialogFragment show(@NonNull FragmentActivity activity, int requestId,
@NonNull Class<? extends BaseMwmDialogFragment> dialogClass)
{
final FragmentManager fm = activity.getSupportFragmentManager();
if (fm.isDestroyed())
return null;
Fragment f = fm.findFragmentByTag(dialogClass.getName());
if (f != null)
return (DialogFragment) f;
BaseMwmDialogFragment dialog = null;
try
{
dialog = dialogClass.newInstance();
final Bundle args = new Bundle();
args.putInt(REQUEST_ID, requestId);
dialog.setArguments(args);
dialog.setCancelable(false);
dialog.show(fm, dialogClass.getName());
}
catch (java.lang.InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
return dialog;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null)
{
mRequestId = args.getInt(REQUEST_ID);
}
}
@Override
protected int getCustomTheme()
{
return super.getFullscreenTheme();
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
Dialog res = super.onCreateDialog(savedInstanceState);
res.requestWindowFeature(Window.FEATURE_NO_TITLE);
View content = View.inflate(getActivity(), getLayoutRes(), null);
res.setContentView(content);
View button = content.findViewById(getFirstActionButton());
if (button != null)
button.setOnClickListener(this);
button = content.findViewById(getContinueActionButton());
if (button != null)
button.setOnClickListener(this);
return res;
}
@LayoutRes
abstract protected int getLayoutRes();
@IdRes
protected abstract int getFirstActionButton();
protected abstract void onFirstActionClick();
@IdRes
protected abstract int getContinueActionButton();
@Override
public void onClick(@NonNull View v)
{
if (v.getId() == getFirstActionButton())
{
onFirstActionClick();
return;
}
if (v.getId() == getContinueActionButton())
{
PermissionsUtils.requestPermissions(getActivity(), mRequestId);
}
}
protected int getRequestId()
{
return mRequestId;
}
}

View file

@ -0,0 +1,174 @@
package com.mapswithme.maps.permissions;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.mapswithme.maps.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
class PermissionsAdapter extends RecyclerView.Adapter<PermissionsAdapter.ViewHolder>
{
static final int TYPE_TITLE = 0;
static final int TYPE_PERMISSION = 1;
static final int TYPE_NOTE = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ TYPE_TITLE, TYPE_PERMISSION, TYPE_NOTE})
@interface ViewHolderType {}
private static final List<PermissionItem> ITEMS;
static {
ITEMS = new ArrayList<>();
ITEMS.add(new PermissionItem(TYPE_TITLE, R.string.onboarding_detail_permissions_title, 0, 0));
ITEMS.add(new PermissionItem(TYPE_PERMISSION,
R.string.onboarding_detail_permissions_storage_title,
R.string.onboarding_detail_permissions_storage_message,
R.drawable.ic_storage_permission));
ITEMS.add(new PermissionItem(TYPE_PERMISSION,
R.string.onboarding_detail_permissions_location_title,
R.string.onboarding_detail_permissions_location_message,
R.drawable.ic_navigation_permission));
ITEMS.add(new PermissionItem(TYPE_NOTE, 0,
R.string.onboarding_detail_permissions_storage_path_message, 0));
}
@ViewHolderType
@Override
public int getItemViewType(int position)
{
return ITEMS.get(position).mType;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, @ViewHolderType int viewType)
{
switch (viewType)
{
case TYPE_NOTE:
return new NoteViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_permissions_note, parent, false));
case TYPE_PERMISSION:
return new PermissionViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_permission, parent,
false));
case TYPE_TITLE:
return new TitleViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_permissions_title, parent,
false));
default:
return null;
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.bind(ITEMS.get(position));
}
@Override
public int getItemCount()
{
return ITEMS.size();
}
private static final class PermissionItem
{
@ViewHolderType
private final int mType;
@StringRes
private final int mTitle;
@StringRes
private final int mMessage;
@DrawableRes
private final int mIcon;
PermissionItem(@ViewHolderType int type, @StringRes int title, @StringRes int message, int icon)
{
mType = type;
mTitle = title;
mMessage = message;
mIcon = icon;
}
}
static abstract class ViewHolder extends RecyclerView.ViewHolder
{
public ViewHolder(View itemView)
{
super(itemView);
}
abstract void bind(@NonNull PermissionItem item);
}
private static class TitleViewHolder extends ViewHolder
{
private final TextView mTitle;
TitleViewHolder(View itemView)
{
super(itemView);
mTitle = (TextView) itemView.findViewById(R.id.tv__title);
}
@Override
void bind(@NonNull PermissionItem item)
{
mTitle.setText(item.mTitle);
}
}
private static class PermissionViewHolder extends ViewHolder
{
private final ImageView mIcon;
private final TextView mTitle;
private final TextView mMessage;
PermissionViewHolder(View itemView)
{
super(itemView);
mIcon = (ImageView) itemView.findViewById(R.id.iv__permission_icon);
mTitle = (TextView) itemView.findViewById(R.id.tv__permission_title);
mMessage = (TextView) itemView.findViewById(R.id.tv__permission_message);
}
@Override
void bind(@NonNull PermissionItem item)
{
mIcon.setImageResource(item.mIcon);
mTitle.setText(item.mTitle);
mMessage.setText(item.mMessage);
}
}
private static class NoteViewHolder extends ViewHolder
{
private final TextView mMessage;
NoteViewHolder(View itemView)
{
super(itemView);
mMessage = (TextView) itemView.findViewById(R.id.tv__note);
}
@Override
void bind(@NonNull PermissionItem item)
{
mMessage.setText(item.mMessage);
}
}
}

View file

@ -0,0 +1,67 @@
package com.mapswithme.maps.permissions;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.mapswithme.maps.R;
public class PermissionsDetailDialogFragment extends BasePermissionsDialogFragment
{
@Nullable
public static DialogFragment show(@NonNull FragmentActivity activity, int requestId)
{
DialogFragment dialog = BasePermissionsDialogFragment.show(activity, requestId,
PermissionsDetailDialogFragment.class);
if (dialog != null)
dialog.setCancelable(true);
return dialog;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
Dialog res = super.onCreateDialog(savedInstanceState);
RecyclerView permissions = (RecyclerView) res.findViewById(R.id.rv__permissions);
permissions.setLayoutManager(new LinearLayoutManager(getContext(),
LinearLayoutManager.VERTICAL, false));
permissions.setAdapter(new PermissionsAdapter());
return res;
}
@LayoutRes
@Override
protected int getLayoutRes()
{
return R.layout.fragment_detail_permissions;
}
@IdRes
@Override
protected int getFirstActionButton()
{
return R.id.btn__back;
}
@Override
protected void onFirstActionClick()
{
dismiss();
}
@IdRes
@Override
protected int getContinueActionButton()
{
return R.id.btn__continue;
}
}

View file

@ -0,0 +1,81 @@
package com.mapswithme.maps.permissions;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import com.mapswithme.maps.R;
import com.mapswithme.maps.SplashActivity;
public class PermissionsDialogFragment extends BasePermissionsDialogFragment
{
@Nullable
private DialogFragment mDetailDialog;
@Nullable
public static DialogFragment show(@NonNull FragmentActivity activity, int requestId)
{
return BasePermissionsDialogFragment.show(activity, requestId, PermissionsDialogFragment.class);
}
public static DialogFragment find(SplashActivity activity)
{
final FragmentManager fm = activity.getSupportFragmentManager();
if (fm.isDestroyed())
return null;
Fragment f = fm.findFragmentByTag(PermissionsDialogFragment.class.getName());
return (DialogFragment) f;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Fragment f = getActivity().getSupportFragmentManager()
.findFragmentByTag(PermissionsDetailDialogFragment.class.getName());
if (f != null)
mDetailDialog = (DialogFragment) f;
}
@LayoutRes
@Override
protected int getLayoutRes()
{
return R.layout.fragment_permissions;
}
@IdRes
@Override
protected int getFirstActionButton()
{
return R.id.btn__learn_more;
}
@Override
protected void onFirstActionClick()
{
mDetailDialog = PermissionsDetailDialogFragment.show(getActivity(), getRequestId());
}
@IdRes
@Override
protected int getContinueActionButton()
{
return R.id.btn__continue;
}
@Override
public void dismiss()
{
if (mDetailDialog != null)
mDetailDialog.dismiss();
super.dismiss();
}
}

View file

@ -0,0 +1,90 @@
package com.mapswithme.maps.permissions;
import android.app.Dialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.view.View;
import android.view.Window;
import com.mapswithme.maps.R;
import com.mapswithme.maps.SplashActivity;
import com.mapswithme.maps.base.BaseMwmDialogFragment;
public class StoragePermissionsDialogFragment extends BaseMwmDialogFragment implements View.OnClickListener
{
@Nullable
public static DialogFragment show(@NonNull FragmentActivity activity)
{
final FragmentManager fm = activity.getSupportFragmentManager();
if (fm.isDestroyed())
return null;
Fragment f = fm.findFragmentByTag(StoragePermissionsDialogFragment.class.getName());
if (f != null)
return (DialogFragment) f;
StoragePermissionsDialogFragment dialog = new StoragePermissionsDialogFragment();
dialog.setCancelable(false);
dialog.show(fm, StoragePermissionsDialogFragment.class.getName());
return dialog;
}
public static DialogFragment find(SplashActivity activity)
{
final FragmentManager fm = activity.getSupportFragmentManager();
if (fm.isDestroyed())
return null;
Fragment f = fm.findFragmentByTag(StoragePermissionsDialogFragment.class.getName());
return (DialogFragment) f;
}
@Override
protected int getCustomTheme()
{
return super.getFullscreenTheme();
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
Dialog res = super.onCreateDialog(savedInstanceState);
res.requestWindowFeature(Window.FEATURE_NO_TITLE);
View content = View.inflate(getActivity(), R.layout.fragment_storage_permissions, null);
res.setContentView(content);
content.findViewById(R.id.btn__exit).setOnClickListener(this);
content.findViewById(R.id.btn__settings).setOnClickListener(this);
return res;
}
@Override
public void onClick(@NonNull View v)
{
switch (v.getId())
{
case R.id.btn__exit:
getActivity().finish();
break;
case R.id.btn__settings:
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getContext().getPackageName(), null);
intent.setData(uri);
startActivity(intent);
break;
}
}
}

View file

@ -2,6 +2,7 @@ package com.mapswithme.util;
import android.support.annotation.NonNull;
import com.mapswithme.maps.BuildConfig;
import com.mapswithme.maps.MwmApplication;
import static com.mapswithme.util.Counters.KEY_APP_FIRST_INSTALL_FLAVOR;
@ -104,14 +105,17 @@ public final class Config
public static void migrateCountersToSharedPrefs()
{
nativeReload();
int version = getInt(KEY_APP_FIRST_INSTALL_VERSION, BuildConfig.VERSION_CODE);
MwmApplication.prefs()
.edit()
.putInt(KEY_APP_LAUNCH_NUMBER, getInt(KEY_APP_LAUNCH_NUMBER))
.putInt(KEY_APP_FIRST_INSTALL_VERSION, getInt(KEY_APP_FIRST_INSTALL_VERSION))
.putInt(KEY_APP_FIRST_INSTALL_VERSION, version)
.putString(KEY_APP_FIRST_INSTALL_FLAVOR, getString(KEY_APP_FIRST_INSTALL_FLAVOR))
.putLong(KEY_APP_LAST_SESSION_TIMESTAMP, getLong(KEY_APP_LAST_SESSION_TIMESTAMP))
.putInt(KEY_APP_SESSION_NUMBER, getInt(KEY_APP_SESSION_NUMBER))
.putBoolean(KEY_MISC_FIRST_START_DIALOG_SEEN, getBool(KEY_MISC_FIRST_START_DIALOG_SEEN))
.putBoolean(KEY_MISC_FIRST_START_DIALOG_SEEN,
getBool(KEY_MISC_FIRST_START_DIALOG_SEEN))
.putInt(KEY_MISC_NEWS_LAST_VERSION, getInt(KEY_MISC_NEWS_LAST_VERSION))
.putInt(KEY_LIKES_LAST_RATED_SESSION, getInt(KEY_LIKES_LAST_RATED_SESSION))
.apply();
@ -332,4 +336,5 @@ public final class Config
private static native void nativeSetLargeFontsSize(boolean value);
private static native boolean nativeGetTransliteration();
private static native void nativeSetTransliteration(boolean value);
private static native void nativeReload();
}

View file

@ -15,8 +15,8 @@ import java.util.Map;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.GET_ACCOUNTS;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.support.v4.app.ActivityCompat.shouldShowRequestPermissionRationale;
public final class PermissionsUtils
{
@ -24,8 +24,13 @@ public final class PermissionsUtils
{
WRITE_EXTERNAL_STORAGE,
ACCESS_COARSE_LOCATION,
ACCESS_FINE_LOCATION,
GET_ACCOUNTS
ACCESS_FINE_LOCATION
};
private static final String[] LOCATION_PERMISSIONS = new String[]
{
ACCESS_COARSE_LOCATION,
ACCESS_FINE_LOCATION
};
private PermissionsUtils() {}
@ -48,16 +53,17 @@ public final class PermissionsUtils
return checkPermissions().isLocationGranted();
}
public static boolean isLocationExplanationNeeded(@NonNull Activity activity)
{
return shouldShowRequestPermissionRationale(activity, ACCESS_COARSE_LOCATION)
|| shouldShowRequestPermissionRationale(activity, ACCESS_FINE_LOCATION);
}
public static boolean isExternalStorageGranted()
{
return checkPermissions().isExternalStorageGranted();
}
public static boolean isGetAccountsGranted()
{
return checkPermissions().isGetAccountsGranted();
}
@NonNull
private static PermissionsResult checkPermissions()
{
@ -82,13 +88,16 @@ public final class PermissionsUtils
? result.get(ACCESS_COARSE_LOCATION) : false)
|| (result.containsKey(ACCESS_FINE_LOCATION)
? result.get(ACCESS_FINE_LOCATION) : false);
boolean getAccountsGranted = result.containsKey(GET_ACCOUNTS)
? result.get(GET_ACCOUNTS) : false;
return new PermissionsResult(externalStorageGranted, locationGranted, getAccountsGranted);
return new PermissionsResult(externalStorageGranted, locationGranted);
}
public static void requestPermissions(@NonNull Activity activity, int code)
{
ActivityCompat.requestPermissions(activity, PERMISSIONS, code);
}
public static void requestLocationPermission(@NonNull Activity activity, int code)
{
ActivityCompat.requestPermissions(activity, LOCATION_PERMISSIONS, code);
}
}

View file

@ -4,14 +4,11 @@ public final class PermissionsResult
{
private final boolean mExternalStorageGranted;
private final boolean mLocationGranted;
private final boolean mGetAccountsGranted;
public PermissionsResult(boolean externalStorageGranted, boolean locationGranted,
boolean getAccountsGranted)
public PermissionsResult(boolean externalStorageGranted, boolean locationGranted)
{
mExternalStorageGranted = externalStorageGranted;
mLocationGranted = locationGranted;
mGetAccountsGranted = getAccountsGranted;
}
public boolean isExternalStorageGranted()
@ -23,9 +20,4 @@ public final class PermissionsResult
{
return mLocationGranted;
}
public boolean isGetAccountsGranted()
{
return mGetAccountsGranted;
}
}

View file

@ -25,9 +25,11 @@ char const * kMeasurementUnits = "Units";
StringStorage::StringStorage() : StringStorageBase(GetPlatform().SettingsPathForFile(SETTINGS_FILE_NAME)) {}
StringStorage & StringStorage::Instance()
StringStorage & StringStorage::Instance(bool reload)
{
static StringStorage inst;
if (reload)
inst = StringStorage();
return inst;
}

View file

@ -21,7 +21,7 @@ string ToString(T const & value);
class StringStorage : public platform::StringStorageBase
{
public:
static StringStorage & Instance();
static StringStorage & Instance(bool reload = false);
private:
StringStorage();
@ -42,6 +42,7 @@ void Set(string const & key, Value const & value)
StringStorage::Instance().SetValue(key, ToString(value));
}
inline void Reload() { StringStorage::Instance(true); }
inline void Delete(string const & key) { StringStorage::Instance().DeleteKeyAndValue(key); }
inline void Clear() { StringStorage::Instance().Clear(); }

View file

@ -49,6 +49,17 @@ StringStorageBase::StringStorageBase(string const & path) : m_path(path)
}
}
StringStorageBase::StringStorageBase(StringStorageBase const & rhs)
{
m_values = Container(rhs.m_values.begin(), rhs.m_values.end());
}
StringStorageBase& StringStorageBase::operator=(StringStorageBase const & rhs)
{
m_values = Container(rhs.m_values.begin(), rhs.m_values.end());
return *this;
}
void StringStorageBase::Save() const
{
try

View file

@ -10,11 +10,14 @@ class StringStorageBase
{
public:
StringStorageBase(std::string const & path);
StringStorageBase(StringStorageBase const & rhs);
void Save() const;
void Clear();
bool GetValue(std::string const & key, std::string & outValue) const;
void SetValue(std::string const & key, std::string && value);
void DeleteKeyAndValue(std::string const & key);
StringStorageBase& operator=(StringStorageBase const & rhs);
private:
using Container = std::map<std::string, std::string>;