Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2018-04-24 18:06:04 +02:00
commit 39e7ba876e
40 changed files with 1866 additions and 1180 deletions

View file

@ -50,8 +50,8 @@ body {
h1 {
font-size: 2em;
color: #212121;
font-family: serif;
letter-spacing: 0.03em;
font-family: RobotoSlab-Regular;
letter-spacing: 0.02em;
word-wrap: break-word;
padding-top: 5%;
font-weight: normal;
@ -59,14 +59,14 @@ h1 {
h2 {
font-size: 1.5em;
color: #575757;
color: #454545;
font-family: RobotoSlab-Regular;
font-weight:100;
word-wrap: break-word;
margin-top: 3%;
padding-bottom: 3%;
/* font-weight: bold; */
padding-top: 2%;
padding-bottom: 4%;
line-height: 1.6em;
letter-spacing: 0.01em;
letter-spacing: 0.015em;
border-bottom: 1px solid #eaecf0;
width: 100%;
}
@ -105,7 +105,7 @@ h3 {
font-family: sans-serif;
word-wrap: break-word;
font-weight: bold;
margin-top: 3%;
margin-top: 5%;
margin-bottom: 3%;
line-height: 1.6em;
}
@ -113,7 +113,7 @@ h3 {
p {
font-family: sans-serif;
font-size: 1.1em;
line-height: 1.5em;
line-height: 1.6em;
}
ul {
@ -162,8 +162,8 @@ pre {
.geo {
background-color: #fafafa;
border: 1px solid #e6e6e6;
border-radius: 5px;
padding: 3% 3% 3% 3%;
border-radius: 4px;
padding: 10px 10px 10px 10px;
color: #237bff;
font-size: 0.9em;
font-weight: bold;
@ -174,7 +174,7 @@ pre {
@font-face {
font-family: RobotoSlab-Regular;
src: url("file:///assets/fonts/RobotoSlab-Regular.ttf")
src: url("fonts/RobotoSlab-Regular.ttf")
}
td {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View file

@ -6,9 +6,11 @@
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/shared_string_explore"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="@dimen/map_markers_recycler_view_padding_bottom"/>
</LinearLayout>

View file

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/freeVersionBanner"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/freeVersionBanner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/osmo_header_dark"
@ -17,11 +16,6 @@
android:paddingBottom="@dimen/list_header_padding"
android:paddingTop="@dimen/list_header_padding">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/bannerTopLayout"
android:layout_width="match_parent"
@ -80,158 +74,6 @@
</LinearLayout>
<LinearLayout
android:id="@+id/priceInfoLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/list_content_padding"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/dashboard_divider_dark"
android:visibility="visible"/>
<LinearLayout
android:id="@+id/fullVersionLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/list_content_padding"
android:orientation="horizontal"
android:visibility="visible">
<android.support.v7.widget.AppCompatImageView
android:layout_width="54dp"
android:layout_height="32dp"
android:scaleType="center"
android:src="@drawable/ic_action_osmand_logo"
android:tint="@color/osmand_orange"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/list_content_padding"
android:orientation="vertical">
<TextView
android:id="@+id/fullVersionTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/osmand_unlimited"
android:textSize="@dimen/default_list_text_size_large"
android:textStyle="bold"/>
<TextView
android:id="@+id/fullVersionDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/osmand_plus_banner_desc"/>
<ProgressBar
android:id="@+id/fullVersionProgress"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="16dp"
android:indeterminate="true"
android:visibility="gone"/>
<android.support.v7.widget.AppCompatButton
android:id="@+id/fullVersionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:background="@drawable/blue_button_drawable"
android:paddingBottom="4dp"
android:paddingLeft="14dp"
android:paddingRight="14dp"
android:paddingTop="4dp"
android:textColor="@color/color_white"
android:visibility="visible"
tools:text="GET FOR 5 EUR"/>
</LinearLayout>
</LinearLayout>
<View
android:id="@+id/osmLiveLayoutTopDivider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="54dp"
android:layout_marginTop="@dimen/list_content_padding"
android:background="@color/dashboard_divider_dark"
android:visibility="visible"/>
<LinearLayout
android:id="@+id/osmLiveLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/list_content_padding"
android:layout_marginBottom="@dimen/list_content_padding"
android:orientation="horizontal">
<android.support.v7.widget.AppCompatImageView
android:layout_width="54dp"
android:layout_height="32dp"
android:scaleType="center"
android:src="@drawable/ic_action_osm_live"
android:tint="@color/osmand_orange"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/list_content_padding"
android:orientation="vertical">
<TextView
android:id="@+id/osmLiveTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/osm_live_subscription"
android:textSize="@dimen/default_list_text_size_large"
android:textStyle="bold"/>
<TextView
android:id="@+id/osmLiveDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/osm_live_banner_desc"/>
<ProgressBar
android:id="@+id/osmLiveProgress"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="16dp"
android:indeterminate="true"
android:visibility="gone"/>
<android.support.v7.widget.AppCompatButton
android:id="@+id/osmLiveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:background="@drawable/blue_button_drawable"
android:paddingBottom="4dp"
android:paddingLeft="14dp"
android:paddingRight="14dp"
android:paddingTop="4dp"
android:textColor="@color/color_white"
tools:text="GET FOR 1,5 EUR PER MONTH"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>

View file

@ -13,11 +13,19 @@
android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/card_button_min_size"
android:orientation="vertical"
android:gravity="center"
android:paddingBottom="@dimen/list_header_padding"
android:paddingLeft="@dimen/list_content_padding"
android:paddingRight="@dimen/list_content_padding"
android:paddingTop="@dimen/list_header_padding">
<ProgressBar
android:id="@+id/card_button_progress"
android:layout_width="@dimen/card_button_progress_size"
android:layout_height="@dimen/card_button_progress_size"
android:indeterminate="true"
android:visibility="gone"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/card_button_title"
android:layout_width="match_parent"

View file

@ -21,7 +21,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/action_bar_height"
android:layout_height="wrap_content"
android:orientation="horizontal">
<android.support.v7.widget.AppCompatImageView
@ -33,6 +33,17 @@
android:src="@drawable/ic_arrow_back"
android:tint="@color/icon_color"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/list_header_padding"
android:text="@string/purchase_dialog_title"
android:textColor="?attr/dialog_title_color"
android:textSize="@dimen/dialog_header_text_size"
osmand:typeface="@string/font_roboto_medium"/>
</LinearLayout>
<LinearLayout
@ -43,16 +54,6 @@
android:layout_marginRight="@dimen/list_content_padding_large"
android:orientation="vertical">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/title_padding"
android:text="@string/purchase_dialog_title"
android:textColor="?attr/dialog_title_color"
android:textSize="@dimen/title_text_size"
osmand:typeface="@string/font_roboto_medium"/>
<LinearLayout
android:id="@+id/info_container"
android:layout_width="match_parent"
@ -70,16 +71,6 @@
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/list_content_padding_large"
android:text="@string/purchase_dialog_subtitle"
android:textColor="?attr/dialog_description_color"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_medium"/>
</LinearLayout>

View file

@ -25,12 +25,12 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/content_padding"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginTop="2dp"
android:layout_marginTop="4dp"
android:layout_weight="1"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?attr/wikivoyage_primary_text_color"
android:textSize="@dimen/travel_card_title_text_size"
android:textSize="@dimen/travel_card_primary_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="Download file"/>
@ -48,7 +48,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/wikivoyage_secondary_text"
android:textSize="@dimen/travel_card_title_size"
android:textSize="@dimen/travel_card_primary_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Download this Wikivoyage travel guides file to view articles about places around the world without an internet connection."/>
@ -56,15 +56,17 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_selected_item_title_height"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/content_padding"
android:layout_marginLeft="@dimen/bottom_sheet_content_margin_small"
android:layout_marginRight="@dimen/bottom_sheet_content_margin_small"
android:background="@drawable/travel_card_stroke_bg"
android:minHeight="@dimen/bottom_sheet_selected_item_title_height"
android:paddingLeft="@dimen/content_padding"
android:paddingRight="@dimen/content_padding">
<ImageView
android:id="@+id/file_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
@ -81,7 +83,7 @@
android:layout_weight="1"
android:orientation="vertical">
<TextView
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/file_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -89,9 +91,10 @@
android:maxLines="1"
android:textColor="?attr/wikivoyage_primary_text_color"
android:textSize="@dimen/default_list_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Wikivoyage"/>
<TextView
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/file_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -99,8 +102,19 @@
android:maxLines="1"
android:textColor="@color/wikivoyage_secondary_text"
android:textSize="@dimen/default_sub_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="255 Mb • Update 11 April"/>
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:minHeight="0dp"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
</LinearLayout>
@ -119,22 +133,25 @@
android:background="@drawable/wikivoyage_secondary_btn_bg">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/left_button"
android:id="@+id/secondary_button"
android:layout_width="match_parent"
android:layout_height="@dimen/wikivoyage_card_button_height"
android:layout_gravity="center"
android:background="?attr/selectableItemBackgroundBorderless"
android:ellipsize="end"
android:gravity="center"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="1"
android:textColor="?attr/wikivoyage_active_color"
android:textSize="@dimen/text_button_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:ignore="UnusedAttribute"
tools:text="Later"/>
</FrameLayout>
<View
android:id="@+id/buttons_divider"
android:layout_width="@dimen/bottom_sheet_content_margin_small"
android:layout_height="match_parent"/>
@ -145,17 +162,19 @@
android:background="@drawable/wikivoyage_primary_btn_bg">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/right_button"
android:id="@+id/primary_button"
android:layout_width="match_parent"
android:layout_height="@dimen/wikivoyage_card_button_height"
android:layout_gravity="center"
android:background="?attr/selectableItemBackgroundBorderless"
android:ellipsize="end"
android:gravity="center"
android:letterSpacing="@dimen/text_button_letter_spacing"
android:maxLines="1"
android:textColor="?attr/wikivoyage_primary_btn_text_color"
android:textSize="@dimen/text_button_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:ignore="UnusedAttribute"
tools:text="Update"/>
</FrameLayout>

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginTop="@dimen/list_content_padding"
android:background="@drawable/travel_card_bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/background_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/welcome_to_open_beta"
tools:src="@drawable/img_help_wikivoyage_articles" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginTop="@dimen/bottom_sheet_icon_margin"
tools:text="@string/welcome_to_open_beta" />
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:layout_marginStart="@dimen/list_content_padding"
tools:text="@string/welcome_to_open_beta_description" />
<View
android:id="@+id/bottom_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/wikivoyage_card_divider_color" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/bottom_button_text"
android:layout_width="wrap_content"
android:layout_height="@dimen/bottom_sheet_title_height"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:gravity="center"
android:textColor="?attr/color_dialog_buttons"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/get_unlimited_access" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginTop="@dimen/list_content_padding"
android:background="@drawable/travel_card_bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/wikivoyage_start_editing_image_background"
android:orientation="horizontal">
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginTop="42dp"
android:layout_weight="1"
android:textColor="@color/primary_text_dark"
tools:text="@string/start_editing_card_image_text" />
<ImageView
android:id="@+id/background_image"
android:layout_width="wrap_content"
android:layout_height="@dimen/wikivoyage_explore_card_image_height"
android:contentDescription="@string/welcome_to_open_beta"
android:src="@drawable/img_help_wikivoyage_contribute" />
</LinearLayout>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginEnd="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:layout_marginRight="@dimen/list_content_padding"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginTop="@dimen/list_content_padding"
tools:text="@string/start_editing_card_description" />
<View
android:id="@+id/bottom_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/wikivoyage_card_divider_color" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/bottom_button_text"
android:layout_width="wrap_content"
android:layout_height="@dimen/bottom_sheet_title_height"
android:layout_gravity="center"
android:gravity="center"
android:background="?attr/selectableItemBackground"
android:textColor="?attr/color_dialog_buttons"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/start_editing" />
</LinearLayout>
</LinearLayout>

View file

@ -101,7 +101,7 @@
<dimen name="default_sub_text_size_small">12sp</dimen>
<dimen name="welcome_header_text_size">27sp</dimen>
<dimen name="text_button_text_size">22sp</dimen>
<dimen name="travel_card_title_text_size">22sp</dimen>
<dimen name="travel_card_primary_text_size">22sp</dimen>
<dimen name="dialog_header_text_size">24sp</dimen>

View file

@ -428,5 +428,6 @@
<color name="wikivoyage_primary_text_light">#212121</color>
<color name="wikivoyage_primary_text_dark">#cccccc</color>
<color name="wikivoyage_secondary_text">#727272</color>
<color name="wikivoyage_start_editing_image_background">#339966</color>
</resources>

View file

@ -7,7 +7,8 @@
<dimen name="title_text_size">28sp</dimen>
<dimen name="card_title_row_min_height">64dp</dimen>
<dimen name="card_row_min_height">48dp</dimen>
<dimen name="card_button_min_size">52dp</dimen>
<dimen name="card_button_min_size">58dp</dimen>
<dimen name="card_button_progress_size">32dp</dimen>
<dimen name="widget_turn_lane_size">36dp</dimen>
<dimen name="widget_turn_lane_border">6dp</dimen>
@ -175,7 +176,7 @@
<dimen name="default_sub_text_size_small">10sp</dimen>
<dimen name="welcome_header_text_size">23sp</dimen>
<dimen name="text_button_text_size">15sp</dimen>
<dimen name="travel_card_title_text_size">15sp</dimen>
<dimen name="travel_card_primary_text_size">15sp</dimen>
<dimen name="default_split_segments_overview">13sp</dimen>
<dimen name="default_split_segments_data">13sp</dimen>
@ -291,5 +292,7 @@
<dimen name="wikivoyage_search_icon_margin_right">22dp</dimen>
<dimen name="wikivoyage_search_divider_margin_start">64dp</dimen>
<dimen name="wikivoyage_explore_card_image_height">144dp</dimen>
<dimen name="text_button_letter_spacing" format="float">0.01</dimen>
</resources>

View file

@ -9,6 +9,16 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="travel_card_update_descr">We prepared updates and fixes in the Wikivoyage data, update the file to see them.</string>
<string name="travel_card_download_descr">Download this Wikivoyage travel guides file to view articles about places around the world without an internet connection.</string>
<string name="update_is_available">Update is available</string>
<string name="download_file">Download file</string>
<string name="start_editing_card_image_text">The free worldwide travel guide that anyone can edit.</string>
<string name="welcome_to_open_beta_description">Travel is based on Wikivoyage. During open beta testing you have the opportunity to evaluate all the features for free. After the end of the beta period, Travel will be available to subscribers of OsmAnd Unlimited and the owners of OsmAnd+</string>
<string name="start_editing_card_description">You can edit any article on Wikivoyage, and we hope that you do. We need your knowledge, your experience, your talent, and your attention</string>
<string name="start_editing">Start editing</string>
<string name="get_unlimited_access">Get unlimited access</string>
<string name="welcome_to_open_beta">Welcome, to the open beta!</string>
<string name="travel_guide">Travel Guide</string>
<string name="travel_guide_description">Browse the Wikivoyage guides to the most interesting places on the planet inside OsmAnd without an internet connection.</string>
<string name="monthly_map_updates">Map updates: <b>every month</b></string>
@ -23,7 +33,7 @@
<string name="unlimited_downloads">Unlimited downloads</string>
<string name="wikipedia_offline">Wikipedia offline</string>
<string name="contour_lines_sea_depth">Contour lines + Sea depth</string>
<string name="contour_lines_hillshade_maps">Contour lines &amp; Hillshade maps</string>
<string name="unlock_all_features">Unlock all OsmAnd features</string>
<string name="purchase_dialog_title">Choose plan</string>
@ -2854,4 +2864,12 @@
<string name="toast_empty_name_error">Location has no name</string>
<string name="tunnel_warning">Tunnel ahead</string>
<string name="show_tunnels">Tunnels</string>
<string name="download_wikipedia_description">Download the Wikipedia articles for %1$s to read them offline.</string>
<string name="download_wikipedia_label">Download Wikipedia data</string>
<string name="open_in_browser_wiki">Open article online</string>
<string name="open_in_browser_wiki_description">View this article in a browser.</string>
<string name="download_wiki_region_placeholder">this region</string>
<string name="wiki_article_search_text">Searching for the necessary wiki article</string>
<string name="wiki_article_not_found">Article not found</string>
<string name="how_to_open_wiki_title">How to open Wikipedia articles?</string>
</resources>

View file

@ -577,6 +577,10 @@
<item name="android:windowLightStatusBar">true</item>
</style>
<style name="OsmandLightTheme.DarkActionbar.LightStatusBar">
<item name="android:windowLightStatusBar">true</item>
</style>
<style name="XmasDialogTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="android:background">@color/xmas_blue</item>
</style>

View file

@ -31,6 +31,7 @@ import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
import net.osmand.plus.helpers.AvoidSpecificRoads;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.liveupdates.LiveUpdatesHelper;
import net.osmand.plus.mapmarkers.MapMarkersDbHelper;
import net.osmand.plus.monitoring.LiveMonitoringHelper;
@ -421,6 +422,7 @@ public class AppInitializer implements IProgress {
e.printStackTrace();
}
app.applyTheme(app);
app.inAppPurchaseHelper = startupInit(new InAppPurchaseHelper(app), InAppPurchaseHelper.class);
app.poiTypes = startupInit(MapPoiTypes.getDefaultNoInit(), MapPoiTypes.class);
app.routingHelper = startupInit(new RoutingHelper(app), RoutingHelper.class);
app.resourceManager = startupInit(new ResourceManager(app), ResourceManager.class);

View file

@ -19,7 +19,6 @@ import android.support.multidex.MultiDex;
import android.support.multidex.MultiDexApplication;
import android.support.v7.app.AlertDialog;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.ImageView;
@ -46,7 +45,7 @@ import net.osmand.plus.dialogs.RateUsBottomSheetDialog;
import net.osmand.plus.download.DownloadIndexesThread;
import net.osmand.plus.helpers.AvoidSpecificRoads;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.mapcontextmenu.other.RoutePreferencesMenu;
import net.osmand.plus.mapmarkers.MapMarkersDbHelper;
import net.osmand.plus.monitoring.LiveMonitoringHelper;
@ -120,6 +119,7 @@ public class OsmandApplication extends MultiDexApplication {
GeocodingLookupService geocodingLookupService;
QuickSearchHelper searchUICore;
TravelDbHelper travelDbHelper;
InAppPurchaseHelper inAppPurchaseHelper;
RoutingConfiguration.Builder defaultRoutingConfig;
private Locale preferredLocale = null;
@ -166,7 +166,6 @@ public class OsmandApplication extends MultiDexApplication {
// if(!osmandSettings.FOLLOW_THE_ROUTE.get()) {
// targetPointsHelper.clearPointToNavigate(false);
// }
InAppHelper.initialize(this);
initExternalLibs();
startApplication();
System.out.println("Time to start application " + (System.currentTimeMillis() - timeToStart) + " ms. Should be less < 800 ms");
@ -396,6 +395,10 @@ public class OsmandApplication extends MultiDexApplication {
return travelDbHelper;
}
public InAppPurchaseHelper getInAppPurchaseHelper() {
return inAppPurchaseHelper;
}
public CommandPlayer getPlayer() {
return player;
}

View file

@ -976,6 +976,8 @@ public class OsmandSettings {
public final OsmandPreference<Integer> DISCOUNT_TOTAL_SHOW = new IntPreference("discount_total_show", 0).makeGlobal();
public final OsmandPreference<Long> DISCOUNT_SHOW_DATETIME_MS = new LongPreference("show_discount_datetime_ms", 0).makeGlobal();
public final OsmandPreference<Boolean> TRAVEL_ARTICLES_PURCHASED = new BooleanPreference("travel_articles_purchased", false).makeGlobal();
// this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<String> USER_OSM_BUG_NAME =
new StringPreference("user_osm_bug_name", "NoName/OsmAnd").makeGlobal();

View file

@ -92,7 +92,8 @@ import net.osmand.plus.helpers.ExternalApiHelper;
import net.osmand.plus.helpers.ImportHelper;
import net.osmand.plus.helpers.ImportHelper.ImportGpxBottomSheetDialogFragment;
import net.osmand.plus.helpers.WakeLockHelper;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.mapcontextmenu.AdditionalActionsBottomSheetDialogFragment;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.MapContextMenuFragment;
@ -204,7 +205,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
private boolean permissionGranted;
private boolean mIsDestroyed = false;
private InAppHelper inAppHelper;
private InAppPurchaseHelper inAppPurchaseHelper;
private Timer splashScreenTimer;
private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
@ -1214,8 +1215,8 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
if (atlasMapRendererView != null) {
atlasMapRendererView.handleOnDestroy();
}
if (inAppHelper != null) {
inAppHelper.stop();
if (inAppPurchaseHelper != null) {
inAppPurchaseHelper.stop();
}
mIsDestroyed = true;
}
@ -1513,7 +1514,7 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (inAppHelper != null && inAppHelper.onActivityResultHandled(requestCode, resultCode, data)) {
if (inAppPurchaseHelper != null && inAppPurchaseHelper.onActivityResultHandled(requestCode, resultCode, data)) {
return;
}
for (ActivityResultListener listener : activityResultListeners) {
@ -1920,43 +1921,4 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
DESTINATION_SELECTION,
INTERMEDIATE_SELECTION
}
public InAppHelper execInAppTask(@NonNull InAppHelper.InAppRunnable runnable) {
if (inAppHelper != null) {
inAppHelper.stop();
}
if (Version.isGooglePlayEnabled(app)) {
inAppHelper = new InAppHelper(getMyApplication(), false);
inAppHelper.addListener(new InAppHelper.InAppListener() {
@Override
public void onError(String error) {
inAppHelper = null;
}
@Override
public void onGetItems() {
inAppHelper = null;
}
@Override
public void onItemPurchased(String sku) {
inAppHelper = null;
}
@Override
public void showProgress() {
}
@Override
public void dismissProgress() {
}
});
inAppHelper.exec(runnable);
return inAppHelper;
} else {
return null;
}
}
}

View file

@ -1,5 +1,6 @@
package net.osmand.plus.activities;
import android.annotation.SuppressLint;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
@ -11,7 +12,8 @@ import android.view.ViewGroup;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
public class OsmandActionBarActivity extends AppCompatActivity {
@SuppressLint("Registered")
public class OsmandActionBarActivity extends OsmandInAppPurchaseActivity {
protected boolean haveHomeButton = true;
@ -50,8 +52,4 @@ public class OsmandActionBarActivity extends AppCompatActivity {
setupHomeButton();
}
}
public OsmandApplication getMyApplication() {
return (OsmandApplication) getApplication();
}
}

View file

@ -0,0 +1,166 @@
package net.osmand.plus.activities;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.Version;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import org.apache.commons.logging.Log;
import static net.osmand.plus.OsmandApplication.SHOW_PLUS_VERSION_INAPP_PARAM;
@SuppressLint("Registered")
public class OsmandInAppPurchaseActivity extends AppCompatActivity implements InAppPurchaseListener {
private static final Log LOG = PlatformUtil.getLog(OsmandInAppPurchaseActivity.class);
private InAppPurchaseHelper purchaseHelper;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isInAppPurchaseAllowed() && isInAppPurchaseSupported()) {
purchaseHelper = getMyApplication().getInAppPurchaseHelper();
}
}
@Override
protected void onResume() {
super.onResume();
initInAppPurchaseHelper();
}
@Override
protected void onDestroy() {
super.onDestroy();
deinitInAppPurchaseHelper();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Pass on the activity result to the helper for handling
if (purchaseHelper == null || !purchaseHelper.onActivityResultHandled(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
}
private void initInAppPurchaseHelper() {
deinitInAppPurchaseHelper();
if (purchaseHelper != null) {
purchaseHelper.addListener(this);
if (purchaseHelper.needRequestInventory()) {
purchaseHelper.requestInventory();
}
}
}
private void deinitInAppPurchaseHelper() {
if (purchaseHelper != null) {
purchaseHelper.removeListener(this);
purchaseHelper.stop();
}
}
public void purchaseFullVersion() {
OsmandApplication app = getMyApplication();
if (Version.isFreeVersion(app)) {
if (app.getRemoteBoolean(SHOW_PLUS_VERSION_INAPP_PARAM, true)) {
if (purchaseHelper != null) {
app.logEvent(this, "in_app_purchase_redirect");
purchaseHelper.purchaseFullVersion(this);
}
} else {
app.logEvent(this, "paid_version_redirect");
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(Version.getUrlWithUtmRef(app, "net.osmand.plus")));
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
LOG.error("ActivityNotFoundException", e);
}
}
}
}
public void purchaseDepthContours() {
if (purchaseHelper != null) {
getMyApplication().logEvent(this, "depth_contours_purchase_redirect");
purchaseHelper.purchaseDepthContours(this);
}
}
public OsmandApplication getMyApplication() {
return (OsmandApplication) getApplication();
}
@Nullable
public InAppPurchaseHelper getPurchaseHelper() {
return purchaseHelper;
}
public boolean isInAppPurchaseAllowed() {
return false;
}
public boolean isInAppPurchaseSupported() {
return Version.isGooglePlayEnabled(getMyApplication());
}
@Override
public void onError(InAppPurchaseTaskType taskType, String error) {
onInAppPurchaseError(taskType, error);
}
@Override
public void onGetItems() {
onInAppPurchaseGetItems();
}
@Override
public void onItemPurchased(String sku) {
onInAppPurchaseItemPurchased(sku);
}
@Override
public void showProgress(InAppPurchaseTaskType taskType) {
showInAppPurchaseProgress(taskType);
}
@Override
public void dismissProgress(InAppPurchaseTaskType taskType) {
dismissInAppPurchaseProgress(taskType);
}
public void onInAppPurchaseError(InAppPurchaseTaskType taskType, String error) {
// not implemented
}
public void onInAppPurchaseGetItems() {
// not implemented
}
public void onInAppPurchaseItemPurchased(String sku) {
// not implemented
}
public void showInAppPurchaseProgress(InAppPurchaseTaskType taskType) {
// not implemented
}
public void dismissInAppPurchaseProgress(InAppPurchaseTaskType taskType) {
// not implemented
}
}

View file

@ -6,11 +6,14 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@ -18,68 +21,117 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadValidationManager;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.liveupdates.OsmLiveActivity;
import net.osmand.plus.srtmplugin.SRTMPlugin;
import net.osmand.plus.widgets.TextViewEx;
import org.apache.commons.logging.Log;
import static net.osmand.plus.OsmandApplication.SHOW_PLUS_VERSION_INAPP_PARAM;
public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment implements InAppPurchaseListener {
public static final String TAG = ChoosePlanDialogFragment.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(ChoosePlanDialogFragment.class);
private static final String PLAN_TYPE_KEY = "plan_type";
private OsmandApplication app;
private InAppPurchaseHelper purchaseHelper;
private boolean nightMode;
private PlanType planType;
private OsmAndFeature[] osmandLiveFeatures = {
OsmAndFeature.UNLIMITED_DOWNLOADS,
OsmAndFeature.DAILY_MAP_UPDATES,
OsmAndFeature.WIKIPEDIA_OFFLINE,
OsmAndFeature.WIKIVOYAGE_OFFLINE,
OsmAndFeature.CONTOUR_LINES_SEA_DEPTH,
OsmAndFeature.DONATION_TO_OSM,
// OsmAndFeature.UNLOCK_ALL_FEATURES,
};
private OsmAndFeature[] osmandUnlimitedFeatures = {
OsmAndFeature.UNLIMITED_DOWNLOADS,
OsmAndFeature.MONTHLY_MAP_UPDATES,
OsmAndFeature.WIKIPEDIA_OFFLINE,
OsmAndFeature.WIKIVOYAGE_OFFLINE,
};
private View osmLiveCardButton;
private View planTypeCardButton;
public enum PlanType {
FREE_VERSION_BANNER(OsmAndFeature.UNLIMITED_DOWNLOADS, OsmAndFeature.UNLIMITED_DOWNLOADS);
FREE_VERSION_BANNER(
new OsmAndFeature[]{
OsmAndFeature.DAILY_MAP_UPDATES,
OsmAndFeature.UNLIMITED_DOWNLOADS,
OsmAndFeature.WIKIPEDIA_OFFLINE,
OsmAndFeature.WIKIVOYAGE_OFFLINE,
OsmAndFeature.CONTOUR_LINES_HILLSHADE_MAPS,
OsmAndFeature.SEA_DEPTH_MAPS,
OsmAndFeature.UNLOCK_ALL_FEATURES,
OsmAndFeature.DONATION_TO_OSM,
},
new OsmAndFeature[]{
OsmAndFeature.DAILY_MAP_UPDATES,
OsmAndFeature.UNLIMITED_DOWNLOADS,
},
new OsmAndFeature[]{
OsmAndFeature.WIKIPEDIA_OFFLINE,
OsmAndFeature.WIKIVOYAGE_OFFLINE,
OsmAndFeature.UNLIMITED_DOWNLOADS,
OsmAndFeature.MONTHLY_MAP_UPDATES,
},
new OsmAndFeature[]{});
private final OsmAndFeature osmandLiveFeature;
private final OsmAndFeature osmandUnlimitedFeature;
private final OsmAndFeature[] osmLiveFeatures;
private final OsmAndFeature[] planTypeFeatures;
private final OsmAndFeature[] selectedOsmLiveFeatures;
private final OsmAndFeature[] selectedPlanTypeFeatures;
PlanType(OsmAndFeature osmandLiveFeature, OsmAndFeature osmandUnlimitedFeature) {
this.osmandLiveFeature = osmandLiveFeature;
this.osmandUnlimitedFeature = osmandUnlimitedFeature;
PlanType(OsmAndFeature[] osmLiveFeatures, OsmAndFeature[] selectedOsmLiveFeatures,
OsmAndFeature[] planTypeFeatures, OsmAndFeature[] selectedPlanTypeFeatures) {
this.osmLiveFeatures = osmLiveFeatures;
this.planTypeFeatures = planTypeFeatures;
this.selectedOsmLiveFeatures = selectedOsmLiveFeatures;
this.selectedPlanTypeFeatures = selectedPlanTypeFeatures;
}
public OsmAndFeature getOsmandLiveFeature() {
return osmandLiveFeature;
public OsmAndFeature[] getOsmLiveFeatures() {
return osmLiveFeatures;
}
public OsmAndFeature getOsmandUnlimitedFeature() {
return osmandUnlimitedFeature;
public OsmAndFeature[] getPlanTypeFeatures() {
return planTypeFeatures;
}
public OsmAndFeature[] getSelectedOsmLiveFeatures() {
return selectedOsmLiveFeatures;
}
public OsmAndFeature[] getSelectedPlanTypeFeatures() {
return selectedPlanTypeFeatures;
}
public boolean hasSelectedOsmLiveFeature(OsmAndFeature feature) {
if (selectedOsmLiveFeatures != null) {
for (OsmAndFeature f : selectedOsmLiveFeatures) {
if (feature == f) {
return true;
}
}
}
return false;
}
public boolean hasSelectedPlanTypeFeature(OsmAndFeature feature) {
if (selectedPlanTypeFeatures != null) {
for (OsmAndFeature f : selectedPlanTypeFeatures) {
if (feature == f) {
return true;
}
}
}
return false;
}
}
@ -89,7 +141,8 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
MONTHLY_MAP_UPDATES(R.string.monthly_map_updates),
UNLIMITED_DOWNLOADS(R.string.unlimited_downloads),
WIKIPEDIA_OFFLINE(R.string.wikipedia_offline),
CONTOUR_LINES_SEA_DEPTH(R.string.contour_lines_sea_depth),
CONTOUR_LINES_HILLSHADE_MAPS(R.string.contour_lines_hillshade_maps),
SEA_DEPTH_MAPS(R.string.index_item_depth_contours_osmand_ext),
UNLOCK_ALL_FEATURES(R.string.unlock_all_features),
DONATION_TO_OSM(R.string.donation_to_osm);
@ -103,9 +156,27 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
return ctx.getString(key);
}
public boolean isFeaturePurchased(OsmandApplication ctx) {
switch (this) {
case DAILY_MAP_UPDATES:
case MONTHLY_MAP_UPDATES:
case UNLIMITED_DOWNLOADS:
case WIKIPEDIA_OFFLINE:
case UNLOCK_ALL_FEATURES:
case DONATION_TO_OSM:
return false;
case WIKIVOYAGE_OFFLINE:
return ctx.getSettings().TRAVEL_ARTICLES_PURCHASED.get();
case CONTOUR_LINES_HILLSHADE_MAPS:
boolean srtmEnabled = OsmandPlugin.getEnabledPlugin(SRTMPlugin.class) != null;
return srtmEnabled && ctx.getSettings().DEPTH_CONTOURS_PURCHASED.get();
}
return false;
}
public static OsmAndFeature[] possibleValues() {
return new OsmAndFeature[]{WIKIVOYAGE_OFFLINE, DAILY_MAP_UPDATES, MONTHLY_MAP_UPDATES, UNLIMITED_DOWNLOADS,
WIKIPEDIA_OFFLINE, CONTOUR_LINES_SEA_DEPTH, UNLOCK_ALL_FEATURES, DONATION_TO_OSM};
WIKIPEDIA_OFFLINE, CONTOUR_LINES_HILLSHADE_MAPS, UNLOCK_ALL_FEATURES, DONATION_TO_OSM};
}
}
@ -113,6 +184,9 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = getMyApplication();
purchaseHelper = app.getInAppPurchaseHelper();
Bundle args = getArguments();
if (args == null) {
args = savedInstanceState;
@ -130,13 +204,16 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int themeId = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
Dialog dialog = new Dialog(getContext(), themeId);
Window window = dialog.getWindow();
if (window != null) {
if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) {
window.getAttributes().windowAnimations = R.style.Animations_Alpha;
}
if (Build.VERSION.SDK_INT >= 21) {
window.setStatusBarColor(ContextCompat.getColor(getContext(), getStatusBarColor()));
}
}
return dialog;
}
@ -169,68 +246,28 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
switch (planType) {
case FREE_VERSION_BANNER: {
infoDescription.setText(ctx.getString(R.string.free_version_message,
infoDescription.setText(getString(R.string.free_version_message,
DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS));
//infoDescription.setVisibility(View.GONE);
//View freeVersionInfoView = inflate(R.layout.purchase_dialog_info_free_version, infoContainer);
//initFreeVersionInfoView(ctx, freeVersionInfoView);
//infoContainer.addView(freeVersionInfoView);
break;
}
}
cardsContainer.addView(buildOsmAndLiveCard(ctx, cardsContainer));
cardsContainer.addView(buildOsmAndUnlimitedCard(ctx, cardsContainer));
cardsContainer.addView(buildOsmLiveCard(ctx, cardsContainer));
cardsContainer.addView(buildPlanTypeCard(ctx, cardsContainer));
return view;
}
/*
private void initFreeVersionInfoView(Context ctx, View freeVersionInfoView) {
TextView downloadsLeftTextView = (TextView) freeVersionInfoView.findViewById(R.id.downloadsLeftTextView);
ProgressBar downloadsLeftProgressBar = (ProgressBar) freeVersionInfoView.findViewById(R.id.downloadsLeftProgressBar);
TextView freeVersionDescriptionTextView = (TextView) freeVersionInfoView
.findViewById(R.id.freeVersionDescriptionTextView);
OsmandSettings settings = getMyApplication().getSettings();
final Integer mapsDownloaded = settings.NUMBER_OF_FREE_DOWNLOADS.get();
downloadsLeftProgressBar.setProgress(mapsDownloaded);
int downloadsLeft = DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS - mapsDownloaded;
downloadsLeft = Math.max(downloadsLeft, 0);
downloadsLeftTextView.setText(ctx.getString(R.string.downloads_left_template, downloadsLeft));
downloadsLeftProgressBar.setMax(DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS);
freeVersionDescriptionTextView.setText(ctx.getString(R.string.free_version_message,
DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS));
LinearLayout marksLinearLayout = (LinearLayout) freeVersionInfoView.findViewById(R.id.marksLinearLayout);
Space spaceView = new Space(ctx);
LinearLayout.LayoutParams layoutParams =
new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1);
spaceView.setLayoutParams(layoutParams);
marksLinearLayout.addView(spaceView);
int markWidth = (int) (1 * ctx.getResources().getDisplayMetrics().density);
int colorBlack = ctx.getResources().getColor(nightMode ? R.color.wikivoyage_bg_dark : R.color.wikivoyage_bg_light);
for (int i = 1; i < DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS; i++) {
View markView = new View(ctx);
layoutParams = new LinearLayout.LayoutParams(markWidth, ViewGroup.LayoutParams.MATCH_PARENT);
markView.setLayoutParams(layoutParams);
markView.setBackgroundColor(colorBlack);
marksLinearLayout.addView(markView);
spaceView = new Space(ctx);
layoutParams = new LinearLayout.LayoutParams(0,
ViewGroup.LayoutParams.MATCH_PARENT, 1);
spaceView.setLayoutParams(layoutParams);
marksLinearLayout.addView(spaceView);
@ColorRes
protected int getStatusBarColor() {
return nightMode ? R.color.status_bar_wikivoyage_dark : R.color.status_bar_wikivoyage_light;
}
}
*/
private View inflate(@LayoutRes int layoutId, @Nullable ViewGroup container) {
int themeRes = nightMode ? R.style.OsmandDarkTheme : R.style.OsmandLightTheme;
int themeRes = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
return LayoutInflater.from(new ContextThemeWrapper(getContext(), themeRes))
.inflate(layoutId, container, false);
}
private ViewGroup buildOsmAndLiveCard(@NonNull Context ctx, ViewGroup container) {
private ViewGroup buildOsmLiveCard(@NonNull Context ctx, ViewGroup container) {
ViewGroup cardView = (ViewGroup) inflate(R.layout.purchase_dialog_active_card, container);
TextView headerTitle = (TextView) cardView.findViewById(R.id.header_title);
TextView headerDescr = (TextView) cardView.findViewById(R.id.header_descr);
@ -238,11 +275,10 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
headerDescr.setText(R.string.osm_live_subscription);
ViewGroup rowsContainer = (ViewGroup) cardView.findViewById(R.id.rows_container);
View featureRowDiv = null;
for (OsmAndFeature feature : osmandLiveFeatures) {
for (OsmAndFeature feature : planType.getOsmLiveFeatures()) {
String featureName = feature.toHumanString(ctx);
// View featureRow = inflate(planType.osmandLiveFeature == feature
// ? R.layout.purchase_dialog_card_selected_row : R.layout.purchase_dialog_card_row, cardView);
View featureRow = inflate(R.layout.purchase_dialog_card_row, cardView);
View featureRow = inflate(planType.hasSelectedOsmLiveFeature(feature)
? R.layout.purchase_dialog_card_selected_row : R.layout.purchase_dialog_card_row, cardView);
TextViewEx titleView = (TextViewEx) featureRow.findViewById(R.id.title);
titleView.setText(featureName);
featureRowDiv = featureRow.findViewById(R.id.div);
@ -257,29 +293,49 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
TextViewEx cardDescription = (TextViewEx) cardView.findViewById(R.id.card_descr);
cardDescription.setText(R.string.osm_live_payment_desc);
View cardButton = cardView.findViewById(R.id.card_button);
TextViewEx buttonTitle = (TextViewEx) cardButton.findViewById(R.id.card_button_title);
TextViewEx buttonSubtitle = (TextViewEx) cardButton.findViewById(R.id.card_button_subtitle);
if (!InAppHelper.hasPrices(getMyApplication())) {
buttonTitle.setText(ctx.getString(R.string.purchase_subscription_title, ctx.getString(R.string.osm_live_default_price)));
osmLiveCardButton = cardView.findViewById(R.id.card_button);
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
boolean requestingInventory = purchaseHelper != null && purchaseHelper.getActiveTask() == InAppPurchaseTaskType.REQUEST_INVENTORY;
setupOsmLiveCardButton(requestingInventory);
return cardView;
}
private void setupOsmLiveCardButton(boolean progress) {
if (osmLiveCardButton != null) {
ProgressBar progressBar = (ProgressBar) osmLiveCardButton.findViewById(R.id.card_button_progress);
TextViewEx buttonTitle = (TextViewEx) osmLiveCardButton.findViewById(R.id.card_button_title);
TextViewEx buttonSubtitle = (TextViewEx) osmLiveCardButton.findViewById(R.id.card_button_subtitle);
if (!purchaseHelper.hasPrices()) {
buttonTitle.setText(getString(R.string.purchase_subscription_title, getString(R.string.osm_live_default_price)));
} else {
buttonTitle.setText(ctx.getString(R.string.purchase_subscription_title, InAppHelper.getLiveUpdatesPrice()));
buttonTitle.setText(getString(R.string.purchase_subscription_title, purchaseHelper.getLiveUpdatesPrice()));
}
buttonSubtitle.setText(R.string.osm_live_month_cost_desc);
cardButton.setOnClickListener(new View.OnClickListener() {
if (progress) {
buttonTitle.setVisibility(View.GONE);
buttonSubtitle.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
osmLiveCardButton.setOnClickListener(null);
} else {
buttonTitle.setVisibility(View.VISIBLE);
buttonSubtitle.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
osmLiveCardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
subscript();
dismiss();
}
});
return cardView;
}
}
}
private void subscript() {
Activity ctx = getActivity();
if (ctx != null) {
getMyApplication().logEvent(ctx, "click_subscribe_live_osm");
app.logEvent(ctx, "click_subscribe_live_osm");
Intent intent = new Intent(ctx, OsmLiveActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.putExtra(OsmLiveActivity.OPEN_SUBSCRIPTION_INTENT_PARAM, true);
@ -287,7 +343,7 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
}
}
private ViewGroup buildOsmAndUnlimitedCard(@NonNull Context ctx, ViewGroup container) {
private ViewGroup buildPlanTypeCard(@NonNull Context ctx, ViewGroup container) {
ViewGroup cardView = (ViewGroup) inflate(R.layout.purchase_dialog_card, container);
TextView headerTitle = (TextView) cardView.findViewById(R.id.header_title);
TextView headerDescr = (TextView) cardView.findViewById(R.id.header_descr);
@ -295,9 +351,9 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
headerDescr.setText(R.string.in_app_purchase);
ViewGroup rowsContainer = (ViewGroup) cardView.findViewById(R.id.rows_container);
View featureRow = null;
for (OsmAndFeature feature : osmandUnlimitedFeatures) {
for (OsmAndFeature feature : planType.getPlanTypeFeatures()) {
String featureName = feature.toHumanString(ctx);
featureRow = inflate(planType.osmandUnlimitedFeature == feature
featureRow = inflate(planType.hasSelectedPlanTypeFeature(feature)
? R.layout.purchase_dialog_card_selected_row : R.layout.purchase_dialog_card_row, cardView);
TextViewEx titleView = (TextViewEx) featureRow.findViewById(R.id.title);
titleView.setText(featureName);
@ -309,28 +365,46 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
TextViewEx cardDescription = (TextViewEx) cardView.findViewById(R.id.card_descr);
cardDescription.setText(R.string.in_app_purchase_desc_ex);
View cardButton = cardView.findViewById(R.id.card_button);
TextViewEx buttonTitle = (TextViewEx) cardButton.findViewById(R.id.card_button_title);
TextViewEx buttonSubtitle = (TextViewEx) cardButton.findViewById(R.id.card_button_subtitle);
if (!InAppHelper.hasPrices(getMyApplication())) {
buttonTitle.setText(ctx.getString(R.string.purchase_unlim_title, ctx.getString(R.string.full_version_price)));
planTypeCardButton = cardView.findViewById(R.id.card_button);
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
boolean requestingInventory = purchaseHelper != null && purchaseHelper.getActiveTask() == InAppPurchaseTaskType.REQUEST_INVENTORY;
setupPlanTypeCardButton(requestingInventory);
return cardView;
}
private void setupPlanTypeCardButton(boolean progress) {
if (planTypeCardButton != null) {
ProgressBar progressBar = (ProgressBar) planTypeCardButton.findViewById(R.id.card_button_progress);
TextViewEx buttonTitle = (TextViewEx) planTypeCardButton.findViewById(R.id.card_button_title);
TextViewEx buttonSubtitle = (TextViewEx) planTypeCardButton.findViewById(R.id.card_button_subtitle);
if (!purchaseHelper.hasPrices()) {
buttonTitle.setText(getString(R.string.purchase_unlim_title, getString(R.string.full_version_price)));
} else {
buttonTitle.setText(ctx.getString(R.string.purchase_unlim_title, InAppHelper.getFullVersionPrice()));
buttonTitle.setText(getString(R.string.purchase_unlim_title, purchaseHelper.getFullVersionPrice()));
}
buttonSubtitle.setText(R.string.in_app_purchase_desc);
cardButton.setOnClickListener(new View.OnClickListener() {
if (progress) {
buttonTitle.setVisibility(View.GONE);
buttonSubtitle.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
planTypeCardButton.setOnClickListener(null);
} else {
buttonTitle.setVisibility(View.VISIBLE);
buttonSubtitle.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
planTypeCardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
purchaseFullVersion();
dismiss();
}
});
return cardView;
}
}
}
public void purchaseFullVersion() {
/*
OsmandApplication app = getMyApplication();
if (app.getRemoteBoolean(SHOW_PLUS_VERSION_INAPP_PARAM, true)) {
app.logEvent(getActivity(), "in_app_purchase_redirect_from_banner");
} else {
@ -338,12 +412,13 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
}
if (Version.isFreeVersion(app)) {
if (app.getRemoteBoolean(SHOW_PLUS_VERSION_INAPP_PARAM, true)) {
if (inAppHelper != null) {
app.logEvent(this, "in_app_purchase_redirect");
inAppHelper.purchaseFullVersion(this);
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
if (purchaseHelper != null) {
app.logEvent(getActivity(), "in_app_purchase_redirect");
purchaseHelper.purchaseFullVersion(getActivity());
}
} else {
app.logEvent(this, "paid_version_redirect");
app.logEvent(getActivity(), "paid_version_redirect");
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(Version.getUrlWithUtmRef(app, "net.osmand.plus")));
try {
@ -353,7 +428,6 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
}
}
}
*/
}
@Override
@ -391,6 +465,38 @@ public class ChoosePlanDialogFragment extends BaseOsmAndDialogFragment {
}
}
@Override
public void onError(InAppPurchaseTaskType taskType, String error) {
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
setupOsmLiveCardButton(false);
setupPlanTypeCardButton(false);
}
}
@Override
public void onGetItems() {
}
@Override
public void onItemPurchased(String sku) {
}
@Override
public void showProgress(InAppPurchaseTaskType taskType) {
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
setupOsmLiveCardButton(true);
setupPlanTypeCardButton(true);
}
}
@Override
public void dismissProgress(InAppPurchaseTaskType taskType) {
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
setupOsmLiveCardButton(false);
setupPlanTypeCardButton(false);
}
}
public static void showFreeVersionInstance(@NonNull FragmentManager fm) {
PlanType planType = PlanType.FREE_VERSION_BANNER;
showInstance(fm, planType);

View file

@ -1,12 +1,11 @@
package net.osmand.plus.download;
import android.Manifest;
import android.content.ActivityNotFoundException;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StatFs;
@ -21,7 +20,6 @@ import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.Space;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.AppCompatButton;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.MenuItem;
@ -54,17 +52,15 @@ import net.osmand.plus.activities.TabActivity;
import net.osmand.plus.base.BasicProgressAsyncTask;
import net.osmand.plus.base.BottomSheetDialogFragment;
import net.osmand.plus.dialogs.ChoosePlanDialogFragment;
import net.osmand.plus.dialogs.ChoosePlanDialogFragment.PlanType;
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
import net.osmand.plus.download.ui.ActiveDownloadsDialogFragment;
import net.osmand.plus.download.ui.DownloadResourceGroupFragment;
import net.osmand.plus.download.ui.FreeVersionDialogFragment;
import net.osmand.plus.download.ui.LocalIndexesFragment;
import net.osmand.plus.download.ui.UpdatesIndexFragment;
import net.osmand.plus.helpers.FileNameTranslationHelper;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppHelper.InAppListener;
import net.osmand.plus.liveupdates.OsmLiveActivity;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin;
import net.osmand.plus.srtmplugin.SRTMPlugin;
import net.osmand.plus.views.controls.PagerSlidingTabStrip;
@ -83,10 +79,8 @@ import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static net.osmand.plus.OsmandApplication.SHOW_PLUS_VERSION_INAPP_PARAM;
public class DownloadActivity extends AbstractDownloadActivity implements DownloadEvents,
OnRequestPermissionsResultCallback, InAppListener {
OnRequestPermissionsResultCallback {
private static final Log LOG = PlatformUtil.getLog(DownloadActivity.class);
public static final int UPDATES_TAB_NUMBER = 2;
@ -122,8 +116,6 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
protected WorldRegion downloadItem;
protected String downloadTargetFileName;
private InAppHelper inAppHelper;
private boolean srtmDisabled;
private boolean srtmNeedsInstallation;
private boolean nauticalPluginDisabled;
@ -196,11 +188,9 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
visibleBanner = new BannerAndDownloadFreeVersion(findViewById(R.id.mainLayout), this, true);
if (shouldShowFreeVersionBanner(getMyApplication())) {
visibleBanner.setUpdatingPrices(true);
visibleBanner.updateFreeVersionBanner();
}
startInAppHelper();
final Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
filter = intent.getExtras().getString(FILTER_KEY);
@ -209,65 +199,60 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
}
}
public boolean isInAppPurchaseAllowed() {
return true;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Pass on the activity result to the helper for handling
if (inAppHelper == null || !inAppHelper.onActivityResultHandled(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
public void onInAppPurchaseError(InAppPurchaseTaskType taskType, String error) {
visibleBanner.updateFreeVersionBanner();
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppPurchaseListener && f.isAdded()) {
((InAppPurchaseListener) f).onError(taskType, error);
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
stopInAppHelper();
}
public void startInAppHelper() {
stopInAppHelper();
if (Version.isGooglePlayEnabled(getMyApplication())) {
inAppHelper = new InAppHelper(getMyApplication(), true);
inAppHelper.addListener(this);
inAppHelper.start(false);
}
}
public void stopInAppHelper() {
if (inAppHelper != null) {
inAppHelper.removeListener(this);
inAppHelper.stop();
}
}
public void purchaseFullVersion() {
OsmandApplication app = getMyApplication();
if (Version.isFreeVersion(app)) {
if (app.getRemoteBoolean(SHOW_PLUS_VERSION_INAPP_PARAM, true)) {
if (inAppHelper != null) {
app.logEvent(this, "in_app_purchase_redirect");
inAppHelper.purchaseFullVersion(this);
}
} else {
app.logEvent(this, "paid_version_redirect");
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(Version.getUrlWithUtmRef(app, "net.osmand.plus")));
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
LOG.error("ActivityNotFoundException", e);
}
public void onInAppPurchaseGetItems() {
visibleBanner.updateFreeVersionBanner();
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppPurchaseListener && f.isAdded()) {
((InAppPurchaseListener) f).onGetItems();
}
}
}
public void purchaseDepthContours() {
if (inAppHelper != null) {
getMyApplication().logEvent(this, "depth_contours_purchase_redirect");
inAppHelper.purchaseDepthContours(this);
@Override
public void onInAppPurchaseItemPurchased(String sku) {
visibleBanner.updateFreeVersionBanner();
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppPurchaseListener && f.isAdded()) {
((InAppPurchaseListener) f).onItemPurchased(sku);
}
}
}
@Override
public void showInAppPurchaseProgress(InAppPurchaseTaskType taskType) {
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppPurchaseListener && f.isAdded()) {
((InAppPurchaseListener) f).showProgress(taskType);
}
}
}
@Override
public void dismissInAppPurchaseProgress(InAppPurchaseTaskType taskType) {
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppPurchaseListener && f.isAdded()) {
((InAppPurchaseListener) f).dismissProgress(taskType);
}
}
}
@ -369,59 +354,6 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
}
}
@Override
public void onError(String error) {
visibleBanner.setUpdatingPrices(false);
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppListener && f.isAdded()) {
((InAppListener) f).onError(error);
}
}
}
@Override
public void onGetItems() {
visibleBanner.setUpdatingPrices(false);
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppListener && f.isAdded()) {
((InAppListener) f).onGetItems();
}
}
}
@Override
public void onItemPurchased(String sku) {
visibleBanner.setUpdatingPrices(false);
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppListener && f.isAdded()) {
((InAppListener) f).onItemPurchased(sku);
}
}
}
@Override
public void showProgress() {
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppListener && f.isAdded()) {
((InAppListener) f).showProgress();
}
}
}
@Override
public void dismissProgress() {
for (WeakReference<Fragment> ref : fragSet) {
Fragment f = ref.get();
if (f instanceof InAppListener && f.isAdded()) {
((InAppListener) f).dismissProgress();
}
}
}
@Override
@UiThread
public void downloadInProgress() {
@ -478,25 +410,14 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
}
public static class FreeVersionDialog {
public static class FreeVersionBanner {
private final View freeVersionBanner;
private final View freeVersionBannerTitle;
private boolean updatingPrices;
private final View priceInfoLayout;
private final TextView freeVersionDescriptionTextView;
private final TextView downloadsLeftTextView;
private final ProgressBar downloadsLeftProgressBar;
// private final View laterButton;
// private final View buttonsLinearLayout;
private final View fullVersionProgress;
private final AppCompatButton fullVersionButton;
private final View osmLiveProgress;
private final AppCompatButton osmLiveButton;
private DownloadActivity ctx;
private boolean dialog;
private OnClickListener onCollapseListener = new OnClickListener() {
@Override
@ -511,45 +432,26 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
}
};
public FreeVersionDialog(View view, final DownloadActivity ctx, boolean dialog) {
public FreeVersionBanner(View view, final DownloadActivity ctx) {
this.ctx = ctx;
this.dialog = dialog;
freeVersionBanner = view.findViewById(R.id.freeVersionBanner);
downloadsLeftTextView = (TextView) freeVersionBanner.findViewById(R.id.downloadsLeftTextView);
downloadsLeftProgressBar = (ProgressBar) freeVersionBanner.findViewById(R.id.downloadsLeftProgressBar);
priceInfoLayout = freeVersionBanner.findViewById(R.id.priceInfoLayout);
freeVersionDescriptionTextView = (TextView) freeVersionBanner
.findViewById(R.id.freeVersionDescriptionTextView);
freeVersionBannerTitle = freeVersionBanner.findViewById(R.id.freeVersionBannerTitle);
// laterButton = freeVersionBanner.findViewById(R.id.laterButton);
// buttonsLinearLayout = freeVersionBanner.findViewById(R.id.buttonsLinearLayout);
fullVersionProgress = freeVersionBanner.findViewById(R.id.fullVersionProgress);
fullVersionButton = (AppCompatButton) freeVersionBanner.findViewById(R.id.fullVersionButton);
osmLiveProgress = freeVersionBanner.findViewById(R.id.osmLiveProgress);
osmLiveButton = (AppCompatButton) freeVersionBanner.findViewById(R.id.osmLiveButton);
}
public void setUpdatingPrices(boolean updatingPrices) {
this.updatingPrices = updatingPrices;
updateFreeVersionBanner();
}
private void collapseBanner() {
freeVersionDescriptionTextView.setVisibility(View.GONE);
// buttonsLinearLayout.setVisibility(View.GONE);
priceInfoLayout.setVisibility(View.GONE);
freeVersionBannerTitle.setVisibility(View.VISIBLE);
}
public void expandBanner() {
freeVersionDescriptionTextView.setVisibility(View.VISIBLE);
// buttonsLinearLayout.setVisibility(View.VISIBLE);
priceInfoLayout.setVisibility(View.VISIBLE);
freeVersionBannerTitle.setVisibility(View.VISIBLE);
}
public void initFreeVersionBanner() {
if (!shouldShowFreeVersionBanner(ctx.getMyApplication())) {
freeVersionBanner.setVisibility(View.GONE);
@ -559,33 +461,6 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
downloadsLeftProgressBar.setMax(DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS);
freeVersionDescriptionTextView.setText(ctx.getString(R.string.free_version_message,
DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS));
fullVersionButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
OsmandApplication app = ctx.getMyApplication();
if (app.getRemoteBoolean(SHOW_PLUS_VERSION_INAPP_PARAM, true)) {
app.logEvent(ctx, "in_app_purchase_redirect_from_banner");
} else {
app.logEvent(ctx, "paid_version_redirect_from_banner");
}
ctx.purchaseFullVersion();
DialogFragment f = (DialogFragment) ctx.getSupportFragmentManager()
.findFragmentByTag(FreeVersionDialogFragment.TAG);
if (f != null) {
f.dismiss();
}
}
});
osmLiveButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ctx.getMyApplication().logEvent(ctx, "click_subscribe_live_osm");
Intent intent = new Intent(ctx, OsmLiveActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.putExtra(OsmLiveActivity.OPEN_SUBSCRIPTION_INTENT_PARAM, true);
ctx.startActivity(intent);
}
});
LinearLayout marksLinearLayout = (LinearLayout) freeVersionBanner.findViewById(R.id.marksLinearLayout);
Space spaceView = new Space(ctx);
@ -609,12 +484,8 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
}
updateFreeVersionBanner();
if(dialog) {
expandBanner();
} else {
collapseBanner();
}
}
public void updateFreeVersionBanner() {
if (!shouldShowFreeVersionBanner(ctx.getMyApplication())) {
@ -630,30 +501,9 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
int downloadsLeft = DownloadValidationManager.MAXIMUM_AVAILABLE_FREE_DOWNLOADS - mapsDownloaded;
downloadsLeft = Math.max(downloadsLeft, 0);
downloadsLeftTextView.setText(ctx.getString(R.string.downloads_left_template, downloadsLeft));
if(!dialog) {
freeVersionBanner.findViewById(R.id.bannerTopLayout).setOnClickListener(onCollapseListener);
}
if (InAppHelper.hasPrices(ctx.getMyApplication()) || !updatingPrices) {
if (!InAppHelper.hasPrices(ctx.getMyApplication())) {
fullVersionButton.setText(ctx.getString(R.string.get_for, ctx.getString(R.string.full_version_price)));
osmLiveButton.setText(ctx.getString(R.string.get_for_month, ctx.getString(R.string.osm_live_default_price)));
} else {
fullVersionButton.setText(ctx.getString(R.string.get_for, InAppHelper.getFullVersionPrice()));
osmLiveButton.setText(ctx.getString(R.string.get_for_month, InAppHelper.getLiveUpdatesPrice()));
}
fullVersionProgress.setVisibility(View.GONE);
fullVersionButton.setVisibility(View.VISIBLE);
osmLiveProgress.setVisibility(View.GONE);
osmLiveButton.setVisibility(View.VISIBLE);
} else {
fullVersionProgress.setVisibility(View.VISIBLE);
fullVersionButton.setVisibility(View.GONE);
osmLiveProgress.setVisibility(View.VISIBLE);
osmLiveButton.setVisibility(View.GONE);
}
}
private void setMinimizedFreeVersionBanner(boolean minimize) {
if (minimize && isDownlodingPermitted(ctx.getMyApplication().getSettings())) {
collapseBanner();
@ -668,7 +518,6 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
final Integer mapsDownloaded = settings.NUMBER_OF_FREE_DOWNLOADS.get() + activeTasks;
downloadsLeftProgressBar.setProgress(mapsDownloaded);
}
}
public static class BannerAndDownloadFreeVersion {
@ -681,26 +530,24 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
private final DownloadActivity ctx;
private boolean showSpace;
private FreeVersionDialog freeVersionDialog;
private FreeVersionBanner freeVersionBanner;
public BannerAndDownloadFreeVersion(View view, final DownloadActivity ctx, boolean showSpace) {
this.ctx = ctx;
this.showSpace = showSpace;
freeVersionDialog = new FreeVersionDialog(view, ctx, false);
freeVersionBanner = new FreeVersionBanner(view, ctx);
downloadProgressLayout = view.findViewById(R.id.downloadProgressLayout);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
leftTextView = (TextView) view.findViewById(R.id.leftTextView);
rightTextView = (TextView) view.findViewById(R.id.rightTextView);
freeVersionDialog.initFreeVersionBanner();
freeVersionBanner.initFreeVersionBanner();
updateBannerInProgress();
}
public void setUpdatingPrices(boolean updatingPrices) {
freeVersionDialog.setUpdatingPrices(updatingPrices);
public void updateFreeVersionBanner() {
freeVersionBanner.updateFreeVersionBanner();
}
public void updateBannerInProgress() {
@ -715,13 +562,13 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
} else {
downloadProgressLayout.setVisibility(View.VISIBLE);
}
freeVersionDialog.updateFreeVersionBanner();
freeVersionBanner.updateFreeVersionBanner();
} else {
boolean indeterminate = basicProgressAsyncTask.isIndeterminate();
String message = basicProgressAsyncTask.getDescription();
int percent = basicProgressAsyncTask.getProgressPercentage();
freeVersionDialog.setMinimizedFreeVersionBanner(true);
freeVersionDialog.updateAvailableDownloads();
freeVersionBanner.setMinimizedFreeVersionBanner(true);
freeVersionBanner.updateAvailableDownloads();
downloadProgressLayout.setVisibility(View.VISIBLE);
downloadProgressLayout.setOnClickListener(new OnClickListener() {
@Override
@ -735,27 +582,14 @@ public class DownloadActivity extends AbstractDownloadActivity implements Downlo
rightTextView.setText(null);
} else {
progressBar.setProgress(percent);
// final String format = ctx.getString(R.string.downloading_number_of_files);
leftTextView.setText(message);
rightTextView.setText(percent + "%");
}
}
}
public void hideDownloadProgressLayout() {
downloadProgressLayout.setVisibility(View.GONE);
}
public void showDownloadProgressLayout() {
downloadProgressLayout.setVisibility(View.VISIBLE);
}
}
@SuppressLint("StaticFieldLeak")
public void reloadLocalIndexes() {
AsyncTask<Void, String, List<String>> task = new AsyncTask<Void, String, List<String>>() {
@Override

View file

@ -1,5 +1,6 @@
package net.osmand.plus.download.ui;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.res.Resources;
@ -41,8 +42,9 @@ import net.osmand.plus.download.DownloadResourceGroup.DownloadResourceGroupType;
import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.download.DownloadValidationManager;
import net.osmand.plus.download.IndexItem;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppHelper.InAppListener;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.util.Algorithms;
import org.json.JSONException;
@ -55,7 +57,7 @@ import java.util.List;
import java.util.Map;
public class DownloadResourceGroupFragment extends DialogFragment implements DownloadEvents,
InAppListener, OnChildClickListener {
InAppPurchaseListener, OnChildClickListener {
public static final int RELOAD_ID = 0;
public static final int SEARCH_ID = 1;
public static final String TAG = "RegionDialogFragment";
@ -67,6 +69,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
protected DownloadResourceGroupAdapter listAdapter;
private DownloadResourceGroup group;
private DownloadActivity activity;
private InAppPurchaseHelper purchaseHelper;
private Toolbar toolbar;
private View searchView;
private View restorePurchasesView;
@ -75,6 +78,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
purchaseHelper = getDownloadActivity().getPurchaseHelper();
boolean isLightTheme = getMyApplication().getSettings().OSMAND_THEME.get() == OsmandSettings.OSMAND_LIGHT_THEME;
int themeId = isLightTheme ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme;
setStyle(STYLE_NO_FRAME, themeId);
@ -152,7 +156,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
}
private void addRestorePurchasesRow() {
if (!openAsDialog() && !InAppHelper.isInAppIntentoryRead()) {
if (!openAsDialog() && purchaseHelper != null && !purchaseHelper.hasInventory()) {
restorePurchasesView = activity.getLayoutInflater().inflate(R.layout.restore_purchases_list_footer, null);
((ImageView) restorePurchasesView.findViewById(R.id.icon)).setImageDrawable(
getMyApplication().getIconsCache().getThemedIcon(R.drawable.ic_action_reset_to_default_dark));
@ -160,7 +164,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
@Override
public void onClick(View v) {
restorePurchasesView.findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
activity.startInAppHelper();
purchaseHelper.requestInventory();
}
});
listView.addFooterView(restorePurchasesView);
@ -205,7 +209,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
}
}
if (restorePurchasesView != null && restorePurchasesView.findViewById(R.id.container).getVisibility() == View.GONE
&& !InAppHelper.isInAppIntentoryRead()) {
&& purchaseHelper != null && !purchaseHelper.hasInventory()) {
if (worldBaseMapItem != null && worldBaseMapItem.isDownloaded()) {
restorePurchasesView.findViewById(R.id.container).setVisibility(View.VISIBLE);
}
@ -260,6 +264,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
alertDialog.show();
}
@SuppressLint("StaticFieldLeak")
private void doSubscribe(final String email) {
new AsyncTask<Void, Void, String>() {
@ -329,7 +334,7 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
}
@Override
public void onError(String error) {
public void onError(InAppPurchaseTaskType taskType, String error) {
}
@Override
@ -346,11 +351,11 @@ public class DownloadResourceGroupFragment extends DialogFragment implements Dow
}
@Override
public void showProgress() {
public void showProgress(InAppPurchaseTaskType taskType) {
}
@Override
public void dismissProgress() {
public void dismissProgress(InAppPurchaseTaskType taskType) {
if (restorePurchasesView != null && restorePurchasesView.findViewById(R.id.container).getVisibility() == View.VISIBLE) {
restorePurchasesView.findViewById(R.id.progressBar).setVisibility(View.GONE);
}

View file

@ -1,44 +0,0 @@
package net.osmand.plus.download.ui;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.view.ContextThemeWrapper;
import android.view.View;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadActivity.FreeVersionDialog;
import static net.osmand.plus.OsmandApplication.SHOW_PLUS_VERSION_INAPP_PARAM;
public class FreeVersionDialogFragment extends DialogFragment {
public static final String TAG = "FreeVersionDialogFragment";
private FreeVersionDialog dialog;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
OsmandApplication app = (OsmandApplication) getActivity().getApplication();
app.activateFetchedRemoteParams();
AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), R.style.OsmandDarkTheme));
builder.setNegativeButton(R.string.later, null);
View view = getActivity().getLayoutInflater().inflate(R.layout.free_version_banner, null);
builder.setView(view);
dialog = new DownloadActivity.FreeVersionDialog(view, getDownloadActivity(), true);
dialog.initFreeVersionBanner();
dialog.expandBanner();
return builder.create();
}
DownloadActivity getDownloadActivity() {
return (DownloadActivity) getActivity();
}
}

View file

@ -14,7 +14,7 @@ import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.liveupdates.OsmLiveActivity;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarController;
import net.osmand.plus.views.mapwidgets.MapInfoWidgetsFactory.TopToolbarControllerType;
@ -109,7 +109,8 @@ public class DiscountHelper {
if (url.startsWith(INAPP_PREFIX) && url.length() > INAPP_PREFIX.length()) {
String inAppSku = url.substring(INAPP_PREFIX.length());
if (InAppHelper.isPurchased(app, inAppSku)) {
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
if (purchaseHelper != null && purchaseHelper.isPurchased(inAppSku)) {
return;
}
}
@ -210,15 +211,11 @@ public class DiscountHelper {
private static void openUrl(final MapActivity mapActivity, String url) {
if (url.startsWith(INAPP_PREFIX)) {
if (url.contains(InAppHelper.SKU_FULL_VERSION_PRICE)) {
mapActivity.execInAppTask(new InAppHelper.InAppRunnable() {
@Override
public void run(InAppHelper helper) {
mapActivity.getMyApplication().logEvent(mapActivity, "in_app_purchase_redirect");
helper.purchaseFullVersion(mapActivity);
}
});
} else if (url.contains(InAppHelper.SKU_LIVE_UPDATES)){
if (url.contains(InAppPurchaseHelper.SKU_FULL_VERSION_PRICE)) {
OsmandApplication app = mapActivity.getMyApplication();
app.logEvent(mapActivity, "in_app_purchase_redirect");
app.getInAppPurchaseHelper().purchaseFullVersion(mapActivity);
} else if (url.contains(InAppPurchaseHelper.SKU_LIVE_UPDATES)){
Intent intent = new Intent(mapActivity, OsmLiveActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.putExtra(OsmLiveActivity.OPEN_SUBSCRIPTION_INTENT_PARAM, true);

View file

@ -1,5 +1,6 @@
package net.osmand.plus.inapp;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
@ -26,29 +27,29 @@ import net.osmand.util.Algorithms;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InAppHelper {
public class InAppPurchaseHelper {
// Debug tag, for logging
static final String TAG = "InAppHelper";
private static final String TAG = InAppPurchaseHelper.class.getSimpleName();
boolean mDebugLog = false;
private static boolean mSubscribedToLiveUpdates = false;
private static boolean mFullVersionPurchased = false;
private static boolean mDepthContoursPurchased = false;
private static String mLiveUpdatesPrice;
private static long lastValidationCheckTime;
private static String mFullVersionPrice;
private static String mDepthContoursPrice;
private long lastValidationCheckTime;
private String liveUpdatesPrice;
private String fullVersionPrice;
private String depthContoursPrice;
public static final String SKU_FULL_VERSION_PRICE = "osmand_full_version_price";
private static final String SKU_LIVE_UPDATES_FULL = "osm_live_subscription_2";
private static final String SKU_LIVE_UPDATES_FREE = "osm_free_live_subscription_2";
private static final String SKU_DEPTH_CONTOURS_FULL = "net.osmand.seadepth_plus";
private static final String SKU_DEPTH_CONTOURS_FREE = "net.osmand.seadepth";
public static String SKU_LIVE_UPDATES;
public static String SKU_DEPTH_CONTOURS;
@ -58,15 +59,13 @@ public class InAppHelper {
// The helper object
private IabHelper mHelper;
private boolean stopAfterResult = false;
private boolean isDeveloperVersion = false;
private boolean forceRequestInventory = false;
private boolean isDeveloperVersion;
private String token = "";
private boolean inventoryRequesting = false;
private boolean stopRequested = false;
private InAppPurchaseTaskType activeTask;
private boolean processingTask = false;
private OsmandApplication ctx;
private List<InAppListener> listeners = new ArrayList<>();
private List<InAppPurchaseListener> listeners = new ArrayList<>();
/* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY
* (that you got from the Google Play developer console). This is not your
@ -86,60 +85,64 @@ public class InAppHelper {
"I+ftJO46a1XkNh1dO2anUiQ8P/H4yOTqnMsXF7biyYuiwjXPOcy0OMhEHi54Dq6Mr3u5ZALOAkc" +
"YTjh1H/ZgqIHy5ZluahINuDE76qdLYMXrDMQIDAQAB";
public interface InAppListener {
void onError(String error);
public interface InAppPurchaseListener {
void onError(InAppPurchaseTaskType taskType, String error);
void onGetItems();
void onItemPurchased(String sku);
void showProgress();
void showProgress(InAppPurchaseTaskType taskType);
void dismissProgress();
void dismissProgress(InAppPurchaseTaskType taskType);
}
public enum InAppPurchaseTaskType {
REQUEST_INVENTORY,
PURCHASE_FULL_VERSION,
PURCHASE_LIVE_UPDATES,
PURCHASE_DEPTH_CONTOURS
}
public interface InAppRunnable {
void run(InAppHelper helper);
// return true if done and false if async task started
boolean run(InAppPurchaseHelper helper);
}
public String getToken() {
return token;
}
public static boolean isSubscribedToLiveUpdates() {
return mSubscribedToLiveUpdates;
public InAppPurchaseTaskType getActiveTask() {
return activeTask;
}
public static boolean isFullVersionPurchased() {
return mFullVersionPurchased;
public boolean isSubscribedToLiveUpdates() {
return ctx.getSettings().LIVE_UPDATES_PURCHASED.get();
}
public static boolean isDepthContoursPurchased() {
return mDepthContoursPurchased;
public String getLiveUpdatesPrice() {
return liveUpdatesPrice;
}
public static String getLiveUpdatesPrice() {
return mLiveUpdatesPrice;
public String getFullVersionPrice() {
return fullVersionPrice;
}
public static String getDepthContoursPrice() {
return mDepthContoursPrice;
public String getDepthContoursPrice() {
return depthContoursPrice;
}
public static String getFullVersionPrice() {
return mFullVersionPrice;
}
public static String getSkuLiveUpdates() {
public String getSkuLiveUpdates() {
return SKU_LIVE_UPDATES;
}
public static boolean hasPrices(OsmandApplication app) {
return !Algorithms.isEmpty(mLiveUpdatesPrice)
&& (!Version.isFreeVersion(app) || !Algorithms.isEmpty(mFullVersionPrice));
public boolean hasPrices() {
return !Algorithms.isEmpty(liveUpdatesPrice)
&& (!Version.isFreeVersion(ctx) || !Algorithms.isEmpty(fullVersionPrice));
}
public static void initialize(OsmandApplication ctx) {
private void initialize() {
if (SKU_LIVE_UPDATES == null) {
if (Version.isFreeVersion(ctx)) {
SKU_LIVE_UPDATES = SKU_LIVE_UPDATES_FREE;
@ -156,26 +159,22 @@ public class InAppHelper {
}
}
public InAppHelper(OsmandApplication ctx, boolean forceRequestInventory) {
public InAppPurchaseHelper(OsmandApplication ctx) {
this.ctx = ctx;
this.forceRequestInventory = forceRequestInventory;
isDeveloperVersion = Version.isDeveloperVersion(ctx);
if (isDeveloperVersion) {
mSubscribedToLiveUpdates = true;
mFullVersionPurchased = true;
mDepthContoursPurchased = true;
this.isDeveloperVersion = Version.isDeveloperVersion(ctx);
if (this.isDeveloperVersion) {
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
ctx.getSettings().FULL_VERSION_PURCHASED.set(true);
ctx.getSettings().DEPTH_CONTOURS_PURCHASED.set(true);
}
initialize();
}
public static boolean isInAppIntentoryRead() {
public boolean hasInventory() {
return lastValidationCheckTime != 0;
}
public static boolean isPurchased(OsmandApplication ctx, String inAppSku) {
public boolean isPurchased(String inAppSku) {
OsmandSettings settings = ctx.getSettings();
if (inAppSku.equals(SKU_FULL_VERSION_PRICE)) {
return settings.FULL_VERSION_PURCHASED.get();
@ -187,11 +186,18 @@ public class InAppHelper {
return false;
}
public void exec(final @NonNull InAppRunnable runnable) {
this.stopAfterResult = true;
private void exec(final @NonNull InAppPurchaseTaskType taskType, final @NonNull InAppRunnable runnable) {
if (isDeveloperVersion || !Version.isGooglePlayEnabled(ctx)) {
return;
}
if (processingTask) {
logError("Already processing task: " + taskType + ". Exit.");
return;
}
// Create the helper, passing it our context and the public key to verify signatures with
logDebug("Creating InAppHelper.");
logDebug("Creating InAppPurchaseHelper.");
mHelper = new IabHelper(ctx, BASE64_ENCODED_PUBLIC_KEY);
// enable debug logging (for a production application, you should set this to false).
@ -201,6 +207,8 @@ public class InAppHelper {
// will be called once setup completes.
logDebug("Starting setup.");
try {
processingTask = true;
activeTask = taskType;
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
logDebug("Setup finished.");
@ -208,112 +216,115 @@ public class InAppHelper {
if (!result.isSuccess()) {
// Oh noes, there was a problem.
//complain("Problem setting up in-app billing: " + result);
notifyError(result.getMessage());
if (stopAfterResult) {
stop();
}
notifyError(taskType, result.getMessage());
stop(true);
return;
}
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
if (mHelper == null) {
stop(true);
return;
}
runnable.run(InAppHelper.this);
processingTask = !runnable.run(InAppPurchaseHelper.this);
}
});
} catch (Exception e) {
logError("exec Error", e);
if (stopAfterResult) {
stop();
stop(true);
}
}
public boolean needRequestInventory() {
return !ctx.getSettings().BILLING_PURCHASE_TOKEN_SENT.get()
|| System.currentTimeMillis() - lastValidationCheckTime > PURCHASE_VALIDATION_PERIOD_MSEC;
}
public void start(final boolean stopAfterResult) {
this.stopAfterResult = stopAfterResult;
// Create the helper, passing it our context and the public key to verify signatures with
logDebug("Creating InAppHelper.");
mHelper = new IabHelper(ctx, BASE64_ENCODED_PUBLIC_KEY);
// enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(false);
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
logDebug("Starting setup.");
try {
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
logDebug("Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
//complain("Problem setting up in-app billing: " + result);
notifyError(result.getMessage());
if (stopAfterResult) {
stop();
}
return;
}
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
// IAB is fully set up. Now, let's get an inventory of stuff we own if needed.
if (forceRequestInventory || (!isDeveloperVersion &&
(!mSubscribedToLiveUpdates
|| !ctx.getSettings().BILLING_PURCHASE_TOKEN_SENT.get()
|| System.currentTimeMillis() - lastValidationCheckTime > PURCHASE_VALIDATION_PERIOD_MSEC))) {
public void requestInventory() {
notifyShowProgress(InAppPurchaseTaskType.REQUEST_INVENTORY);
exec(InAppPurchaseTaskType.REQUEST_INVENTORY, new InAppRunnable() {
@Override
public boolean run(InAppPurchaseHelper helper) {
logDebug("Setup successful. Querying inventory.");
List<String> skus = new ArrayList<>();
skus.add(SKU_LIVE_UPDATES);
skus.add(SKU_DEPTH_CONTOURS);
skus.add(SKU_FULL_VERSION_PRICE);
try {
inventoryRequesting = true;
mHelper.queryInventoryAsync(true, skus, mGotInventoryListener);
return false;
} catch (Exception e) {
inventoryRequesting = false;
logError("queryInventoryAsync Error", e);
notifyDismissProgress();
if (stopAfterResult) {
stop();
}
}
} else {
notifyDismissProgress();
if (stopAfterResult) {
stop();
}
notifyDismissProgress(InAppPurchaseTaskType.REQUEST_INVENTORY);
stop(true);
}
return true;
}
});
}
public void purchaseFullVersion(final Activity activity) {
notifyShowProgress(InAppPurchaseTaskType.PURCHASE_FULL_VERSION);
exec(InAppPurchaseTaskType.PURCHASE_FULL_VERSION, new InAppRunnable() {
@Override
public boolean run(InAppPurchaseHelper helper) {
try {
mHelper.launchPurchaseFlow(activity,
SKU_FULL_VERSION_PRICE, RC_REQUEST, mPurchaseFinishedListener);
return false;
} catch (Exception e) {
logError("start Error", e);
if (stopAfterResult) {
stop();
complain("Cannot launch full version purchase!");
logError("purchaseFullVersion Error", e);
stop(true);
}
return true;
}
});
}
public void purchaseLiveUpdates(Activity activity, String email, String userName,
String countryDownloadName, boolean hideUserName) {
notifyShowProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
new LiveUpdatesPurchaseTask(activity, email, userName, countryDownloadName, hideUserName)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
public void purchaseDepthContours(final Activity activity) {
notifyShowProgress(InAppPurchaseTaskType.PURCHASE_DEPTH_CONTOURS);
exec(InAppPurchaseTaskType.PURCHASE_DEPTH_CONTOURS, new InAppRunnable() {
@Override
public boolean run(InAppPurchaseHelper helper) {
try {
mHelper.launchPurchaseFlow(activity,
SKU_DEPTH_CONTOURS, RC_REQUEST, mPurchaseFinishedListener);
return false;
} catch (Exception e) {
complain("Cannot launch depth contours purchase!");
logError("purchaseDepthContours Error", e);
stop(true);
}
return true;
}
});
}
// Listener that's called when we finish querying the items and subscriptions we own
private QueryInventoryFinishedListener mGotInventoryListener = new QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
logDebug("Query inventory finished.");
inventoryRequesting = false;
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
if (mHelper == null) {
stop(true);
return;
}
// Is it a failure?
if (result.isFailure() || stopRequested) {
if (result.isFailure()) {
logError("Failed to query inventory: " + result);
notifyError(result.getMessage());
if (stopAfterResult || stopRequested) {
stop();
}
notifyError(InAppPurchaseTaskType.REQUEST_INVENTORY, result.getMessage());
stop(true);
return;
}
@ -327,47 +338,43 @@ public class InAppHelper {
// Do we have the live updates?
Purchase liveUpdatesPurchase = inventory.getPurchase(SKU_LIVE_UPDATES);
mSubscribedToLiveUpdates = isDeveloperVersion || (liveUpdatesPurchase != null && liveUpdatesPurchase.getPurchaseState() == 0);
if (mSubscribedToLiveUpdates) {
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
}
boolean subscribedToLiveUpdates = (liveUpdatesPurchase != null && liveUpdatesPurchase.getPurchaseState() == 0);
//subscribedToLiveUpdates = false;
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(subscribedToLiveUpdates);
Purchase fullVersionPurchase = inventory.getPurchase(SKU_FULL_VERSION_PRICE);
mFullVersionPurchased = isDeveloperVersion || (fullVersionPurchase != null && fullVersionPurchase.getPurchaseState() == 0);
if (mFullVersionPurchased) {
boolean fullVersionPurchased = (fullVersionPurchase != null && fullVersionPurchase.getPurchaseState() == 0);
if (fullVersionPurchased) {
ctx.getSettings().FULL_VERSION_PURCHASED.set(true);
}
Purchase depthContoursPurchase = inventory.getPurchase(SKU_DEPTH_CONTOURS);
mDepthContoursPurchased = isDeveloperVersion || (depthContoursPurchase != null && depthContoursPurchase.getPurchaseState() == 0);
if (mDepthContoursPurchased) {
boolean depthContoursPurchased = (depthContoursPurchase != null && depthContoursPurchase.getPurchaseState() == 0);
if (depthContoursPurchased) {
ctx.getSettings().DEPTH_CONTOURS_PURCHASED.set(true);
}
lastValidationCheckTime = System.currentTimeMillis();
logDebug("User " + (mSubscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
+ " live updates purchased.");
if (inventory.hasDetails(SKU_LIVE_UPDATES)) {
SkuDetails liveUpdatesDetails = inventory.getSkuDetails(SKU_LIVE_UPDATES);
mLiveUpdatesPrice = liveUpdatesDetails.getPrice();
liveUpdatesPrice = liveUpdatesDetails.getPrice();
}
if (inventory.hasDetails(SKU_DEPTH_CONTOURS)) {
SkuDetails depthContoursDetails = inventory.getSkuDetails(SKU_DEPTH_CONTOURS);
mDepthContoursPrice = depthContoursDetails.getPrice();
}
if (inventory.hasDetails(SKU_FULL_VERSION_PRICE)) {
SkuDetails fullPriceDetails = inventory.getSkuDetails(SKU_FULL_VERSION_PRICE);
mFullVersionPrice = fullPriceDetails.getPrice();
fullVersionPrice = fullPriceDetails.getPrice();
}
if (inventory.hasDetails(SKU_DEPTH_CONTOURS)) {
SkuDetails depthContoursDetails = inventory.getSkuDetails(SKU_DEPTH_CONTOURS);
depthContoursPrice = depthContoursDetails.getPrice();
}
OsmandSettings settings = ctx.getSettings();
settings.INAPPS_READ.set(true);
boolean needSendToken = false;
if (!isDeveloperVersion && liveUpdatesPurchase != null) {
if (liveUpdatesPurchase != null) {
if ((Algorithms.isEmpty(settings.BILLING_USER_ID.get()) || Algorithms.isEmpty(settings.BILLING_USER_TOKEN.get()))
&& !Algorithms.isEmpty(liveUpdatesPurchase.getDeveloperPayload())) {
String payload = liveUpdatesPurchase.getDeveloperPayload();
@ -390,11 +397,9 @@ public class InAppHelper {
final OnRequestResultListener listener = new OnRequestResultListener() {
@Override
public void onResult(String result) {
notifyDismissProgress();
notifyDismissProgress(InAppPurchaseTaskType.REQUEST_INVENTORY);
notifyGetItems();
if (stopAfterResult || stopRequested) {
stop();
}
stop(true);
logDebug("Initial inapp query finished");
}
};
@ -407,81 +412,28 @@ public class InAppHelper {
}
};
public void purchaseFullVersion(final Activity activity) {
if (mHelper == null) {
//complain("In-app hepler is not initialized!");
notifyError("In-app hepler is not initialized!");
if (stopAfterResult) {
stop();
}
return;
}
@SuppressLint("StaticFieldLeak")
private class LiveUpdatesPurchaseTask extends AsyncTask<Void, Void, String> {
logDebug("Launching purchase flow for full version");
if (mHelper != null) {
try {
mHelper.launchPurchaseFlow(activity,
SKU_FULL_VERSION_PRICE, RC_REQUEST, mPurchaseFinishedListener);
} catch (Exception e) {
complain("Cannot launch full version purchase!");
logError("purchaseFullVersion Error", e);
if (stopAfterResult) {
stop();
}
}
}
}
private WeakReference<Activity> activity;
public void purchaseDepthContours(final Activity activity) {
if (mHelper == null) {
//complain("In-app hepler is not initialized!");
notifyError("In-app hepler is not initialized!");
if (stopAfterResult) {
stop();
}
return;
}
logDebug("Launching purchase flow for sea depth contours");
if (mHelper != null) {
try {
mHelper.launchPurchaseFlow(activity,
SKU_DEPTH_CONTOURS, RC_REQUEST, mPurchaseFinishedListener);
} catch (Exception e) {
complain("Cannot launch depth contours purchase!");
logError("purchaseDepthContours Error", e);
if (stopAfterResult) {
stop();
}
}
}
}
public void purchaseLiveUpdates(final Activity activity, final String email, final String userName,
final String countryDownloadName, final boolean hideUserName) {
try {
if (mHelper == null || !mHelper.subscriptionsSupported()) {
complain("Subscriptions not supported on your device yet. Sorry!");
notifyError("Subscriptions not supported on your device yet. Sorry!");
if (stopAfterResult) {
stop();
}
return;
}
} catch (Exception e) {
logError("purchaseLiveUpdates Error", e);
if (stopAfterResult) {
stop();
}
return;
}
notifyShowProgress();
new AsyncTask<Void, Void, String>() {
private String email;
private String userName;
private String countryDownloadName;
private boolean hideUserName;
private String userId;
LiveUpdatesPurchaseTask(Activity activity, String email, String userName,
String countryDownloadName, boolean hideUserName) {
this.activity = new WeakReference<>(activity);
this.email = email;
this.userName = userName;
this.countryDownloadName = countryDownloadName;
this.hideUserName = hideUserName;
}
@Override
protected String doInBackground(Void... params) {
userId = ctx.getSettings().BILLING_USER_ID.get();
@ -509,11 +461,9 @@ public class InAppHelper {
logDebug("Response=" + response);
if (response == null) {
complain("Cannot retrieve userId from server.");
notifyDismissProgress();
notifyError("Cannot retrieve userId from server.");
if (stopAfterResult) {
stop();
}
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
notifyError(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, "Cannot retrieve userId from server.");
stop(true);
return;
} else {
@ -528,39 +478,42 @@ public class InAppHelper {
String message = "JSON parsing error: "
+ (e.getMessage() == null ? "unknown" : e.getMessage());
complain(message);
notifyDismissProgress();
notifyError(message);
if (stopAfterResult) {
stop();
}
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
notifyError(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, message);
stop(true);
}
}
notifyDismissProgress();
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
if (!Algorithms.isEmpty(userId)) {
logDebug("Launching purchase flow for live updates subscription for userId=" + userId);
String payload = userId + " " + token;
if (mHelper != null) {
final String payload = userId + " " + token;
exec(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES, new InAppRunnable() {
@Override
public boolean run(InAppPurchaseHelper helper) {
try {
mHelper.launchPurchaseFlow(activity,
Activity a = activity.get();
if (a != null) {
mHelper.launchPurchaseFlow(a,
SKU_LIVE_UPDATES, IabHelper.ITEM_TYPE_SUBS,
RC_REQUEST, mPurchaseFinishedListener, payload);
return false;
} else {
stop(true);
}
} catch (Exception e) {
logError("launchPurchaseFlow Error", e);
if (stopAfterResult) {
stop();
}
stop(true);
}
return true;
}
});
} else {
notifyError("Empty userId");
if (stopAfterResult) {
stop();
notifyError(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES,"Empty userId");
stop(true);
}
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
public boolean onActivityResultHandled(int requestCode, int resultCode, Intent data) {
logDebug("onActivityResult(" + requestCode + "," + resultCode + "," + data);
@ -590,15 +543,16 @@ public class InAppHelper {
logDebug("Purchase finished: " + result + ", purchase: " + purchase);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (mHelper == null) {
stop(true);
return;
}
if (result.isFailure()) {
complain("Error purchasing: " + result);
notifyDismissProgress();
notifyError("Error purchasing: " + result);
if (stopAfterResult) {
stop();
}
notifyDismissProgress(activeTask);
notifyError(activeTask, "Error purchasing: " + result);
stop(true);
return;
}
@ -611,58 +565,61 @@ public class InAppHelper {
@Override
public void onResult(String result) {
showToast(ctx.getString(R.string.osm_live_thanks));
mSubscribedToLiveUpdates = true;
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
notifyDismissProgress();
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
notifyItemPurchased(SKU_LIVE_UPDATES);
if (stopAfterResult) {
stop();
}
stop(true);
}
});
}
if (purchase.getSku().equals(SKU_FULL_VERSION_PRICE)) {
} else if (purchase.getSku().equals(SKU_FULL_VERSION_PRICE)) {
// bought full version
logDebug("Full version purchased.");
showToast(ctx.getString(R.string.full_version_thanks));
mFullVersionPurchased = true;
ctx.getSettings().FULL_VERSION_PURCHASED.set(true);
notifyDismissProgress();
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_FULL_VERSION);
notifyItemPurchased(SKU_FULL_VERSION_PRICE);
if (stopAfterResult) {
stop();
}
}
if (purchase.getSku().equals(SKU_DEPTH_CONTOURS)) {
stop(true);
} else if (purchase.getSku().equals(SKU_DEPTH_CONTOURS)) {
// bought sea depth contours
logDebug("Sea depth contours purchased.");
showToast(ctx.getString(R.string.sea_depth_thanks));
mDepthContoursPurchased = true;
ctx.getSettings().DEPTH_CONTOURS_PURCHASED.set(true);
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(true);
notifyDismissProgress();
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_DEPTH_CONTOURS);
notifyItemPurchased(SKU_DEPTH_CONTOURS);
if (stopAfterResult) {
stop();
}
stop(true);
} else {
notifyDismissProgress(activeTask);
stop(true);
}
}
};
// Do not forget call stop() when helper is not needed anymore
public void stop() {
stop(false);
}
private void stop(boolean taskDone) {
logDebug("Destroying helper.");
if (mHelper != null) {
if (!inventoryRequesting) {
stopRequested = false;
if (taskDone) {
processingTask = false;
}
if (!processingTask) {
activeTask = null;
mHelper.dispose();
mHelper = null;
} else {
stopRequested = true;
}
} else {
processingTask = false;
activeTask = null;
}
}
@ -739,46 +696,46 @@ public class InAppHelper {
}
}
private void notifyError(String message) {
for (InAppListener l : listeners) {
l.onError(message);
private void notifyError(InAppPurchaseTaskType taskType, String message) {
for (InAppPurchaseListener l : listeners) {
l.onError(taskType, message);
}
}
private void notifyGetItems() {
for (InAppListener l : listeners) {
for (InAppPurchaseListener l : listeners) {
l.onGetItems();
}
}
private void notifyItemPurchased(String sku) {
for (InAppListener l : listeners) {
for (InAppPurchaseListener l : listeners) {
l.onItemPurchased(sku);
}
}
private void notifyShowProgress() {
for (InAppListener l : listeners) {
l.showProgress();
private void notifyShowProgress(InAppPurchaseTaskType taskType) {
for (InAppPurchaseListener l : listeners) {
l.showProgress(taskType);
}
}
private void notifyDismissProgress() {
for (InAppListener l : listeners) {
l.dismissProgress();
private void notifyDismissProgress(InAppPurchaseTaskType taskType) {
for (InAppPurchaseListener l : listeners) {
l.dismissProgress(taskType);
}
}
public void addListener(InAppListener listener) {
public void addListener(InAppPurchaseListener listener) {
this.listeners.add(listener);
}
public void removeListener(InAppListener listener) {
public void removeListener(InAppPurchaseListener listener) {
this.listeners.remove(listener);
}
private void complain(String message) {
logError("**** InAppHelper Error: " + message);
logError("**** InAppPurchaseHelper Error: " + message);
showToast(message);
}
@ -787,7 +744,9 @@ public class InAppHelper {
}
private void logDebug(String msg) {
if (mDebugLog) Log.d(TAG, msg);
if (mDebugLog) {
Log.d(TAG, msg);
}
}
private void logError(String msg) {

View file

@ -10,10 +10,10 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
@ -45,10 +45,12 @@ import net.osmand.plus.Version;
import net.osmand.plus.activities.LocalIndexHelper;
import net.osmand.plus.activities.LocalIndexInfo;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.activities.OsmandInAppPurchaseActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppHelper.InAppListener;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.resources.IncrementalChangesManager;
import net.osmand.util.Algorithms;
@ -73,7 +75,7 @@ import static net.osmand.plus.liveupdates.LiveUpdatesHelper.preferenceUpdateFreq
import static net.osmand.plus.liveupdates.LiveUpdatesHelper.runLiveUpdate;
import static net.osmand.plus.liveupdates.LiveUpdatesHelper.setAlarmForPendingIntent;
public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppListener {
public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppPurchaseListener {
public static final int TITLE = R.string.live_updates;
private static final int SUBSCRIPTION_SETTINGS = 5;
public static final Comparator<LocalIndexInfo> LOCAL_INDEX_INFO_COMPARATOR = new Comparator<LocalIndexInfo>() {
@ -90,10 +92,11 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
private ProgressBar progressBar;
private boolean processing;
public InAppHelper getInAppHelper() {
@Nullable
public InAppPurchaseHelper getInAppPurchaseHelper() {
Activity activity = getActivity();
if (activity instanceof OsmLiveActivity) {
return ((OsmLiveActivity) activity).getInAppHelper();
if (activity instanceof OsmandInAppPurchaseActivity) {
return ((OsmandInAppPurchaseActivity) activity).getPurchaseHelper();
} else {
return null;
}
@ -121,7 +124,8 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
listView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
if (!processing && InAppHelper.isSubscribedToLiveUpdates()) {
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (!processing && purchaseHelper != null && purchaseHelper.isSubscribedToLiveUpdates()) {
final FragmentManager fragmentManager = getChildFragmentManager();
LiveUpdatesSettingsDialogFragment
.createInstance(adapter.getChild(groupPosition, childPosition).getFileName())
@ -143,7 +147,8 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 0 && !processing && InAppHelper.isSubscribedToLiveUpdates()) {
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (position == 0 && !processing && purchaseHelper != null && purchaseHelper.isSubscribedToLiveUpdates()) {
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
subscriptionFragment.setEditMode(true);
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
@ -207,17 +212,17 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
@Override
public void onResume() {
super.onResume();
InAppHelper helper = getInAppHelper();
if (helper != null) {
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null) {
if (purchaseHelper.getActiveTask() == InAppPurchaseTaskType.REQUEST_INVENTORY) {
enableProgress();
helper.addListener(this);
helper.start(false);
}
purchaseHelper.addListener(this);
}
if (((OsmLiveActivity) getActivity()).shouldOpenSubscription()) {
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
}
}
@Override
@ -227,11 +232,11 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
}
@Override
public void onDestroy() {
super.onDestroy();
InAppHelper helper = getInAppHelper();
if (helper != null) {
helper.removeListener(this);
public void onPause() {
super.onPause();
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null) {
purchaseHelper.removeListener(this);
}
}
@ -383,7 +388,8 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
if (InAppHelper.isSubscribedToLiveUpdates()) {
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null && purchaseHelper.isSubscribedToLiveUpdates()) {
switchOnLiveUpdates(settings);
} else {
liveUpdatesSwitch.setChecked(false);
@ -578,7 +584,8 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
descriptionTextView.setText(context.getString(R.string.last_map_change, lastCheckString));
}
if (!fragment.isProcessing() && InAppHelper.isSubscribedToLiveUpdates()) {
InAppPurchaseHelper purchaseHelper = fragment.getInAppPurchaseHelper();
if (!fragment.isProcessing() && purchaseHelper != null && purchaseHelper.isSubscribedToLiveUpdates()) {
final View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -673,14 +680,14 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
}
@Override
public void onError(String error) {
public void onError(InAppPurchaseTaskType taskType, String error) {
disableProgress();
}
@Override
public void onGetItems() {
getSettings().LIVE_UPDATES_PURCHASED.set(InAppHelper.isSubscribedToLiveUpdates());
if (!InAppHelper.isSubscribedToLiveUpdates()) {
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null && !purchaseHelper.isSubscribedToLiveUpdates()) {
getSettings().IS_LIVE_UPDATES_ON.set(false);
adapter.enableLiveUpdates(false);
}
@ -689,18 +696,19 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment implements InAppList
@Override
public void onItemPurchased(String sku) {
if (InAppHelper.getSkuLiveUpdates().equals(sku)) {
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null && purchaseHelper.getSkuLiveUpdates().equals(sku)) {
updateSubscriptionHeader();
}
}
@Override
public void showProgress() {
public void showProgress(InAppPurchaseTaskType taskType) {
enableProgress();
}
@Override
public void dismissProgress() {
public void dismissProgress(InAppPurchaseTaskType taskType) {
disableProgress();
}
}

View file

@ -15,10 +15,8 @@ import android.view.MenuItem;
import net.osmand.AndroidNetworkUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.download.AbstractDownloadActivity;
import net.osmand.plus.download.DownloadIndexesThread;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
import org.apache.commons.logging.Log;
@ -28,32 +26,21 @@ import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class OsmLiveActivity extends AbstractDownloadActivity implements DownloadIndexesThread.DownloadEvents {
public class OsmLiveActivity extends AbstractDownloadActivity implements DownloadEvents {
private final static Log LOG = PlatformUtil.getLog(OsmLiveActivity.class);
public final static String OPEN_SUBSCRIPTION_INTENT_PARAM = "open_subscription_intent_param";
private LiveUpdatesFragmentPagerAdapter pagerAdapter;
private InAppHelper inAppHelper;
private boolean openSubscription;
private GetLastUpdateDateTask getLastUpdateDateTask;
private static final String URL = "https://osmand.net/api/osmlive_status";
public InAppHelper getInAppHelper() {
return inAppHelper;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
getMyApplication().applyTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_livie_updates);
if (Version.isGooglePlayEnabled(getMyApplication())) {
inAppHelper = new InAppHelper(getMyApplication(), false);
}
if (Version.isDeveloperVersion(getMyApplication())) {
inAppHelper = null;
}
Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
openSubscription = intent.getExtras().getBoolean(OPEN_SUBSCRIPTION_INTENT_PARAM, false);
@ -82,17 +69,6 @@ public class OsmLiveActivity extends AbstractDownloadActivity implements Downloa
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Pass on the activity result to the helper for handling
if (inAppHelper == null || !inAppHelper.onActivityResultHandled(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
protected void onPause() {
super.onPause();
@ -102,17 +78,17 @@ public class OsmLiveActivity extends AbstractDownloadActivity implements Downloa
@Override
protected void onDestroy() {
super.onDestroy();
if (inAppHelper != null) {
inAppHelper.stop();
}
if (getLastUpdateDateTask != null) {
getLastUpdateDateTask.cancel(true);
}
}
public boolean isInAppPurchaseAllowed() {
return true;
}
@Override
public void newDownloadIndexes() {
}
@Override

View file

@ -3,6 +3,8 @@ package net.osmand.plus.liveupdates;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.AppCompatCheckBox;
import android.view.LayoutInflater;
@ -22,9 +24,11 @@ import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.OsmandInAppPurchaseActivity;
import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.plus.inapp.InAppHelper;
import net.osmand.plus.inapp.InAppHelper.InAppListener;
import net.osmand.plus.inapp.InAppPurchaseHelper;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
import net.osmand.plus.liveupdates.CountrySelectionFragment.OnFragmentInteractionListener;
import net.osmand.util.Algorithms;
@ -35,7 +39,7 @@ import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppListener, OnFragmentInteractionListener {
public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppPurchaseListener, OnFragmentInteractionListener {
public static final String TAG = "SubscriptionFragment";
private static final String EDIT_MODE_ID = "edit_mode_id";
@ -59,10 +63,11 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
this.editMode = editMode;
}
public InAppHelper getInAppHelper() {
@Nullable
public InAppPurchaseHelper getInAppPurchaseHelper() {
Activity activity = getActivity();
if (activity instanceof OsmLiveActivity) {
return ((OsmLiveActivity) activity).getInAppHelper();
if (activity instanceof OsmandInAppPurchaseActivity) {
return ((OsmandInAppPurchaseActivity) activity).getPurchaseHelper();
} else {
return null;
}
@ -103,14 +108,9 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
InAppHelper helper = getInAppHelper();
if (helper != null) {
helper.addListener(this);
}
String userName = settings.BILLING_USER_NAME.get();
String email = settings.BILLING_USER_EMAIL.get();
String countryDownloadName = settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get();
@ -214,8 +214,8 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
saveChangesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
InAppHelper helper = getInAppHelper();
if (helper != null && applySettings(userNameEdit.getText().toString().trim(),
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null && applySettings(userNameEdit.getText().toString().trim(),
emailEdit.getText().toString().trim(), hideUserNameCheckbox.isChecked())) {
final Map<String, String> parameters = new HashMap<>();
@ -224,16 +224,16 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
parameters.put("email", settings.BILLING_USER_EMAIL.get());
parameters.put("cemail", prevEmail);
parameters.put("userid", settings.BILLING_USER_ID.get());
parameters.put("token", helper.getToken());
parameters.put("token", purchaseHelper.getToken());
showProgress();
showProgress(null);
AndroidNetworkUtils.sendRequestAsync(getMyApplication(),
"http://download.osmand.net/subscription/update.php",
parameters, "Sending data...", true, true, new AndroidNetworkUtils.OnRequestResultListener() {
@Override
public void onResult(String result) {
dismissProgress();
dismissProgress(null);
OsmandApplication app = getMyApplication();
if (result != null) {
try {
@ -283,12 +283,12 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
subscribeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
InAppHelper helper = getInAppHelper();
if (helper != null) {
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null) {
if (applySettings(userNameEdit.getText().toString().trim(),
emailEdit.getText().toString().trim(), hideUserNameCheckbox.isChecked())) {
helper.purchaseLiveUpdates(getActivity(),
purchaseHelper.purchaseLiveUpdates(getActivity(),
settings.BILLING_USER_EMAIL.get(),
settings.BILLING_USER_NAME.get(),
settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get(),
@ -308,13 +308,27 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
return view;
}
@Override
public void onResume() {
super.onResume();
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null) {
purchaseHelper.addListener(this);
}
}
@Override
public void onPause() {
super.onPause();
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper != null) {
purchaseHelper.removeListener(this);
}
}
@Override
public void onDestroy() {
super.onDestroy();
InAppHelper helper = getInAppHelper();
if (helper != null) {
helper.removeListener(this);
}
if (dlg != null && dlg.isShowing()) {
dlg.hide();
}
@ -350,7 +364,7 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
}
@Override
public void onError(String error) {
public void onError(InAppPurchaseTaskType taskType, String error) {
}
@Override
@ -365,7 +379,7 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
}
@Override
public void showProgress() {
public void showProgress(InAppPurchaseTaskType taskType) {
if (dlg != null) {
dlg.dismiss();
}
@ -377,7 +391,7 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
}
@Override
public void dismissProgress() {
public void dismissProgress(InAppPurchaseTaskType taskType) {
if (dlg != null) {
dlg.dismiss();
dlg = null;
@ -402,8 +416,9 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
}
if (view != null) {
TextView priceTextView = (TextView) view.findViewById(R.id.priceTextView);
if (InAppHelper.getLiveUpdatesPrice() != null) {
priceTextView.setText(InAppHelper.getLiveUpdatesPrice());
InAppPurchaseHelper purchaseHelper = getInAppPurchaseHelper();
if (purchaseHelper.getLiveUpdatesPrice() != null) {
priceTextView.setText(purchaseHelper.getLiveUpdatesPrice());
}
}
}

View file

@ -851,6 +851,19 @@ public class ResourceManager {
return map;
}
public List<AmenityIndexRepositoryBinary> getWikiAmenityRepository(double lat, double lon) {
List<AmenityIndexRepositoryBinary> repos = new ArrayList<>();
for (String filename : amenityRepositories.keySet()) {
if (filename.contains("_wiki")
|| filename.contains(IndexConstants.BINARY_WIKI_MAP_INDEX_EXT)) {
AmenityIndexRepository repository = amenityRepositories.get(filename);
if (repository.checkContains(lat, lon) && repository instanceof AmenityIndexRepositoryBinary) {
repos.add((AmenityIndexRepositoryBinary) repository);
}
}
}
return repos;
}
////////////////////////////////////////////// Working with address ///////////////////////////////////////////

View file

@ -1,10 +1,14 @@
package net.osmand.plus.wikivoyage;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
@ -12,29 +16,42 @@ import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import net.osmand.binary.BinaryMapDataObject;
import net.osmand.data.Amenity;
import net.osmand.data.PointDescription;
import net.osmand.map.OsmandRegions;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.WikipediaDialogFragment;
import net.osmand.plus.resources.AmenityIndexRepositoryBinary;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleWikiLinkFragment;
import net.osmand.plus.wikivoyage.data.TravelArticle;
import net.osmand.plus.wikivoyage.explore.WikivoyageExploreDialogFragment;
import net.osmand.util.MapUtils;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import static android.support.v4.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
interface RegionCallback {
void onRegionFound(String s);
}
/**
* Custom WebView client to handle the internal links.
*/
public class WikivoyageWebViewClient extends WebViewClient {
public class WikivoyageWebViewClient extends WebViewClient implements RegionCallback {
private static final String TAG = WikivoyageWebViewClient.class.getSimpleName();
@ -43,11 +60,16 @@ public class WikivoyageWebViewClient extends WebViewClient {
private Context context;
private TravelArticle article;
private boolean nightMode;
private String regionName;
private static final String PREFIX_GEO = "geo:";
private static final String PAGE_PREFIX_HTTP = "http://";
private static final String PAGE_PREFIX_HTTPS = "https://";
private static final String WEB_DOMAIN = ".wikivoyage.com/wiki/";
private static final String WIKIVOAYAGE_DOMAIN = ".wikivoyage.com/wiki/";
private static final String WIKI_DOMAIN = ".wikipedia.org/wiki/";
private FetchWikiRegion fetchRegionTask;
private WikiArticleSearchTask articleSearchTask;
public WikivoyageWebViewClient(FragmentActivity context, FragmentManager fm, boolean nightMode) {
app = (OsmandApplication) context.getApplication();
@ -58,24 +80,21 @@ public class WikivoyageWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.contains(WEB_DOMAIN)) {
String lang = url.substring(url.startsWith(PAGE_PREFIX_HTTPS) ? PAGE_PREFIX_HTTPS.length() : 0, url.indexOf("."));
String articleName = url.replace(PAGE_PREFIX_HTTPS + lang + WEB_DOMAIN, "")
.replaceAll("_", " ");
try {
articleName = URLDecoder.decode(articleName, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage(), e);
}
if (url.contains(WIKIVOAYAGE_DOMAIN)) {
String lang = getLang(url);
String articleName = getArticleNameFromUrl(url, lang);
long articleId = app.getTravelDbHelper().getArticleId(articleName, lang);
if (articleId != 0) {
WikivoyageArticleDialogFragment.showInstance(app, fragmentManager, articleId, lang);
} else {
warnAboutExternalLoad(url);
warnAboutExternalLoad(url, context, nightMode);
}
return true;
} else if (url.contains(WIKI_DOMAIN)) {
String articleName = getArticleNameFromUrl(url, getLang(url));
getWikiArticle(articleName, url);
} else if (url.startsWith(PAGE_PREFIX_HTTP) || url.startsWith(PAGE_PREFIX_HTTPS)) {
warnAboutExternalLoad(url);
warnAboutExternalLoad(url, context, nightMode);
} else if (url.startsWith(PREFIX_GEO)) {
if (article != null) {
List<GPXUtilities.WptPt> points = article.getGpxFile().getPoints();
@ -120,7 +139,27 @@ public class WikivoyageWebViewClient extends WebViewClient {
return true;
}
private void warnAboutExternalLoad(final String url) {
@NonNull
private String getLang(String url) {
return url.substring(url.startsWith(PAGE_PREFIX_HTTPS) ? PAGE_PREFIX_HTTPS.length() : 0, url.indexOf("."));
}
private String getArticleNameFromUrl(String url, String lang) {
String domain = url.contains(WIKIVOAYAGE_DOMAIN) ? WIKIVOAYAGE_DOMAIN : WIKI_DOMAIN;
String articleName = url.replace(PAGE_PREFIX_HTTPS + lang + domain, "")
.replaceAll("_", " ");
try {
articleName = URLDecoder.decode(articleName, "UTF-8");
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e.getMessage(), e);
}
return articleName;
}
private static void warnAboutExternalLoad(final String url, final Context context, final boolean nightMode) {
if (context == null) {
return;
}
new AlertDialog.Builder(context)
.setTitle(url)
.setMessage(R.string.online_webpage_warning)
@ -136,5 +175,160 @@ public class WikivoyageWebViewClient extends WebViewClient {
public void setArticle(TravelArticle article) {
this.article = article;
if (this.article != null && app != null) {
fetchRegionTask = new FetchWikiRegion(this, app.getRegions(), article.getLat(), article.getLon());
fetchRegionTask.execute();
}
}
private void getWikiArticle(String name, String url) {
List<AmenityIndexRepositoryBinary> indexes = app.getResourceManager()
.getWikiAmenityRepository(article.getLat(), article.getLon());
if (indexes.isEmpty()) {
WikivoyageArticleWikiLinkFragment.showInstance(fragmentManager, regionName == null ?
"" : regionName, url);
} else {
articleSearchTask = new WikiArticleSearchTask(name, indexes, (MapActivity) context, nightMode, url);
articleSearchTask.execute();
}
}
@Override
public void onRegionFound(String s) {
regionName = s;
}
public void stopRunningAsyncTasks() {
if (articleSearchTask != null && articleSearchTask.getStatus() == AsyncTask.Status.RUNNING) {
articleSearchTask.cancel(false);
}
if (fetchRegionTask != null && fetchRegionTask.getStatus() == AsyncTask.Status.RUNNING) {
fetchRegionTask.cancel(false);
}
}
private static class FetchWikiRegion extends AsyncTask<Void, Void, String> {
private RegionCallback callback;
private OsmandRegions osmandRegions;
private double lat;
private double lon;
FetchWikiRegion(RegionCallback callback, OsmandRegions osmandRegions, double lat, double lon) {
this.callback = callback;
this.osmandRegions = osmandRegions;
this.lat = lat;
this.lon = lon;
}
@Override
protected String doInBackground(Void... voids) {
if (osmandRegions != null) {
int x31 = MapUtils.get31TileNumberX(lon);
int y31 = MapUtils.get31TileNumberY(lat);
List<BinaryMapDataObject> dataObjects = null;
try {
if (isCancelled()) {
return null;
}
dataObjects = osmandRegions.query(x31, y31);
} catch (IOException e) {
e.printStackTrace();
}
if (dataObjects != null) {
for (BinaryMapDataObject b : dataObjects) {
if (isCancelled()) {
break;
}
if(osmandRegions.contain(b, x31, y31)) {
return osmandRegions.getLocaleName(osmandRegions.getDownloadName(b), false);
}
}
}
}
return "";
}
@Override
protected void onCancelled(){
callback = null;
}
@Override
protected void onPostExecute(String result) {
if (callback != null) {
callback.onRegionFound(result);
}
}
}
private static class WikiArticleSearchTask extends AsyncTask<Void, Void, List<Amenity>> {
private ProgressDialog dialog;
private String name;
private List<AmenityIndexRepositoryBinary> indexes;
private WeakReference<MapActivity> weakContext;
private boolean isNightMode;
private String url;
WikiArticleSearchTask(String articleName, List<AmenityIndexRepositoryBinary> indexes,
MapActivity context, boolean isNightMode, String url) {
name = articleName;
this.indexes = indexes;
weakContext = new WeakReference<>(context);
dialog = createProgressDialog();
this.isNightMode = isNightMode;
this.url = url;
}
@Override
protected void onPreExecute() {
if (dialog != null) {
dialog.show();
}
}
@Override
protected List<Amenity> doInBackground(Void... voids) {
List<Amenity> found = new ArrayList<>();
for (AmenityIndexRepositoryBinary repo : indexes) {
if (isCancelled()) {
break;
}
found.addAll(repo.searchAmenitiesByName(0, 0, 0, 0,
Integer.MAX_VALUE, Integer.MAX_VALUE, name, null));
}
return found;
}
@Override
protected void onCancelled(){
dialog = null;
indexes.clear();
}
@Override
protected void onPostExecute(List<Amenity> found) {
MapActivity activity = weakContext.get();
if (activity != null && !activity.isActivityDestroyed() && dialog != null) {
dialog.dismiss();
if (!found.isEmpty()) {
WikipediaDialogFragment.showInstance(activity, found.get(0));
} else {
warnAboutExternalLoad(url, weakContext.get(), isNightMode);
}
}
}
private ProgressDialog createProgressDialog() {
MapActivity activity = weakContext.get();
if (activity != null && !activity.isActivityDestroyed()) {
ProgressDialog dialog = new ProgressDialog(activity);
dialog.setCancelable(false);
dialog.setMessage(activity.getString(R.string.wiki_article_search_text));
return dialog;
}
return null;
}
}
}

View file

@ -247,6 +247,14 @@ public class WikivoyageArticleDialogFragment extends WikivoyageBaseDialogFragmen
}
}
@Override
public void onPause() {
super.onPause();
if (webViewClient != null) {
webViewClient.stopRunningAsyncTasks();
}
}
@Override
public void onResume() {
super.onResume();

View file

@ -0,0 +1,135 @@
package net.osmand.plus.wikivoyage.article;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.view.View;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerHalfItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleDividerItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.mapcontextmenu.WikipediaDialogFragment;
public class WikivoyageArticleWikiLinkFragment extends MenuBottomSheetDialogFragment {
public static final String TAG = WikivoyageArticleWikiLinkFragment.class.getSimpleName();
public static final String ARTICLE_URL_KEY = "article_url";
private static final String WIKI_REGION = "region";
private String articleUrl;
private String wikiRegion;
@Override
public void createMenuItems(Bundle savedInstanceState) {
Context ctx = getContext();
if (ctx == null) {
return;
}
if (savedInstanceState != null) {
articleUrl = savedInstanceState.getString(ARTICLE_URL_KEY);
wikiRegion = savedInstanceState.getString(WIKI_REGION);
} else {
Bundle args = getArguments();
if (args != null) {
articleUrl = args.getString(ARTICLE_URL_KEY);
wikiRegion = args.getString(WIKI_REGION);
}
}
items.add(new TitleItem(getString(R.string.how_to_open_wiki_title)));
BaseBottomSheetItem wikiLinkitem = new TitleItem.Builder().setTitle(articleUrl)
.setTitleColorId(nightMode
? R.color.wikivoyage_contents_parent_icon_dark : R.color.wikivoyage_contents_parent_icon_light)
.setLayoutId(R.layout.bottom_sheet_item_title)
.create();
items.add(wikiLinkitem);
items.add(new TitleDividerItem(getContext()));
Drawable downloadIcon = getIcon(R.drawable.ic_action_import, nightMode
? R.color.wikivoyage_contents_parent_icon_dark : R.color.wikivoyage_contents_parent_icon_light);
Drawable viewOnlineIcon = getIcon(R.drawable.ic_world_globe_dark, nightMode
? R.color.wikivoyage_contents_parent_icon_dark : R.color.wikivoyage_contents_parent_icon_light);
BaseBottomSheetItem wikiDownloadItem = new BottomSheetItemWithDescription.Builder()
.setDescription(getString(R.string.download_wikipedia_description, wikiRegion.isEmpty() ?
getString(R.string.download_wiki_region_placeholder) : wikiRegion))
.setIcon(downloadIcon)
.setTitle(getString(R.string.download_wikipedia_label))
.setLayoutId(R.layout.bottom_sheet_item_with_descr_56dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MapActivity mapActivity = (MapActivity) getActivity();
Intent newIntent = new Intent(mapActivity, mapActivity.getMyApplication().getAppCustomization()
.getDownloadActivity());
newIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
mapActivity.startActivity(newIntent);
dismiss();
}
})
.create();
items.add(wikiDownloadItem);
items.add(new DividerHalfItem(getContext()));
BaseBottomSheetItem wikiArticleOnlineItem = new BottomSheetItemWithDescription.Builder()
.setDescription(getString(R.string.open_in_browser_wiki_description))
.setIcon(viewOnlineIcon)
.setTitle(getString(R.string.open_in_browser_wiki))
.setLayoutId(R.layout.bottom_sheet_item_with_descr_56dp)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
WikipediaDialogFragment.showFullArticle(getContext(), Uri.parse(articleUrl), nightMode);
dismiss();
}
})
.create();
items.add(wikiArticleOnlineItem);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(ARTICLE_URL_KEY, articleUrl);
outState.putString(WIKI_REGION, wikiRegion);
}
@Override
protected boolean useScrollableItemsContainer() {
return false;
}
@Override
protected int getBgColorId() {
return nightMode ? R.color.wikivoyage_bottom_bar_bg_dark : R.color.bg_color_light;
}
public static boolean showInstance(@NonNull FragmentManager fm,
@NonNull String region,
@NonNull String articleUrl) {
try {
Bundle args = new Bundle();
args.putString(ARTICLE_URL_KEY, articleUrl);
args.putString(WIKI_REGION, region);
WikivoyageArticleWikiLinkFragment fragment = new WikivoyageArticleWikiLinkFragment();
fragment.setArguments(args);
fragment.show(fm, TAG);
return true;
} catch (RuntimeException e) {
return false;
}
}
}

View file

@ -91,14 +91,27 @@ public class TravelArticle {
return null;
}
int firstParagraphStart = content.indexOf("<p>");
int firstParagraphEnd = content.indexOf("</p>");
String pOpened = "<p>";
String pClosed = "</p>";
int firstParagraphStart = content.indexOf(pOpened);
int firstParagraphEnd = content.indexOf(pClosed);
if (firstParagraphStart == -1 || firstParagraphEnd == -1) {
return null;
}
int pClosedLength = pClosed.length();
String firstParagraphHtml = content.substring(firstParagraphStart, firstParagraphEnd + pClosedLength);
while (firstParagraphHtml.length() == (pOpened.length() + pClosedLength)
&& (firstParagraphEnd + pClosedLength) < content.length()) {
firstParagraphStart = content.indexOf(pOpened, firstParagraphEnd);
firstParagraphEnd = firstParagraphStart == -1 ? -1 : content.indexOf(pClosed, firstParagraphStart);
if (firstParagraphStart != -1 && firstParagraphEnd != -1) {
firstParagraphHtml = content.substring(firstParagraphStart, firstParagraphEnd + pClosedLength);
} else {
break;
}
}
// 4 is the length of </p> tag
String firstParagraphHtml = content.substring(firstParagraphStart, firstParagraphEnd + 4);
String firstParagraphText = Html.fromHtml(firstParagraphHtml).toString().trim();
String[] phrases = firstParagraphText.split("\\. ");

View file

@ -3,18 +3,41 @@ package net.osmand.plus.wikivoyage.explore;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.wikivoyage.explore.travelcards.BaseTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.OpenBetaTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard;
import java.util.ArrayList;
public class ExploreTabFragment extends BaseOsmAndFragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_explore_tab, container, false);
OsmandApplication app = getMyApplication();
boolean nightMode = !getSettings().isLightContent();
final View mainView = inflater.inflate(R.layout.fragment_explore_tab, container, false);
ArrayList<BaseTravelCard> items = new ArrayList<>();
OpenBetaTravelCard openBetaTravelCard = new OpenBetaTravelCard(app, nightMode, getFragmentManager());
StartEditingTravelCard startEditingTravelCard = new StartEditingTravelCard(app, nightMode);
items.add(openBetaTravelCard);
items.add(startEditingTravelCard);
final RecyclerView rv = (RecyclerView) mainView.findViewById(R.id.recycler_view);
rv.setLayoutManager(new LinearLayoutManager(getContext()));
return mainView;
}
}

View file

@ -0,0 +1,60 @@
package net.osmand.plus.wikivoyage.explore.travelcards;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.dialogs.ChoosePlanDialogFragment;
public class OpenBetaTravelCard extends BaseTravelCard {
private FragmentManager fragmentManager;
public OpenBetaTravelCard(OsmandApplication app, boolean nightMode, FragmentManager fragmentManager) {
super(app, nightMode);
this.fragmentManager = fragmentManager;
}
@Override
public void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof OpenBetaTravelVH) {
final OpenBetaTravelVH holder = (OpenBetaTravelVH) viewHolder;
holder.title.setText(R.string.welcome_to_open_beta);
holder.description.setText(R.string.welcome_to_open_beta_description);
holder.backgroundImage.setImageResource(R.drawable.img_help_wikivoyage_articles);
holder.button.setText(R.string.get_unlimited_access);
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ChoosePlanDialogFragment.showFreeVersionInstance(fragmentManager);
}
});
}
}
class OpenBetaTravelVH extends RecyclerView.ViewHolder {
final TextView title;
final TextView description;
final TextView button;
final ImageView backgroundImage;
OpenBetaTravelVH(final View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
button = (TextView) itemView.findViewById(R.id.bottom_button_text);
backgroundImage = (ImageView) itemView.findViewById(R.id.background_image);
}
}
@Override
public int getCardType() {
return 0;
}
}

View file

@ -0,0 +1,62 @@
package net.osmand.plus.wikivoyage.explore.travelcards;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.customtabs.CustomTabsIntent;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
public class StartEditingTravelCard extends BaseTravelCard {
public StartEditingTravelCard(OsmandApplication app, boolean nightMode) {
super(app, nightMode);
}
@Override
public void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof StartEditingTravelVH) {
final StartEditingTravelVH holder = (StartEditingTravelVH) viewHolder;
holder.title.setText(R.string.start_editing_card_image_text);
holder.description.setText(R.string.start_editing_card_description);
holder.backgroundImage.setImageResource(R.drawable.img_help_wikivoyage_contribute);
holder.button.setText(R.string.start_editing);
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder()
.setToolbarColor(ContextCompat.getColor(app, nightMode ? R.color.actionbar_dark_color : R.color.actionbar_light_color))
.build();
String text = "https://" + app.getLanguage().toLowerCase() + ".m.wikivoyage.org";
customTabsIntent.launchUrl(app, Uri.parse(text));
}
});
}
}
class StartEditingTravelVH extends RecyclerView.ViewHolder {
final TextView title;
final TextView description;
final TextView button;
final ImageView backgroundImage;
StartEditingTravelVH(final View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
button = (TextView) itemView.findViewById(R.id.bottom_button_text);
backgroundImage = (ImageView) itemView.findViewById(R.id.background_image);
}
}
@Override
public int getCardType() {
return 1;
}
}

View file

@ -0,0 +1,154 @@
package net.osmand.plus.wikivoyage.explore.travelcards;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
public class TravelDownloadUpdateCard extends BaseTravelCard {
public static final int TYPE = 50;
private boolean download;
private boolean loadingInProgress;
public TravelDownloadUpdateCard(OsmandApplication app, boolean nightMode, boolean download) {
super(app, nightMode);
this.download = download;
}
@Override
public void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof CardViewHolder) {
CardViewHolder holder = (CardViewHolder) viewHolder;
holder.title.setText(getTitle());
holder.icon.setImageDrawable(getIcon());
holder.description.setText(getDescription());
holder.fileIcon.setImageDrawable(getFileIcon());
holder.fileTitle.setText(getFileTitle());
holder.fileDescription.setText(getFileDescription());
boolean primaryBtnVisible = updatePrimaryButton(holder.primaryButton);
boolean secondaryBtnVisible = updateSecondaryButton(holder.secondaryBtn);
holder.buttonsDivider.setVisibility(primaryBtnVisible && secondaryBtnVisible ? View.VISIBLE : View.GONE);
}
}
@Override
public int getCardType() {
return TYPE;
}
@NonNull
private String getTitle() {
if (loadingInProgress) {
return app.getString(R.string.shared_string_downloading) + "...";
}
return app.getString(download ? R.string.download_file : R.string.update_is_available);
}
private Drawable getIcon() {
int id = download ? R.drawable.travel_card_download_icon : R.drawable.travel_card_update_icon;
return ContextCompat.getDrawable(app, id);
}
@NonNull
private String getDescription() {
return app.getString(download ? R.string.travel_card_download_descr : R.string.travel_card_update_descr);
}
@NonNull
private String getFileTitle() {
return "Some file"; // TODO
}
@NonNull
private String getFileDescription() {
return "Some description"; // TODO
}
private Drawable getFileIcon() {
return getActiveIcon(R.drawable.ic_action_read_article);
}
/**
* @return true if button is visible, false otherwise.
*/
private boolean updateSecondaryButton(TextView btn) {
if (loadingInProgress || !download) {
btn.setText(loadingInProgress ? R.string.shared_string_cancel : R.string.later);
btn.setVisibility(View.VISIBLE);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onSecondaryBtnClick();
}
});
return true;
}
btn.setVisibility(View.GONE);
return false;
}
/**
* @return true if button is visible, false otherwise.
*/
private boolean updatePrimaryButton(TextView btn) {
if (!loadingInProgress) {
btn.setText(download ? R.string.shared_string_download : R.string.shared_string_update);
btn.setVisibility(View.VISIBLE);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onPrimaryBtnClick();
}
});
return true;
}
btn.setVisibility(View.GONE);
return false;
}
private void onSecondaryBtnClick() {
}
private void onPrimaryBtnClick() {
}
public class CardViewHolder extends RecyclerView.ViewHolder {
final TextView title;
final ImageView icon;
final TextView description;
final ImageView fileIcon;
final TextView fileTitle;
final TextView fileDescription;
final ProgressBar progressBar;
final TextView secondaryBtn;
final View buttonsDivider;
final TextView primaryButton;
@SuppressWarnings("RedundantCast")
public CardViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
icon = (ImageView) itemView.findViewById(R.id.icon);
description = (TextView) itemView.findViewById(R.id.description);
fileIcon = (ImageView) itemView.findViewById(R.id.file_icon);
fileTitle = (TextView) itemView.findViewById(R.id.file_title);
fileDescription = (TextView) itemView.findViewById(R.id.file_description);
progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar);
secondaryBtn = (TextView) itemView.findViewById(R.id.secondary_button);
buttonsDivider = itemView.findViewById(R.id.buttons_divider);
primaryButton = (TextView) itemView.findViewById(R.id.primary_button);
}
}
}