Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2016-01-27 19:49:49 +01:00
commit 58ae1bd3ab
11 changed files with 690 additions and 393 deletions

View file

@ -38,6 +38,11 @@
<string name="osm_live_month_cost_desc">Monthly payment</string> <string name="osm_live_month_cost_desc">Monthly payment</string>
<string name="osm_live_active">Active</string> <string name="osm_live_active">Active</string>
<string name="osm_live_not_active">Inactive</string> <string name="osm_live_not_active">Inactive</string>
<string name="osm_live_enter_email">Please enter valid E-mail address</string>
<string name="osm_live_enter_user_name">Please enter Public Name</string>
<string name="osm_live_thanks">Thank you for subscribing to live updates!</string>
<string name="osm_live_region_desc">Part your donation will be sent to OSM users who submit changes to the map in that region</string>
<string name="osm_live_subscription_settings">Subscription settings</string>
<string name="osm_live_header">This subscription enables hourly updates for all maps around the world. <string name="osm_live_header">This subscription enables hourly updates for all maps around the world.
Major part of the income goes back to OSM community and is paid out per each OSM contribution. Major part of the income goes back to OSM community and is paid out per each OSM contribution.

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"><shape android:shape="rectangle">
<solid android:color="@color/map_widget_blue_pressed" />
<corners android:radius="@dimen/map_button_rect_rad" />
</shape></item>
<item><shape android:shape="rectangle">
<solid android:color="@color/map_widget_blue" />
<corners android:radius="@dimen/map_button_rect_rad" />
</shape></item>
</selector>

View file

@ -4,10 +4,10 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="8dp" android:paddingLeft="8dp"
android:paddingRight="8dp" android:paddingRight="8dp"
android:paddingTop="8dp" android:paddingTop="8dp">
android:orientation="vertical">
<LinearLayout <LinearLayout
android:id="@+id/subscription_banner" android:id="@+id/subscription_banner"
@ -20,26 +20,28 @@
android:paddingRight="8dp" android:paddingRight="8dp"
android:paddingTop="16dp"> android:paddingTop="16dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/ic_action_osm_live"/> android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_osm_live"/>
<net.osmand.plus.widgets.TextViewEx
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:text="@string/osm_live_subscription"
android:textColor="@color/color_white"
android:textSize="@dimen/default_list_text_size"
android:textStyle="bold"
app:typeface="@string/font_roboto_regular"/>
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/osm_live_subscription"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:textColor="@color/color_white"
android:textSize="@dimen/default_list_text_size"
android:textStyle="bold"
app:typeface="@string/font_roboto_regular"/>
</LinearLayout>
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -51,27 +53,28 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|right" android:layout_gravity="bottom|right"
android:gravity="right" android:layout_marginTop="16dp"
android:layout_marginTop="16dp"> android:gravity="right">
<Button
android:id="@+id/read_more_button" <Button
android:layout_width="wrap_content" android:id="@+id/read_more_button"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:textColor="@color/color_white" android:layout_height="wrap_content"
android:background="@drawable/btn_round_shade" android:background="@drawable/btn_round_shade"
android:text="@string/shared_string_read_more"/> android:text="@string/shared_string_read_more"
android:textColor="@color/color_white"/>
<Button
android:id="@+id/subscription_button" <Button
android:layout_width="wrap_content" android:id="@+id/subscription_button"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_marginLeft="32dp" android:layout_height="wrap_content"
android:textColor="@color/color_white" android:layout_marginLeft="32dp"
android:background="@drawable/btn_round_shade" android:background="@drawable/btn_round_shade"
android:text="@string/osm_live_subscribe_btn"/> android:text="@string/osm_live_subscribe_btn"
</LinearLayout> android:textColor="@color/color_white"/>
</LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -85,33 +88,54 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center_vertical"
android:minHeight="44dp"> android:minHeight="64dp"
android:orientation="horizontal">
<net.osmand.plus.widgets.TextViewEx <LinearLayout
android:layout_width="120dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp" android:orientation="vertical">
android:layout_marginRight="16dp"
android:text="@string/osm_live_subscription"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
app:typeface="@string/font_roboto_regular"/>
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:id="@+id/statusTextView" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:text="@string/shared_string_status"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/default_desc_text_size"
app:typeface="@string/font_roboto_regular"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/statusTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="4dp"
android:text="@string/osm_live_active"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_list_text_size_large"
app:typeface="@string/font_roboto_medium"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:layout_marginBottom="4dp" android:gravity="right|center_vertical"
android:layout_marginLeft="16dp" android:layout_marginRight="16dp">
android:layout_marginRight="16dp"
android:layout_marginTop="4dp" <ImageView
android:gravity="right" android:id="@+id/statusIcon"
android:text="@string/osm_live_active" android:layout_width="wrap_content"
android:textColor="?android:attr/textColorPrimary" android:layout_height="wrap_content"
android:textSize="@dimen/default_desc_text_size" android:src="@drawable/ic_action_done"/>
app:textAllCapsCompat="true"
app:typeface="@string/font_roboto_medium"/> </LinearLayout>
</LinearLayout> </LinearLayout>
<View <View
@ -123,7 +147,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:minHeight="44dp"> android:minHeight="48dp">
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
@ -133,7 +157,7 @@
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:text="@string/osm_live_support_region" android:text="@string/osm_live_support_region"
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_desc_text_size" android:textSize="@dimen/default_list_text_size"
app:typeface="@string/font_roboto_regular"/> app:typeface="@string/font_roboto_regular"/>
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
@ -147,12 +171,12 @@
android:gravity="right" android:gravity="right"
android:text="World" android:text="World"
android:textColor="?android:attr/textColorPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_desc_text_size" android:textSize="@dimen/default_list_text_size"
app:typeface="@string/font_roboto_medium"/> app:typeface="@string/font_roboto_medium"/>
</LinearLayout> </LinearLayout>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1dp" android:layout_height="1dp"
android:background="?attr/dashboard_divider"/> android:background="?attr/dashboard_divider"/>
@ -160,71 +184,20 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="right|center_vertical"
android:minHeight="44dp"> android:minHeight="48dp">
<Button
<net.osmand.plus.widgets.TextViewEx android:id="@+id/subscribeButton"
android:layout_width="120dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="6dp"
android:text="@string/shared_string_email_address" android:background="?attr/selectableItemBackground"
android:textColor="?android:attr/textColorPrimary" android:paddingLeft="10dp"
android:textSize="@dimen/default_desc_text_size" android:paddingRight="10dp"
app:typeface="@string/font_roboto_regular"/> android:text="@string/osm_live_subscribe_btn"
android:textColor="?attr/color_dialog_buttons"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/emailTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="4dp"
android:gravity="right"
android:text="my@email.com"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
app:typeface="@string/font_roboto_medium"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dashboard_divider"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="44dp">
<net.osmand.plus.widgets.TextViewEx
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:text="@string/osm_live_user_public_name"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
app:typeface="@string/font_roboto_regular"/>
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/userNameTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="4dp"
android:gravity="right"
android:text="None"
android:textColor="?android:attr/textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
app:typeface="@string/font_roboto_medium"/>
</LinearLayout> </LinearLayout>

View file

@ -16,11 +16,12 @@
<ImageButton <ImageButton
android:id="@+id/closeButton" android:id="@+id/closeButton"
style="@style/Widget.AppCompat.Button.Borderless" style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="48dp" android:layout_width="52dp"
android:layout_height="48dp" android:layout_height="52dp"
android:src="@drawable/ic_action_remove_dark"/> android:src="@drawable/ic_action_remove_dark"/>
<net.osmand.plus.widgets.TextViewEx <net.osmand.plus.widgets.TextViewEx
android:id="@+id/titleTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
@ -142,21 +143,36 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="2dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/osm_live_support_region"/>
<net.osmand.plus.widgets.AutoCompleteTextViewEx <net.osmand.plus.widgets.AutoCompleteTextViewEx
android:id="@+id/selectCountryEdit" android:id="@+id/selectCountryEdit"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="4dp"
android:paddingLeft="2dp" android:paddingLeft="2dp"
android:paddingRight="0dp" android:paddingRight="0dp"
android:drawableRight="@drawable/ic_action_arrow_drop_down" android:drawableRight="@drawable/ic_action_arrow_drop_down"
android:editable="false" android:editable="false"
android:hint="@string/osm_live_support_region"/> android:text="Ukraine"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="2dp"
android:layout_marginTop="8dp"
android:textColor="?android:attr/textColorSecondary"
android:text="@string/osm_live_region_desc"/>
</LinearLayout> </LinearLayout>
@ -165,11 +181,35 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/editModeBottomView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:visibility="gone">
<Button
android:id="@+id/saveChangesButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="72dp"
android:layout_marginRight="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColor="@color/color_white"
android:background="@drawable/btn_round_blue"
android:text="@string/shared_string_save_changes"/>
</LinearLayout>
<LinearLayout
android:id="@+id/purchaseCard"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="8dp" android:layout_margin="8dp"
android:background="?attr/bg_card" android:background="?attr/bg_card"
android:orientation="vertical"> android:orientation="vertical"
android:visibility="visible">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -9,6 +9,8 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated). 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 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="shared_string_status">Status</string>
<string name="shared_string_save_changes">Save changes</string>
<string name="shared_string_email_address">E-mail address</string> <string name="shared_string_email_address">E-mail address</string>
<string name="rendering_attr_hideUnderground_name">Hide underground objects</string> <string name="rendering_attr_hideUnderground_name">Hide underground objects</string>
<string name="data_is_not_available">Data is not available</string> <string name="data_is_not_available">Data is not available</string>

View file

@ -0,0 +1,147 @@
package net.osmand;
import android.os.AsyncTask;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.Map;
public class AndroidNetworkUtils {
public interface OnRequestResultListener {
void onResult(String result);
}
public static void sendRequestAsync(final OsmandApplication ctx,
final String url,
final Map<String, String> parameters,
final String userOperation,
final OnRequestResultListener listener) {
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
return sendRequest(ctx, url, parameters, userOperation);
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(String response) {
if (listener != null) {
listener.onResult(response);
}
}
}.execute((Void) null);
}
public static String sendRequest(OsmandApplication ctx, String url, Map<String, String> parameters, String userOperation) {
HttpURLConnection connection = null;
try {
connection = NetworkUtils.getHttpURLConnection(url);
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx));
connection.setConnectTimeout(15000);
if (parameters != null && parameters.size() > 0) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
String params = sb.toString();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
connection.setRequestProperty("Content-Length", String.valueOf(params.getBytes("UTF-8").length));
connection.setFixedLengthStreamingMode(params.getBytes("UTF-8").length);
OutputStream output = new BufferedOutputStream(connection.getOutputStream());
output.write(params.getBytes("UTF-8"));
output.flush();
output.close();
} else {
connection.setRequestMethod("GET");
connection.connect();
}
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
String msg = userOperation
+ " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage();
showToast(ctx, msg);
} else {
StringBuilder responseBody = new StringBuilder();
responseBody.setLength(0);
InputStream i = connection.getInputStream();
if (i != null) {
BufferedReader in = new BufferedReader(new InputStreamReader(i, "UTF-8"), 256);
String s;
boolean f = true;
while ((s = in.readLine()) != null) {
if (!f) {
responseBody.append("\n");
} else {
f = false;
}
responseBody.append(s);
}
try {
in.close();
i.close();
} catch (Exception e) {
// ignore exception
}
}
return responseBody.toString();
}
} catch (NullPointerException e) {
// that's tricky case why NPE is thrown to fix that problem httpClient could be used
String msg = ctx.getString(R.string.auth_failed);
showToast(ctx, msg);
} catch (MalformedURLException e) {
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
} catch (IOException e) {
showToast(ctx, MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
+ ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation));
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
}
private static void showToast(OsmandApplication ctx, String message) {
ctx.showToastMessage(message);
}
}

View file

@ -818,6 +818,7 @@ public class OsmandSettings {
public final OsmandPreference<String> BILLING_USER_COUNTRY_DOWNLOAD_NAME = new StringPreference("billing_user_country_download_name", "").makeGlobal(); public final OsmandPreference<String> BILLING_USER_COUNTRY_DOWNLOAD_NAME = new StringPreference("billing_user_country_download_name", "").makeGlobal();
public final OsmandPreference<Boolean> BILLING_HIDE_USER_NAME = new BooleanPreference("billing_hide_user_name", false).makeGlobal(); public final OsmandPreference<Boolean> BILLING_HIDE_USER_NAME = new BooleanPreference("billing_hide_user_name", false).makeGlobal();
public final OsmandPreference<Boolean> BILLING_PURCHASE_TOKEN_SENT = new BooleanPreference("billing_purchase_token_sent", false).makeGlobal(); public final OsmandPreference<Boolean> BILLING_PURCHASE_TOKEN_SENT = new BooleanPreference("billing_purchase_token_sent", false).makeGlobal();
public final OsmandPreference<Boolean> LIVE_UPDATES_PURCHASED = new BooleanPreference("billing_live_updates_purchased", false).makeGlobal();
// this value string is synchronized with settings_pref.xml preference name // this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<String> USER_OSM_BUG_NAME = public final OsmandPreference<String> USER_OSM_BUG_NAME =

View file

@ -5,7 +5,8 @@ import android.content.Intent;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
import net.osmand.osm.io.NetworkUtils; import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidNetworkUtils.OnRequestResultListener;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
@ -19,16 +20,6 @@ import net.osmand.util.Algorithms;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -37,6 +28,7 @@ import java.util.Map;
public class InAppHelper { public class InAppHelper {
// Debug tag, for logging // Debug tag, for logging
static final String TAG = "InAppHelper"; static final String TAG = "InAppHelper";
boolean mDebugLog = false;
private static boolean mSubscribedToLiveUpdates = false; private static boolean mSubscribedToLiveUpdates = false;
private static String mLiveUpdatesPrice; private static String mLiveUpdatesPrice;
@ -112,7 +104,7 @@ public class InAppHelper {
"YTjh1H/ZgqIHy5ZluahINuDE76qdLYMXrDMQIDAQAB"; "YTjh1H/ZgqIHy5ZluahINuDE76qdLYMXrDMQIDAQAB";
// Create the helper, passing it our context and the public key to verify signatures with // Create the helper, passing it our context and the public key to verify signatures with
Log.d(TAG, "Creating InAppHelper."); logDebug("Creating InAppHelper.");
mHelper = new IabHelper(ctx, base64EncodedPublicKey); mHelper = new IabHelper(ctx, base64EncodedPublicKey);
// enable debug logging (for a production application, you should set this to false). // enable debug logging (for a production application, you should set this to false).
@ -120,10 +112,10 @@ public class InAppHelper {
// Start setup. This is asynchronous and the specified listener // Start setup. This is asynchronous and the specified listener
// will be called once setup completes. // will be called once setup completes.
Log.d(TAG, "Starting setup."); logDebug("Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) { public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished."); logDebug("Setup finished.");
if (!result.isSuccess()) { if (!result.isSuccess()) {
// Oh noes, there was a problem. // Oh noes, there was a problem.
@ -141,7 +133,7 @@ public class InAppHelper {
if (mHelper == null) return; if (mHelper == null) return;
// IAB is fully set up. Now, let's get an inventory of stuff we own. // IAB is fully set up. Now, let's get an inventory of stuff we own.
Log.d(TAG, "Setup successful. Querying inventory."); logDebug("Setup successful. Querying inventory.");
List<String> skus = new ArrayList<>(); List<String> skus = new ArrayList<>();
skus.add(SKU_LIVE_UPDATES); skus.add(SKU_LIVE_UPDATES);
mHelper.queryInventoryAsync(true, skus, mGotInventoryListener); mHelper.queryInventoryAsync(true, skus, mGotInventoryListener);
@ -152,7 +144,7 @@ public class InAppHelper {
// Listener that's called when we finish querying the items and subscriptions we own // Listener that's called when we finish querying the items and subscriptions we own
private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() { private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) { public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished."); logDebug("Query inventory finished.");
// Have we been disposed of in the meantime? If so, quit. // Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return; if (mHelper == null) return;
@ -169,7 +161,7 @@ public class InAppHelper {
return; return;
} }
Log.d(TAG, "Query inventory was successful."); logDebug("Query inventory was successful.");
/* /*
* Check for items we own. Notice that for each purchase, we check * Check for items we own. Notice that for each purchase, we check
@ -180,7 +172,7 @@ public class InAppHelper {
// Do we have the live updates? // Do we have the live updates?
Purchase liveUpdatesPurchase = inventory.getPurchase(SKU_LIVE_UPDATES); Purchase liveUpdatesPurchase = inventory.getPurchase(SKU_LIVE_UPDATES);
mSubscribedToLiveUpdates = (liveUpdatesPurchase != null); mSubscribedToLiveUpdates = (liveUpdatesPurchase != null);
Log.d(TAG, "User " + (mSubscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE") logDebug("User " + (mSubscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
+ " live updates purchased."); + " live updates purchased.");
if (inventory.hasDetails(SKU_LIVE_UPDATES)) { if (inventory.hasDetails(SKU_LIVE_UPDATES)) {
@ -200,12 +192,12 @@ public class InAppHelper {
stop(); stop();
} }
Log.d(TAG, "Initial inapp query finished"); logDebug("Initial inapp query finished");
} }
}; };
public void purchaseLiveUpdates(final Activity activity, final String email, final String userName, public void purchaseLiveUpdates(final Activity activity, final String email, final String userName,
final String countryDownloadName) { final String countryDownloadName, final boolean hideUserName) {
if (!mHelper.subscriptionsSupported()) { if (!mHelper.subscriptionsSupported()) {
complain("Subscriptions not supported on your device yet. Sorry!"); complain("Subscriptions not supported on your device yet. Sorry!");
if (callbacks != null) { if (callbacks != null) {
@ -228,59 +220,56 @@ public class InAppHelper {
@Override @Override
protected String doInBackground(Void... params) { protected String doInBackground(Void... params) {
userId = ctx.getSettings().BILLING_USER_ID.get(); userId = ctx.getSettings().BILLING_USER_ID.get();
if (Algorithms.isEmpty(userId)) { try {
try { Map<String, String> parameters = new HashMap<>();
Map<String, String> parameters = new HashMap<>(); parameters.put("visibleName", hideUserName ? "" : userName);
parameters.put("visibleName", userName); parameters.put("preferredCountry", countryDownloadName);
parameters.put("preferredCountry", countryDownloadName); parameters.put("email", email);
parameters.put("email", email); if (Algorithms.isEmpty(userId)) {
parameters.put("status", "new"); parameters.put("status", "new");
return sendRequest("http://download.osmand.net/subscription/register.php",
parameters, "Requesting userId...");
} catch (Exception e) {
Log.e(TAG, "sendRequest Error", e);
return null;
} }
} else {
return AndroidNetworkUtils.sendRequest(ctx,
"http://download.osmand.net/subscription/register.php",
parameters, "Requesting userId...");
} catch (Exception e) {
logError("sendRequest Error", e);
return null; return null;
} }
} }
@Override @Override
protected void onPostExecute(String response) { protected void onPostExecute(String response) {
if (Algorithms.isEmpty(userId)) { logDebug("Response=" + response);
Log.d(TAG, "Response=" + response); if (response == null) {
if (response == null) { complain("Cannot retrieve userId from server.");
complain("Cannot retrieve userId from server."); if (callbacks != null) {
callbacks.dismissProgress();
callbacks.onError("Cannot retrieve userId from server.");
}
if (stopAfterResult) {
stop();
}
return;
} else {
try {
JSONObject obj = new JSONObject(response);
userId = obj.getString("userid");
ctx.getSettings().BILLING_USER_ID.set(userId);
logDebug("UserId=" + userId);
} catch (JSONException e) {
String message = "JSON parsing error: "
+ (e.getMessage() == null ? "unknown" : e.getMessage());
complain(message);
if (callbacks != null) { if (callbacks != null) {
callbacks.dismissProgress(); callbacks.dismissProgress();
callbacks.onError("Cannot retrieve userId from server."); callbacks.onError(message);
} }
if (stopAfterResult) { if (stopAfterResult) {
stop(); stop();
} }
return;
} else {
try {
JSONObject obj = new JSONObject(response);
userId = obj.getString("userid");
ctx.getSettings().BILLING_USER_ID.set(userId);
Log.d(TAG, "UserId=" + userId);
} catch (JSONException e) {
String message = "JSON parsing error: "
+ (e.getMessage() == null ? "unknown" : e.getMessage());
complain(message);
if (callbacks != null) {
callbacks.dismissProgress();
callbacks.onError(message);
}
if (stopAfterResult) {
stop();
}
}
} }
} }
@ -288,7 +277,7 @@ public class InAppHelper {
callbacks.dismissProgress(); callbacks.dismissProgress();
} }
if (!Algorithms.isEmpty(userId)) { if (!Algorithms.isEmpty(userId)) {
Log.d(TAG, "Launching purchase flow for live updates subscription for userId=" + userId); logDebug("Launching purchase flow for live updates subscription for userId=" + userId);
String payload = userId; String payload = userId;
if (mHelper != null) { if (mHelper != null) {
mHelper.launchPurchaseFlow(activity, mHelper.launchPurchaseFlow(activity,
@ -308,26 +297,31 @@ public class InAppHelper {
} }
public boolean onActivityResultHandled(int requestCode, int resultCode, Intent data) { public boolean onActivityResultHandled(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data); logDebug("onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mHelper == null) return false; if (mHelper == null) return false;
// Pass on the activity result to the helper for handling try {
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) { // Pass on the activity result to the helper for handling
// not handled, so handle it ourselves (here's where you'd if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// perform any handling of activity results not related to in-app // not handled, so handle it ourselves (here's where you'd
// billing... // perform any handling of activity results not related to in-app
//super.onActivityResult(requestCode, resultCode, data); // billing...
//super.onActivityResult(requestCode, resultCode, data);
return false;
} else {
logDebug("onActivityResult handled by IABUtil.");
return true;
}
} catch (Exception e) {
logError("onActivityResultHandled", e);
return false; return false;
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
return true;
} }
} }
// Callback for when a purchase is finished // Callback for when a purchase is finished
private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) { public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase); logDebug("Purchase finished: " + result + ", purchase: " + purchase);
// if we were disposed of in the meantime, quit. // if we were disposed of in the meantime, quit.
if (mHelper == null) return; if (mHelper == null) return;
@ -344,15 +338,17 @@ public class InAppHelper {
return; return;
} }
Log.d(TAG, "Purchase successful."); logDebug("Purchase successful.");
if (purchase.getSku().equals(SKU_LIVE_UPDATES)) { if (purchase.getSku().equals(SKU_LIVE_UPDATES)) {
// bought live updates // bought live updates
sendToken(purchase.getToken()); sendToken(purchase.getToken());
Log.d(TAG, "Live updates subscription purchased."); logDebug("Live updates subscription purchased.");
showToast("Thank you for subscribing to live updates!"); showToast(ctx.getString(R.string.osm_live_thanks));
mSubscribedToLiveUpdates = true; mSubscribedToLiveUpdates = true;
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
if (callbacks != null) { if (callbacks != null) {
callbacks.dismissProgress(); callbacks.dismissProgress();
callbacks.onItemPurchased(SKU_LIVE_UPDATES); callbacks.onItemPurchased(SKU_LIVE_UPDATES);
@ -366,7 +362,7 @@ public class InAppHelper {
// Do not forget call stop() when helper is not needed anymore // Do not forget call stop() when helper is not needed anymore
public void stop() { public void stop() {
Log.d(TAG, "Destroying helper."); logDebug("Destroying helper.");
if (mHelper != null) { if (mHelper != null) {
mHelper.dispose(); mHelper.dispose();
mHelper = null; mHelper = null;
@ -378,27 +374,35 @@ public class InAppHelper {
String email = ctx.getSettings().BILLING_USER_EMAIL.get(); String email = ctx.getSettings().BILLING_USER_EMAIL.get();
try { try {
Map<String, String> parameters = new HashMap<>(); Map<String, String> parameters = new HashMap<>();
parameters.put("userId", userId); parameters.put("userid", userId);
parameters.put("sku", SKU_LIVE_UPDATES); parameters.put("sku", SKU_LIVE_UPDATES);
parameters.put("purchaseToken", token); parameters.put("purchaseToken", token);
parameters.put("email", email); parameters.put("email", email);
sendRequestAsync("http://download.osmand.net/subscription/purchased.php", AndroidNetworkUtils.sendRequestAsync(ctx,
"http://download.osmand.net/subscription/purchased.php",
parameters, "Sending purchase info...", new OnRequestResultListener() { parameters, "Sending purchase info...", new OnRequestResultListener() {
@Override @Override
public void onResult(String result) { public void onResult(String result) {
if (result != null && result.trim().toLowerCase().equals("ok")) { if (result != null) {
ctx.getSettings().BILLING_PURCHASE_TOKEN_SENT.set(true); try {
JSONObject obj = new JSONObject(result);
if (!obj.has("error")) {
ctx.getSettings().BILLING_PURCHASE_TOKEN_SENT.set(true);
}
} catch (JSONException e) {
logError("sendToken", e);
}
} }
} }
}); });
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "sendToken Error", e); logError("sendToken Error", e);
} }
} }
private void complain(String message) { private void complain(String message) {
Log.e(TAG, "**** InAppHelper Error: " + message); logError("**** InAppHelper Error: " + message);
showToast("Error: " + message); showToast("Error: " + message);
} }
@ -406,124 +410,16 @@ public class InAppHelper {
ctx.showToastMessage(message); ctx.showToastMessage(message);
} }
private String sendRequest(String url, Map<String, String> parameters, String userOperation) { void logDebug(String msg) {
Log.d(TAG, "Sending request " + url); if (mDebugLog) Log.d(TAG, msg);
HttpURLConnection connection = null;
try {
connection = NetworkUtils.getHttpURLConnection(url);
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx));
connection.setConnectTimeout(15000);
if (parameters != null && parameters.size() > 0) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : parameters.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
String params = sb.toString();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
connection.setRequestProperty("Content-Length", String.valueOf(params.getBytes("UTF-8").length));
connection.setFixedLengthStreamingMode(params.getBytes("UTF-8").length);
OutputStream output = new BufferedOutputStream(connection.getOutputStream());
output.write(params.getBytes("UTF-8"));
output.flush();
output.close();
} else {
connection.setRequestMethod("GET");
connection.connect();
}
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
String msg = userOperation
+ " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage();
Log.e(TAG, msg);
showToast(msg);
} else {
Log.d(TAG, "Response : " + connection.getResponseMessage());
// populate return fields.
StringBuilder responseBody = new StringBuilder();
responseBody.setLength(0);
InputStream i = connection.getInputStream();
if (i != null) {
BufferedReader in = new BufferedReader(new InputStreamReader(i, "UTF-8"), 256);
String s;
boolean f = true;
while ((s = in.readLine()) != null) {
if (!f) {
responseBody.append("\n");
} else {
f = false;
}
responseBody.append(s);
}
try {
in.close();
i.close();
} catch (Exception e) {
Log.e(TAG, "sendRequest", e);
}
}
return responseBody.toString();
}
} catch (NullPointerException e) {
// that's tricky case why NPE is thrown to fix that problem httpClient could be used
String msg = ctx.getString(R.string.auth_failed);
Log.e(TAG, msg, e);
showToast(msg);
} catch (MalformedURLException e) {
Log.e(TAG, userOperation + " " + ctx.getString(R.string.failed_op), e);
showToast(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
+ ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation));
} catch (IOException e) {
Log.e(TAG, userOperation + " " + ctx.getString(R.string.failed_op), e);
showToast(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template)
+ ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation));
} finally {
if (connection != null) {
connection.disconnect();
}
}
return null;
} }
private void sendRequestAsync(final String url, final Map<String, String> parameters, final String userOperation, final OnRequestResultListener listener) { void logError(String msg) {
Log.e(TAG, "Error: " + msg);
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
return sendRequest(url, parameters, userOperation);
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(String response) {
if (listener != null) {
listener.onResult(response);
}
}
}.execute((Void) null);
} }
private interface OnRequestResultListener { void logError(String msg, Throwable e) {
void onResult(String result); Log.e(TAG, "Error: " + msg, e);
} }
} }

View file

@ -22,6 +22,7 @@ import net.osmand.plus.R;
import net.osmand.plus.base.BaseOsmAndDialogFragment; import net.osmand.plus.base.BaseOsmAndDialogFragment;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -185,7 +186,7 @@ public class CountrySelectionFragment extends BaseOsmAndDialogFragment {
return name; return name;
} }
public static class CountryItem { public static class CountryItem implements Serializable {
private String localName; private String localName;
private String downloadName; private String downloadName;

View file

@ -3,15 +3,23 @@ package net.osmand.plus.liveupdates;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.DrawableRes; import android.support.annotation.DrawableRes;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.SwitchCompat; import android.support.v7.widget.SwitchCompat;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AbsListView; import android.widget.AbsListView;
@ -57,6 +65,7 @@ import static net.osmand.plus.liveupdates.LiveUpdatesHelper.setAlarmForPendingIn
public class LiveUpdatesFragment extends BaseOsmAndFragment { public class LiveUpdatesFragment extends BaseOsmAndFragment {
public static final String TITLE = "Live Updates"; public static final String TITLE = "Live Updates";
private static final int SUBSCRIPTION_SETTINGS = 5;
public static final Comparator<LocalIndexInfo> LOCAL_INDEX_INFO_COMPARATOR = new Comparator<LocalIndexInfo>() { public static final Comparator<LocalIndexInfo> LOCAL_INDEX_INFO_COMPARATOR = new Comparator<LocalIndexInfo>() {
@Override @Override
public int compare(LocalIndexInfo lhs, LocalIndexInfo rhs) { public int compare(LocalIndexInfo lhs, LocalIndexInfo rhs) {
@ -71,6 +80,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
} }
@Override @Override
@ -94,27 +104,32 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
} }
}); });
//test
//getSettings().LIVE_UPDATES_PURCHASED.set(true);
subscriptionHeader = inflater.inflate(R.layout.live_updates_header, listView, false); subscriptionHeader = inflater.inflate(R.layout.live_updates_header, listView, false);
updateHeader();
listView.addHeaderView(subscriptionHeader);
loadLocalIndexesTask = new LoadLocalIndexTask(adapter, this).execute();
return view;
}
public void updateHeader() {
View subscriptionBanner = subscriptionHeader.findViewById(R.id.subscription_banner); View subscriptionBanner = subscriptionHeader.findViewById(R.id.subscription_banner);
View subscriptionInfo = subscriptionHeader.findViewById(R.id.subscription_info); View subscriptionInfo = subscriptionHeader.findViewById(R.id.subscription_info);
Button subscriptionButton = (Button) subscriptionHeader.findViewById(R.id.subscription_button); if (getSettings().LIVE_UPDATES_PURCHASED.get()) {
subscriptionButton.setOnClickListener(new View.OnClickListener() { ImageView statusIcon = (ImageView) subscriptionHeader.findViewById(R.id.statusIcon);
@Override
public void onClick(View v) {
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
}
});
if (InAppHelper.isSubscribedToLiveUpdates()) {
TextView statusTextView = (TextView) subscriptionHeader.findViewById(R.id.statusTextView); TextView statusTextView = (TextView) subscriptionHeader.findViewById(R.id.statusTextView);
TextView regionNameTextView = (TextView) subscriptionHeader.findViewById(R.id.regionTextView); TextView regionNameTextView = (TextView) subscriptionHeader.findViewById(R.id.regionTextView);
TextView emailTextView = (TextView) subscriptionHeader.findViewById(R.id.emailTextView);
TextView userNameTextView = (TextView) subscriptionHeader.findViewById(R.id.userNameTextView);
if (InAppHelper.isSubscribedToLiveUpdates()) { if (InAppHelper.isSubscribedToLiveUpdates()) {
statusTextView.setText(getString(R.string.osm_live_active)); statusTextView.setText(getString(R.string.osm_live_active));
statusIcon.setImageDrawable(getMyApplication().getIconsCache().getContentIcon(R.drawable.ic_action_done));
} else { } else {
statusTextView.setText(getString(R.string.osm_live_not_active)); statusTextView.setText(getString(R.string.osm_live_not_active));
statusIcon.setImageDrawable(getMyApplication().getIconsCache().getContentIcon(R.drawable.ic_action_remove_dark));
} }
OsmandSettings settings = getMyApplication().getSettings(); OsmandSettings settings = getMyApplication().getSettings();
@ -126,19 +141,39 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
} }
regionNameTextView.setText(countryName); regionNameTextView.setText(countryName);
emailTextView.setText(settings.BILLING_USER_EMAIL.get()); Button subscribeButton = (Button) subscriptionHeader.findViewById(R.id.subscribeButton);
userNameTextView.setText(settings.BILLING_USER_NAME.get()); subscribeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
}
});
subscriptionBanner.setVisibility(View.GONE); subscriptionBanner.setVisibility(View.GONE);
subscriptionInfo.setVisibility(View.VISIBLE); subscriptionInfo.setVisibility(View.VISIBLE);
} else { } else {
Button readMoreBtn = (Button) subscriptionHeader.findViewById(R.id.read_more_button);
readMoreBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Uri uri = Uri.parse("http://osmand.net/osm_live.php");
Intent goToOsmLive = new Intent(Intent.ACTION_VIEW, uri);
startActivity(goToOsmLive);
}
});
Button subscriptionButton = (Button) subscriptionHeader.findViewById(R.id.subscription_button);
subscriptionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
}
});
subscriptionBanner.setVisibility(View.VISIBLE); subscriptionBanner.setVisibility(View.VISIBLE);
subscriptionInfo.setVisibility(View.GONE); subscriptionInfo.setVisibility(View.GONE);
} }
listView.addHeaderView(subscriptionHeader);
loadLocalIndexesTask = new LoadLocalIndexTask(adapter, this).execute();
return view;
} }
public void updateSubscriptionBanner() { public void updateSubscriptionBanner() {
@ -165,6 +200,34 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
} }
} }
@SuppressWarnings("deprecation")
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (getSettings().LIVE_UPDATES_PURCHASED.get()) {
ActionBar actionBar = getMyActivity().getSupportActionBar();
if (actionBar != null) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
}
SubMenu split = menu.addSubMenu(R.string.shared_string_more_actions);
split.setIcon(R.drawable.ic_overflow_menu_white);
MenuItemCompat.setShowAsAction(split.getItem(), MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
MenuItem item = split.add(0, SUBSCRIPTION_SETTINGS, 0, R.string.osm_live_subscription_settings);
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == SUBSCRIPTION_SETTINGS) {
SubscriptionFragment subscriptionFragment = new SubscriptionFragment();
subscriptionFragment.setEditMode(true);
subscriptionFragment.show(getChildFragmentManager(), SubscriptionFragment.TAG);
return true;
}
return super.onOptionsItemSelected(item);
}
protected class LocalIndexesAdapter extends OsmandBaseExpandableListAdapter { protected class LocalIndexesAdapter extends OsmandBaseExpandableListAdapter {
public static final int SHOULD_UPDATE_GROUP_POSITION = 0; public static final int SHOULD_UPDATE_GROUP_POSITION = 0;
public static final int SHOULD_NOT_UPDATE_GROUP_POSITION = 1; public static final int SHOULD_NOT_UPDATE_GROUP_POSITION = 1;
@ -382,6 +445,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
divider = view.findViewById(R.id.divider); divider = view.findViewById(R.id.divider);
} }
@SuppressWarnings("deprecation")
public void bindLocalIndexInfo(final LocalIndexInfo item, boolean isLastChild) { public void bindLocalIndexInfo(final LocalIndexInfo item, boolean isLastChild) {
OsmandApplication context = fragment.getMyActivity().getMyApplication(); OsmandApplication context = fragment.getMyActivity().getMyApplication();
final OsmandSettings.CommonPreference<Boolean> shouldUpdatePreference = final OsmandSettings.CommonPreference<Boolean> shouldUpdatePreference =
@ -448,7 +512,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
extends AsyncTask<Void, LocalIndexInfo, List<LocalIndexInfo>> extends AsyncTask<Void, LocalIndexInfo, List<LocalIndexInfo>>
implements AbstractLoadLocalIndexTask { implements AbstractLoadLocalIndexTask {
private List<LocalIndexInfo> result; //private List<LocalIndexInfo> result;
private LocalIndexesAdapter adapter; private LocalIndexesAdapter adapter;
private LiveUpdatesFragment fragment; private LiveUpdatesFragment fragment;
private LocalIndexHelper helper; private LocalIndexHelper helper;
@ -484,7 +548,7 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment {
@Override @Override
protected void onPostExecute(List<LocalIndexInfo> result) { protected void onPostExecute(List<LocalIndexInfo> result) {
this.result = result; //this.result = result;
adapter.sort(); adapter.sort();
} }
} }

View file

@ -4,6 +4,7 @@ import android.app.Activity;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
@ -15,7 +16,9 @@ import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings; import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.base.BaseOsmAndDialogFragment; import net.osmand.plus.base.BaseOsmAndDialogFragment;
@ -25,40 +28,104 @@ import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
import net.osmand.plus.liveupdates.CountrySelectionFragment.OnFragmentInteractionListener; import net.osmand.plus.liveupdates.CountrySelectionFragment.OnFragmentInteractionListener;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppCallbacks, OnFragmentInteractionListener { public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppCallbacks, OnFragmentInteractionListener {
public static final String TAG = "SubscriptionFragment"; public static final String TAG = "SubscriptionFragment";
private static final String EDIT_MODE_ID = "edit_mode_id";
private static final String USER_NAME_ID = "user_name_id";
private static final String EMAIL_ID = "email_id";
private static final String COUNTRY_ITEM_ID = "country_id";
private static final String HIDE_USER_NAME_ID = "hide_user_name_id";
private InAppHelper inAppHelper; private InAppHelper inAppHelper;
private OsmandSettings settings; private OsmandSettings settings;
private ProgressDialog dlg; private ProgressDialog dlg;
private boolean editMode;
private String userName; private String prevEmail;
private String email;
private CountryItem selectedCountryItem; private CountryItem selectedCountryItem;
private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment(); private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment();
public void setEditMode(boolean editMode) {
this.editMode = editMode;
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(EDIT_MODE_ID, editMode);
View view = getView();
if (view != null) {
EditText userNameEdit = (EditText) view.findViewById(R.id.userNameEdit);
outState.putString(USER_NAME_ID, userNameEdit.getText().toString());
EditText emailEdit = (EditText) view.findViewById(R.id.emailEdit);
outState.putString(EMAIL_ID, emailEdit.getText().toString());
CheckBox hideUserNameCheckbox = (CheckBox) view.findViewById(R.id.hideUserNameCheckbox);
outState.putBoolean(HIDE_USER_NAME_ID, hideUserNameCheckbox.isChecked());
if (selectedCountryItem != null) {
outState.putSerializable(COUNTRY_ITEM_ID, selectedCountryItem);
}
}
super.onSaveInstanceState(outState);
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
settings = getMyApplication().getSettings(); if (savedInstanceState != null) {
inAppHelper = new InAppHelper(getMyApplication(), this); editMode = savedInstanceState.getBoolean(EDIT_MODE_ID);
Activity activity = getActivity();
if (activity instanceof OsmLiveActivity) {
((OsmLiveActivity) activity).setInAppHelper(inAppHelper);
} }
inAppHelper.start(false); settings = getMyApplication().getSettings();
prevEmail = settings.BILLING_USER_EMAIL.get();
if (!editMode) {
inAppHelper = new InAppHelper(getMyApplication(), this);
Activity activity = getActivity();
if (activity instanceof OsmLiveActivity) {
((OsmLiveActivity) activity).setInAppHelper(inAppHelper);
}
inAppHelper.start(false);
}
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
String userName = settings.BILLING_USER_NAME.get();
String email = settings.BILLING_USER_EMAIL.get();
String countryDownloadName = settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get();
boolean hideUserName = settings.BILLING_HIDE_USER_NAME.get();
if (savedInstanceState != null) {
userName = savedInstanceState.getString(USER_NAME_ID);
email = savedInstanceState.getString(EMAIL_ID);
hideUserName = savedInstanceState.getBoolean(HIDE_USER_NAME_ID);
Object obj = savedInstanceState.getSerializable(COUNTRY_ITEM_ID);
if (obj instanceof CountryItem) {
selectedCountryItem = (CountryItem) obj;
countryDownloadName = selectedCountryItem.getDownloadName();
} else {
countryDownloadName = "";
}
}
View view = inflater.inflate(R.layout.subscription_fragment, container, false); View view = inflater.inflate(R.layout.subscription_fragment, container, false);
ImageButton closeButton = (ImageButton) view.findViewById(R.id.closeButton); ImageButton closeButton = (ImageButton) view.findViewById(R.id.closeButton);
if (editMode) {
closeButton.setImageDrawable(getMyApplication().getIconsCache().getIcon(R.drawable.ic_action_mode_back));
} else {
closeButton.setImageDrawable(getMyApplication().getIconsCache().getIcon(R.drawable.ic_action_remove_dark));
}
closeButton.setOnClickListener(new View.OnClickListener() { closeButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -66,20 +133,24 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
} }
}); });
userName = settings.BILLING_USER_NAME.get(); TextView title = (TextView) view.findViewById(R.id.titleTextView);
if (editMode) {
title.setText(getString(R.string.osm_live_subscription_settings));
} else {
title.setText(getString(R.string.osm_live_subscription));
}
final EditText userNameEdit = (EditText) view.findViewById(R.id.userNameEdit); final EditText userNameEdit = (EditText) view.findViewById(R.id.userNameEdit);
if (!Algorithms.isEmpty(userName)) { if (!Algorithms.isEmpty(userName)) {
userNameEdit.setText(userName); userNameEdit.setText(userName);
} }
email = settings.BILLING_USER_EMAIL.get();
final EditText emailEdit = (EditText) view.findViewById(R.id.emailEdit); final EditText emailEdit = (EditText) view.findViewById(R.id.emailEdit);
if (!Algorithms.isEmpty(email)) { if (!Algorithms.isEmpty(email)) {
emailEdit.setText(email); emailEdit.setText(email);
} }
countrySelectionFragment.initCountries(getMyApplication()); countrySelectionFragment.initCountries(getMyApplication());
String countryDownloadName = settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get();
if (Algorithms.isEmpty(countryDownloadName)) { if (Algorithms.isEmpty(countryDownloadName)) {
selectedCountryItem = countrySelectionFragment.getCountryItems().get(0); selectedCountryItem = countrySelectionFragment.getCountryItems().get(0);
} else { } else {
@ -103,40 +174,100 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
} }
}); });
updatePrice(view);
final Button subscribeButton = (Button) view.findViewById(R.id.subscribeButton);
final CheckBox hideUserNameCheckbox = (CheckBox) view.findViewById(R.id.hideUserNameCheckbox); final CheckBox hideUserNameCheckbox = (CheckBox) view.findViewById(R.id.hideUserNameCheckbox);
boolean hideUserName = settings.BILLING_HIDE_USER_NAME.get();
hideUserNameCheckbox.setChecked(hideUserName); hideUserNameCheckbox.setChecked(hideUserName);
subscribeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (inAppHelper != null) {
userName = userNameEdit.getText().toString().trim();
email = emailEdit.getText().toString().trim();
String countryName = selectedCountryItem != null ? selectedCountryItem.getLocalName() : "";
String countryDownloadName = selectedCountryItem != null ? selectedCountryItem.getDownloadName() : "";
if (Algorithms.isEmpty(email) || !AndroidUtils.isValidEmail(email)) { View editModeBottomView = view.findViewById(R.id.editModeBottomView);
getMyApplication().showToastMessage("Please enter valid E-mail address"); View purchaseCard = view.findViewById(R.id.purchaseCard);
return; if (editMode) {
editModeBottomView.setVisibility(View.VISIBLE);
purchaseCard.setVisibility(View.GONE);
Button saveChangesButton = (Button) view.findViewById(R.id.saveChangesButton);
saveChangesButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (applySettings(userNameEdit.getText().toString().trim(),
emailEdit.getText().toString().trim(), hideUserNameCheckbox.isChecked())) {
final Map<String, String> parameters = new HashMap<>();
parameters.put("visibleName", settings.BILLING_HIDE_USER_NAME.get() ? "" : settings.BILLING_USER_NAME.get());
parameters.put("preferredCountry", settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get());
parameters.put("email", settings.BILLING_USER_EMAIL.get());
parameters.put("cemail", prevEmail);
parameters.put("userid", settings.BILLING_USER_ID.get());
showProgress();
AndroidNetworkUtils.sendRequestAsync(getMyApplication(),
"http://download.osmand.net/subscription/update.php",
parameters, "Sending data...", new AndroidNetworkUtils.OnRequestResultListener() {
@Override
public void onResult(String result) {
dismissProgress();
OsmandApplication app = getMyApplication();
if (result != null) {
try {
JSONObject obj = new JSONObject(result);
if (!obj.has("error")) {
String userId = obj.getString("userid");
app.getSettings().BILLING_USER_ID.set(userId);
String email = obj.getString("email");
app.getSettings().BILLING_USER_EMAIL.set(email);
String visibleName = obj.getString("visibleName");
if (!Algorithms.isEmpty(visibleName)) {
app.getSettings().BILLING_USER_NAME.set(visibleName);
app.getSettings().BILLING_HIDE_USER_NAME.set(false);
} else {
app.getSettings().BILLING_HIDE_USER_NAME.set(true);
}
String preferredCountry = obj.getString("preferredCountry");
app.getSettings().BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(preferredCountry);
Fragment parent = getParentFragment();
if (parent != null && parent instanceof LiveUpdatesFragment) {
((LiveUpdatesFragment) parent).updateHeader();
}
dismiss();
} else {
app.showToastMessage("Error: " + obj.getString("error"));
}
} catch (JSONException e) {
app.showToastMessage(getString(R.string.shared_string_io_error));
}
} else {
app.showToastMessage(getString(R.string.shared_string_io_error));
}
}
});
} }
if (Algorithms.isEmpty(userName) && !hideUserNameCheckbox.isChecked()) {
getMyApplication().showToastMessage("Please enter Public Name");
return;
}
settings.BILLING_USER_NAME.set(userName);
settings.BILLING_USER_EMAIL.set(email);
settings.BILLING_USER_COUNTRY.set(countryName);
settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(countryDownloadName);
settings.BILLING_HIDE_USER_NAME.set(hideUserNameCheckbox.isChecked());
inAppHelper.purchaseLiveUpdates(getActivity(), email, userName, countryDownloadName);
} }
} });
});
} else {
editModeBottomView.setVisibility(View.GONE);
purchaseCard.setVisibility(View.VISIBLE);
updatePrice(view);
final Button subscribeButton = (Button) view.findViewById(R.id.subscribeButton);
subscribeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (inAppHelper != null) {
if (applySettings(userNameEdit.getText().toString().trim(),
emailEdit.getText().toString().trim(), hideUserNameCheckbox.isChecked())) {
inAppHelper.purchaseLiveUpdates(getActivity(),
settings.BILLING_USER_EMAIL.get(),
settings.BILLING_USER_NAME.get(),
settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get(),
settings.BILLING_HIDE_USER_NAME.get());
}
}
}
});
}
setThemedDrawable((ImageView) view.findViewById(R.id.userNameIcon), R.drawable.ic_person); setThemedDrawable((ImageView) view.findViewById(R.id.userNameIcon), R.drawable.ic_person);
setThemedDrawable((ImageView) view.findViewById(R.id.emailIcon), R.drawable.ic_action_message); setThemedDrawable((ImageView) view.findViewById(R.id.emailIcon), R.drawable.ic_action_message);
@ -150,7 +281,9 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
inAppHelper.stop(); if (inAppHelper != null) {
inAppHelper.stop();
}
if (dlg != null && dlg.isShowing()) { if (dlg != null && dlg.isShowing()) {
dlg.hide(); dlg.hide();
} }
@ -160,6 +293,28 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In
} }
} }
private boolean applySettings(String userName, String email, boolean hideUserName) {
String countryName = selectedCountryItem != null ? selectedCountryItem.getLocalName() : "";
String countryDownloadName = selectedCountryItem != null ? selectedCountryItem.getDownloadName() : "";
if (Algorithms.isEmpty(email) || !AndroidUtils.isValidEmail(email)) {
getMyApplication().showToastMessage(getString(R.string.osm_live_enter_email));
return false;
}
if (Algorithms.isEmpty(userName) && !hideUserName) {
getMyApplication().showToastMessage(getString(R.string.osm_live_enter_user_name));
return false;
}
settings.BILLING_USER_NAME.set(userName);
settings.BILLING_USER_EMAIL.set(email);
settings.BILLING_USER_COUNTRY.set(countryName);
settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(countryDownloadName);
settings.BILLING_HIDE_USER_NAME.set(hideUserName);
return true;
}
@Override @Override
public void onError(String error) { public void onError(String error) {
} }