diff --git a/OsmAnd/no_translate.xml b/OsmAnd/no_translate.xml index 74fcf0776c..a10a00c824 100644 --- a/OsmAnd/no_translate.xml +++ b/OsmAnd/no_translate.xml @@ -30,7 +30,15 @@ OSM Live subscription Subscribe €1,49 - + We need it to provide you information about contributions + Public Name + Don\'t show my name in reports + Support region + Month cost + Monthly payment + Active + Inactive + 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. In case you love OsmAnd and OSM and want to support it, this is a perfect way to do it. diff --git a/OsmAnd/res/layout/live_updates_header.xml b/OsmAnd/res/layout/live_updates_header.xml index 7032c37748..673ef3052a 100644 --- a/OsmAnd/res/layout/live_updates_header.xml +++ b/OsmAnd/res/layout/live_updates_header.xml @@ -99,13 +99,15 @@ app:typeface="@string/font_roboto_regular"/> - - - - - - - - - - - - - \ No newline at end of file diff --git a/OsmAnd/res/layout/subscription_fragment.xml b/OsmAnd/res/layout/subscription_fragment.xml index 8f21cff1db..a2f7195c49 100644 --- a/OsmAnd/res/layout/subscription_fragment.xml +++ b/OsmAnd/res/layout/subscription_fragment.xml @@ -24,7 +24,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp" - android:text="Subscription form" + android:text="@string/osm_live_subscription" android:textColor="@color/color_white" android:textSize="@dimen/default_list_text_size_large" android:textStyle="bold" @@ -63,7 +63,7 @@ android:layout_gravity="center_vertical" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" - android:hint="E-mail address" + android:hint="@string/shared_string_email_address" android:inputType="textEmailAddress"/> @@ -74,7 +74,7 @@ android:layout_gravity="center_vertical" android:layout_marginLeft="72dp" android:layout_marginRight="16dp" - android:text="We need it to provide you information about contributions" + android:text="@string/osm_live_email_desc" android:textColor="?android:attr/textColorSecondary"/> @@ -103,20 +103,21 @@ android:layout_gravity="center_vertical" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" - android:hint="Public Name" + android:hint="@string/osm_live_user_public_name" android:inputType="text"/> + android:hint="@string/osm_live_support_region"/> @@ -174,22 +175,21 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="Month cost" + android:text="@string/osm_live_month_cost" android:textColor="?android:attr/textColorPrimary" android:textSize="@dimen/default_list_text_size_large" - android:textStyle="bold" - app:typeface="@string/font_roboto_regular"/> + android:textStyle="bold"/> + android:textStyle="bold"/> @@ -198,10 +198,9 @@ android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" - android:text="Monthly payment" + android:text="@string/osm_live_month_cost_desc" android:textColor="?android:attr/textColorSecondary" - android:textSize="@dimen/default_desc_text_size" - app:typeface="@string/font_roboto_regular"/> + android:textSize="@dimen/default_desc_text_size"/> diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 4f6707ac68..b7d8d2f042 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -9,6 +9,7 @@ 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 --> + E-mail address Hide underground objects Data is not available Remove diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index b03f79e30e..ae0035daa5 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -815,6 +815,8 @@ public class OsmandSettings { public final OsmandPreference BILLING_USER_NAME = new StringPreference("billing_user_name", "").makeGlobal(); public final OsmandPreference BILLING_USER_EMAIL = new StringPreference("billing_user_email", "").makeGlobal(); public final OsmandPreference BILLING_USER_COUNTRY = new StringPreference("billing_user_country", "").makeGlobal(); + public final OsmandPreference BILLING_USER_COUNTRY_DOWNLOAD_NAME = new StringPreference("billing_user_country_download_name", "").makeGlobal(); + public final OsmandPreference BILLING_HIDE_USER_NAME = new BooleanPreference("billing_hide_user_name", false).makeGlobal(); public final OsmandPreference BILLING_PURCHASE_TOKEN_SENT = new BooleanPreference("billing_purchase_token_sent", false).makeGlobal(); // this value string is synchronized with settings_pref.xml preference name diff --git a/OsmAnd/src/net/osmand/plus/inapp/InAppHelper.java b/OsmAnd/src/net/osmand/plus/inapp/InAppHelper.java index 3d916a5a73..9237a22a1c 100644 --- a/OsmAnd/src/net/osmand/plus/inapp/InAppHelper.java +++ b/OsmAnd/src/net/osmand/plus/inapp/InAppHelper.java @@ -19,16 +19,20 @@ import net.osmand.util.Algorithms; import org.json.JSONException; 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.HashMap; import java.util.List; +import java.util.Map; public class InAppHelper { // Debug tag, for logging @@ -58,10 +62,13 @@ public class InAppHelper { public interface InAppCallbacks { void onError(String error); + void onGetItems(); + void onItemPurchased(String sku); void showProgress(); + void dismissProgress(); } @@ -80,8 +87,8 @@ public class InAppHelper { public void start(final boolean stopAfterResult) { this.stopAfterResult = stopAfterResult; - /* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY - * (that you got from the Google Play developer console). This is not your + /* base64EncodedPublicKey should be YOUR APPLICATION'S PUBLIC KEY + * (that you got from the Google Play developer console). This is not your * developer public key, it's the *app-specific* public key. * * Instead of just storing the entire literal string here embedded in the @@ -159,15 +166,14 @@ public class InAppHelper { Log.d(TAG, "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 * the developer payload to see if it's correct! See * verifyDeveloperPayload(). */ // Do we have the live updates? Purchase liveUpdatesPurchase = inventory.getPurchase(SKU_LIVE_UPDATES); - mSubscribedToLiveUpdates = (liveUpdatesPurchase != null && - verifyDeveloperPayload(liveUpdatesPurchase)); + mSubscribedToLiveUpdates = (liveUpdatesPurchase != null); Log.d(TAG, "User " + (mSubscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE") + " live updates purchased."); @@ -193,7 +199,7 @@ public class InAppHelper { }; public void purchaseLiveUpdates(final Activity activity, final String email, final String userName, - final String country) { + final String countryDownloadName) { if (!mHelper.subscriptionsSupported()) { complain("Subscriptions not supported on your device yet. Sorry!"); if (callbacks != null) { @@ -218,12 +224,17 @@ public class InAppHelper { userId = ctx.getSettings().BILLING_USER_ID.get(); if (Algorithms.isEmpty(userId)) { try { - return sendRequest("http://download.osmand.net/subscription/register?email=" + URLEncoder.encode(email, "UTF-8") - + "&visibleName=" + URLEncoder.encode(userName, "UTF-8") - + "&preferredCountry=" + URLEncoder.encode(country, "UTF-8") - + (Algorithms.isEmpty(userId) ? "&status=new" : ""), - "POST", "Requesting userId..."); + Map parameters = new HashMap<>(); + parameters.put("visibleName", userName); + parameters.put("preferredCountry", countryDownloadName); + parameters.put("email", email); + 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 { @@ -236,6 +247,7 @@ public class InAppHelper { if (Algorithms.isEmpty(userId)) { Log.d(TAG, "Response=" + response); if (response == null) { + complain("Cannot retrieve userId from server."); if (callbacks != null) { callbacks.dismissProgress(); callbacks.onError("Cannot retrieve userId from server."); @@ -252,10 +264,12 @@ public class InAppHelper { 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("JSON parsing error: " - + (e.getMessage() == null ? "unknown" : e.getMessage())); + callbacks.onError(message); } if (stopAfterResult) { stop(); @@ -304,36 +318,6 @@ public class InAppHelper { } } - /** Verifies the developer payload of a purchase. */ - private boolean verifyDeveloperPayload(Purchase p) { - String payload = p.getDeveloperPayload(); - - /* - * TODO: verify that the developer payload of the purchase is correct. It will be - * the same one that you sent when initiating the purchase. - * - * WARNING: Locally generating a random string when starting a purchase and - * verifying it here might seem like a good approach, but this will fail in the - * case where the user purchases an item on one device and then uses your app on - * a different device, because on the other device you will not have access to the - * random string you originally generated. - * - * So a good developer payload has these characteristics: - * - * 1. If two different users purchase an item, the payload is different between them, - * so that one user's purchase can't be replayed to another user. - * - * 2. The payload must be such that you can verify it even when the app wasn't the - * one who initiated the purchase flow (so that items purchased by the user on - * one device work on other devices owned by the user). - * - * Using your own server to store and verify developer payloads across app - * installations is recommended. - */ - - return true; - } - // Callback for when a purchase is finished private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { @@ -353,17 +337,6 @@ public class InAppHelper { } return; } - if (!verifyDeveloperPayload(purchase)) { - complain("Error purchasing. Authenticity verification failed."); - if (callbacks != null) { - callbacks.dismissProgress(); - callbacks.onError("Error purchasing. Authenticity verification failed."); - } - if (stopAfterResult) { - stop(); - } - return; - } Log.d(TAG, "Purchase successful."); @@ -398,11 +371,14 @@ public class InAppHelper { String userId = ctx.getSettings().BILLING_USER_ID.get(); String email = ctx.getSettings().BILLING_USER_EMAIL.get(); try { - sendRequestAsync("http://download.osmand.net/subscription/purchased?userid=" + URLEncoder.encode(userId, "UTF-8") - + "&sku=" + URLEncoder.encode(SKU_LIVE_UPDATES, "UTF-8") - + "&purchaseToken=" + URLEncoder.encode(token, "UTF-8") - + "&email=" + URLEncoder.encode(email, "UTF-8"), - "POST", "Sending purchase info...", new OnRequestResultListener() { + Map parameters = new HashMap<>(); + parameters.put("userId", userId); + parameters.put("sku", SKU_LIVE_UPDATES); + parameters.put("purchaseToken", token); + parameters.put("email", email); + + sendRequestAsync("http://download.osmand.net/subscription/purchased.php", + parameters, "Sending purchase info...", new OnRequestResultListener() { @Override public void onResult(String result) { if (result != null && result.trim().toLowerCase().equals("ok")) { @@ -411,6 +387,7 @@ public class InAppHelper { } }); } catch (Exception e) { + Log.e(TAG, "sendToken Error", e); } } @@ -423,33 +400,63 @@ public class InAppHelper { ctx.showToastMessage(message); } - private String sendRequest(String url, String requestMethod, String userOperation) { + private String sendRequest(String url, Map parameters, String userOperation) { Log.d(TAG, "Sending request " + url); //$NON-NLS-1$ + HttpURLConnection connection = null; try { - HttpURLConnection connection = NetworkUtils.getHttpURLConnection(url); + connection = NetworkUtils.getHttpURLConnection(url); + connection.setRequestProperty("Accept-Charset", "UTF-8"); + connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx)); connection.setConnectTimeout(15000); - connection.setRequestMethod(requestMethod); - connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx)); //$NON-NLS-1$ - StringBuilder responseBody = new StringBuilder(); - connection.connect(); + + if (parameters != null && parameters.size() > 0) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry 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(); //$NON-NLS-1$//$NON-NLS-2$ + + " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage(); Log.e(TAG, msg); showToast(msg); } else { - Log.d(TAG, "Response : " + connection.getResponseMessage()); //$NON-NLS-1$ + 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); //$NON-NLS-1$ + 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"); //$NON-NLS-1$ + responseBody.append("\n"); } else { f = false; } @@ -459,37 +466,42 @@ public class InAppHelper { in.close(); i.close(); } catch (Exception e) { + Log.e(TAG, "sendRequest", e); } } return responseBody.toString(); } - connection.disconnect(); + } 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); //$NON-NLS-1$ + 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); //$NON-NLS-1$ + 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 String requestMethod, final String userOperation, final OnRequestResultListener listener) { + private void sendRequestAsync(final String url, final Map parameters, final String userOperation, final OnRequestResultListener listener) { new AsyncTask() { @Override protected String doInBackground(Void... params) { try { - return sendRequest(url, requestMethod, userOperation); + return sendRequest(url, parameters, userOperation); } catch (Exception e) { return null; } diff --git a/OsmAnd/src/net/osmand/plus/liveupdates/CountrySelectionFragment.java b/OsmAnd/src/net/osmand/plus/liveupdates/CountrySelectionFragment.java new file mode 100644 index 0000000000..88c7cc7c69 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/liveupdates/CountrySelectionFragment.java @@ -0,0 +1,229 @@ +package net.osmand.plus.liveupdates; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.annotation.DrawableRes; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.TextView; + +import net.osmand.map.WorldRegion; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.base.BaseOsmAndDialogFragment; +import net.osmand.util.Algorithms; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class CountrySelectionFragment extends BaseOsmAndDialogFragment { + + private List countryItems = new ArrayList<>(); + private OnFragmentInteractionListener mListener; + + public List getCountryItems() { + return countryItems; + } + + public CountryItem getCountryItem(String downloadName) { + if (!Algorithms.isEmpty(downloadName)) { + for (CountryItem item : countryItems) { + if (downloadName.equals(item.downloadName)) { + return item; + } + } + } + return null; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + if (countryItems.size() == 0) { + initCountries(getMyApplication()); + } + + View view = inflater.inflate(R.layout.fragment_search_list, container, false); + ListView listView = (ListView) view.findViewById(android.R.id.list); + final ArrayAdapter adapter = new ListAdapter(getListItemIcon()); + if (countryItems.size() > 0) { + adapter.addAll(countryItems); + } + listView.setAdapter(adapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + mListener.onSearchResult(adapter.getItem(position)); + dismiss(); + } + }); + final EditText searchEditText = (EditText) view.findViewById(R.id.searchEditText); + searchEditText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + adapter.getFilter().filter(s); + } + }); + ImageButton clearButton = (ImageButton) view.findViewById(R.id.clearButton); + setThemedDrawable(clearButton, R.drawable.ic_action_remove_dark); + clearButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }); + return view; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof OnFragmentInteractionListener) { + mListener = (OnFragmentInteractionListener) context; + } else if (getParentFragment() instanceof OnFragmentInteractionListener) { + mListener = (OnFragmentInteractionListener) getParentFragment(); + } else { + throw new RuntimeException(context.toString() + + " must implement OnFragmentInteractionListener"); + } + } + + @DrawableRes + protected int getListItemIcon() { + return R.drawable.ic_map; + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + public interface OnFragmentInteractionListener { + void onSearchResult(CountryItem name); + } + + + public void initCountries(OsmandApplication app) { + final WorldRegion root = app.getRegions().getWorldRegion(); + ArrayList groups = new ArrayList<>(); + groups.add(root); + processGroup(root, groups); + Collections.sort(groups, new Comparator() { + @Override + public int compare(WorldRegion lhs, WorldRegion rhs) { + if (lhs == root) { + return -1; + } + if (rhs == root) { + return 1; + } + return getHumanReadableName(lhs).compareTo(getHumanReadableName(rhs)); + } + }); + for (WorldRegion group : groups) { + String name = getHumanReadableName(group); + countryItems.add(new CountryItem(name, group.getRegionDownloadName())); + } + } + + private static void processGroup(WorldRegion group, + List nameList) { + if (group.isRegionMapDownload()) { + nameList.add(group); + } + + if (group.getSubregions() != null) { + for (WorldRegion g : group.getSubregions()) { + processGroup(g, nameList); + } + } + } + + private static String getHumanReadableName(WorldRegion group) { + String name; + if (group.getLevel() > 2 || (group.getLevel() == 2 + && group.getSuperregion().getRegionId().equals(WorldRegion.RUSSIA_REGION_ID))) { + WorldRegion parent = group.getSuperregion(); + WorldRegion parentsParent = group.getSuperregion().getSuperregion(); + if (group.getLevel() == 3) { + if (parentsParent.getRegionId().equals(WorldRegion.RUSSIA_REGION_ID)) { + name = parentsParent.getLocaleName() + " " + group.getLocaleName(); + } else if (!parent.getRegionId().equals(WorldRegion.UNITED_KINGDOM_REGION_ID)) { + name = parent.getLocaleName() + " " + group.getLocaleName(); + } else { + name = group.getLocaleName(); + } + } else { + name = parent.getLocaleName() + " " + group.getLocaleName(); + } + } else { + name = group.getLocaleName(); + } + if (name == null) { + name = ""; + } + return name; + } + + public static class CountryItem { + private String localName; + private String downloadName; + + public CountryItem(String localName, String downloadName) { + this.localName = localName; + this.downloadName = downloadName; + } + + public String getLocalName() { + return localName; + } + + public String getDownloadName() { + return downloadName; + } + + @Override + public String toString() { + return localName; + } + } + + private class ListAdapter extends ArrayAdapter { + private final Drawable drawableLeft; + + public ListAdapter(@DrawableRes int drawableLeftId) { + super(getMyActivity(), android.R.layout.simple_list_item_1); + this.drawableLeft = drawableLeftId == -1 ? null : getContentIcon(drawableLeftId); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + CountryItem item = getItem(position); + TextView view = (TextView) super.getView(position, convertView, parent); + view.setText(item.localName); + view.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, null, null, null); + view.setCompoundDrawablePadding(getResources().getDimensionPixelSize(R.dimen.list_content_padding)); + return view; + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/liveupdates/LiveUpdatesFragment.java b/OsmAnd/src/net/osmand/plus/liveupdates/LiveUpdatesFragment.java index aa1222747a..81f561ad28 100644 --- a/OsmAnd/src/net/osmand/plus/liveupdates/LiveUpdatesFragment.java +++ b/OsmAnd/src/net/osmand/plus/liveupdates/LiveUpdatesFragment.java @@ -22,6 +22,7 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import net.osmand.map.WorldRegion; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; @@ -106,6 +107,29 @@ public class LiveUpdatesFragment extends BaseOsmAndFragment { } }); if (InAppHelper.isSubscribedToLiveUpdates()) { + TextView statusTextView = (TextView) subscriptionHeader.findViewById(R.id.statusTextView); + 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()) { + statusTextView.setText(getString(R.string.osm_live_active)); + } else { + statusTextView.setText(getString(R.string.osm_live_not_active)); + } + + OsmandSettings settings = getMyApplication().getSettings(); + + String countryName = settings.BILLING_USER_COUNTRY.get(); + if (Algorithms.isEmpty(countryName)) { + WorldRegion world = getMyApplication().getRegions().getWorldRegion(); + countryName = world.getLocaleName(); + } + regionNameTextView.setText(countryName); + + emailTextView.setText(settings.BILLING_USER_EMAIL.get()); + userNameTextView.setText(settings.BILLING_USER_NAME.get()); + subscriptionBanner.setVisibility(View.GONE); subscriptionInfo.setVisibility(View.VISIBLE); } else { diff --git a/OsmAnd/src/net/osmand/plus/liveupdates/ReportsFragment.java b/OsmAnd/src/net/osmand/plus/liveupdates/ReportsFragment.java index 389e6fc5a1..380f3a4fdc 100644 --- a/OsmAnd/src/net/osmand/plus/liveupdates/ReportsFragment.java +++ b/OsmAnd/src/net/osmand/plus/liveupdates/ReportsFragment.java @@ -22,23 +22,19 @@ import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import net.osmand.PlatformUtil; -import net.osmand.map.WorldRegion; import net.osmand.osm.io.NetworkUtils; import net.osmand.plus.R; import net.osmand.plus.base.BaseOsmAndFragment; +import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem; import org.apache.commons.logging.Log; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; import java.util.Locale; -public class ReportsFragment extends BaseOsmAndFragment implements SearchSelectionFragment.OnFragmentInteractionListener { +public class ReportsFragment extends BaseOsmAndFragment implements CountrySelectionFragment.OnFragmentInteractionListener { public static final String TITLE = "Report"; public static final String TOTAL_CHANGES_BY_MONTH_URL_PATTERN = "http://download.osmand.net/" + "reports/query_report.php?report=total_changes_by_month&month=%s®ion=%s"; @@ -50,11 +46,9 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti private Spinner montReportsSpinner; private MonthsForReportsAdapter monthsForReportsAdapter; - CountrySearchSelectionFragment searchSelectionFragment = new CountrySearchSelectionFragment(); + private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment(); private TextView countryNameTextView; - - HashMap queryRegionNames = new HashMap<>(); - ArrayList regionNames = new ArrayList<>(); + private CountryItem selectedCountryItem; private ImageView numberOfContributorsIcon; private ImageView numberOfEditsIcon; @@ -69,7 +63,6 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - initCountries(); View view = inflater.inflate(R.layout.fragment_reports, container, false); montReportsSpinner = (Spinner) view.findViewById(R.id.montReportsSpinner); monthsForReportsAdapter = new MonthsForReportsAdapter(getActivity()); @@ -79,15 +72,15 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti regionReportsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - SearchSelectionFragment countrySearchSelectionFragment = - searchSelectionFragment; - countrySearchSelectionFragment - .show(getChildFragmentManager(), "CountriesSearchSelectionFragment"); + countrySelectionFragment.show(getChildFragmentManager(), "CountriesSearchSelectionFragment"); } }); + countrySelectionFragment.initCountries(getMyApplication()); + selectedCountryItem = countrySelectionFragment.getCountryItems().get(0); + countryNameTextView = (TextView) regionReportsButton.findViewById(android.R.id.text1); - countryNameTextView.setText(regionNames.get(0)); + countryNameTextView.setText(selectedCountryItem.getLocalName()); setThemedDrawable(view, R.id.calendarImageView, R.drawable.ic_action_data); setThemedDrawable(view, R.id.regionIconImageView, R.drawable.ic_world_globe_dark); @@ -127,7 +120,7 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti public void requestAndUpdateUi() { int monthItemPosition = montReportsSpinner.getSelectedItemPosition(); String monthUrlString = monthsForReportsAdapter.getQueryString(monthItemPosition); - String countryUrlString = queryRegionNames.get(countryNameTextView.getText().toString()); + String countryUrlString = selectedCountryItem.getDownloadName(); tryUpdateData(monthUrlString, countryUrlString); } @@ -171,79 +164,12 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti } @Override - public void onSearchResult(String name) { - countryNameTextView.setText(name); + public void onSearchResult(CountryItem item) { + selectedCountryItem = item; + countryNameTextView.setText(item.getLocalName()); requestAndUpdateUi(); } - private void initCountries() { - final WorldRegion root = getMyApplication().getRegions().getWorldRegion(); - ArrayList groups = new ArrayList<>(); - groups.add(root); - processGroup(root, groups, getActivity()); - Collections.sort(groups, new Comparator() { - @Override - public int compare(WorldRegion lhs, WorldRegion rhs) { - if (lhs == root) { - return -1; - } - if (rhs == root) { - return 1; - } - return getHumanReadableName(lhs).compareTo(getHumanReadableName(rhs)); - } - }); - for (WorldRegion group : groups) { - String name = getHumanReadableName(group); - regionNames.add(name); - queryRegionNames.put(name, group == root ? "" : group.getRegionDownloadName()); - } - } - - private static String getHumanReadableName(WorldRegion group) { - String name; - if (group.getLevel() > 2 || (group.getLevel() == 2 - && group.getSuperregion().getRegionId().equals(WorldRegion.RUSSIA_REGION_ID))) { - WorldRegion parent = group.getSuperregion(); - WorldRegion parentsParent = group.getSuperregion().getSuperregion(); - if (group.getLevel() == 3) { - if (parentsParent.getRegionId().equals(WorldRegion.RUSSIA_REGION_ID)) { - name = parentsParent.getLocaleName() + " " + group.getLocaleName(); - } else if (!parent.getRegionId().equals(WorldRegion.UNITED_KINGDOM_REGION_ID)) { - name = parent.getLocaleName() + " " + group.getLocaleName(); - } else { - name = group.getLocaleName(); - } - } else { - name = parent.getLocaleName() + " " + group.getLocaleName(); - } - } else { - name = group.getLocaleName(); - } - if (name == null) { - name = ""; - } - return name; - } - - public String getQueryString(int position) { - return queryRegionNames.get(position); - } - - private static void processGroup(WorldRegion group, - List nameList, - Context context) { - if (group.isRegionMapDownload()) { - nameList.add(group); - } - - if (group.getSubregions() != null) { - for (WorldRegion g : group.getSubregions()) { - processGroup(g, nameList, context); - } - } - } - private static class MonthsForReportsAdapter extends ArrayAdapter { private static final SimpleDateFormat queryFormat = new SimpleDateFormat("yyyy-MM", Locale.US); @SuppressLint("SimpleDateFormat") @@ -325,18 +251,6 @@ public class ReportsFragment extends BaseOsmAndFragment implements SearchSelecti } } - public static class CountrySearchSelectionFragment extends SearchSelectionFragment { - @Override - protected ArrayList getList() { - return ((ReportsFragment) getParentFragment()).regionNames; - } - - @Override - protected int getListItemIcon() { - return R.drawable.ic_map; - } - } - private void enableProgress() { numberOfContributorsIcon.setImageDrawable(getPaintedContentIcon(R.drawable.ic_group, inactiveColor)); numberOfEditsIcon.setImageDrawable(getPaintedContentIcon(R.drawable.ic_map, inactiveColor)); diff --git a/OsmAnd/src/net/osmand/plus/liveupdates/SearchSelectionFragment.java b/OsmAnd/src/net/osmand/plus/liveupdates/SearchSelectionFragment.java deleted file mode 100644 index b46dd10022..0000000000 --- a/OsmAnd/src/net/osmand/plus/liveupdates/SearchSelectionFragment.java +++ /dev/null @@ -1,126 +0,0 @@ -package net.osmand.plus.liveupdates; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.annotation.DrawableRes; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; - -import net.osmand.plus.R; -import net.osmand.plus.base.BaseOsmAndDialogFragment; - -import java.util.ArrayList; - -public abstract class SearchSelectionFragment extends BaseOsmAndDialogFragment { - private OnFragmentInteractionListener mListener; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_search_list, container, false); - ListView listView = (ListView) view.findViewById(android.R.id.list); - final ArrayAdapter adapter = new ListAdapter(getActivity(), getListItemIcon()); - if (getArray() != null) { - adapter.addAll(getArray()); - } else if (getList() != null) { - adapter.addAll(getList()); - } else { - throw new RuntimeException("Either getArray() or getList() must return non null value."); - } - listView.setAdapter(adapter); - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - mListener.onSearchResult(adapter.getItem(position)); - dismiss(); - } - }); - final EditText searchEditText = (EditText) view.findViewById(R.id.searchEditText); - searchEditText.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void afterTextChanged(Editable s) { - adapter.getFilter().filter(s); - } - }); - ImageButton clearButton = (ImageButton) view.findViewById(R.id.clearButton); - setThemedDrawable(clearButton, R.drawable.ic_action_remove_dark); - clearButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - dismiss(); - } - }); - return view; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnFragmentInteractionListener) { - mListener = (OnFragmentInteractionListener) context; - } else if (getParentFragment() instanceof OnFragmentInteractionListener) { - mListener = (OnFragmentInteractionListener) getParentFragment(); - } else { - throw new RuntimeException(context.toString() - + " must implement OnFragmentInteractionListener"); - } - } - - protected String[] getArray() { - return null; - } - - protected ArrayList getList() { - return null; - } - - @DrawableRes - protected int getListItemIcon() { - return -1; - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - public interface OnFragmentInteractionListener { - void onSearchResult(String name); - } - - private class ListAdapter extends ArrayAdapter { - private final Drawable drawableLeft; - - public ListAdapter(Context context, @DrawableRes int drawableLeftId) { - super(getMyActivity(), android.R.layout.simple_list_item_1); - this.drawableLeft = drawableLeftId == -1 ? null : getContentIcon(drawableLeftId); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView view = (TextView) super.getView(position, convertView, parent); - view.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, null, null, null); - view.setCompoundDrawablePadding(getResources().getDimensionPixelSize(R.dimen.list_content_padding)); - return view; - } - } -} diff --git a/OsmAnd/src/net/osmand/plus/liveupdates/SubscriptionFragment.java b/OsmAnd/src/net/osmand/plus/liveupdates/SubscriptionFragment.java index aa05014a73..03201a876e 100644 --- a/OsmAnd/src/net/osmand/plus/liveupdates/SubscriptionFragment.java +++ b/OsmAnd/src/net/osmand/plus/liveupdates/SubscriptionFragment.java @@ -2,7 +2,6 @@ package net.osmand.plus.liveupdates; import android.app.Activity; import android.app.ProgressDialog; -import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; @@ -10,27 +9,23 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import net.osmand.AndroidUtils; -import net.osmand.map.WorldRegion; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.base.BaseOsmAndDialogFragment; import net.osmand.plus.inapp.InAppHelper; import net.osmand.plus.inapp.InAppHelper.InAppCallbacks; -import net.osmand.plus.liveupdates.SearchSelectionFragment.OnFragmentInteractionListener; +import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem; +import net.osmand.plus.liveupdates.CountrySelectionFragment.OnFragmentInteractionListener; import net.osmand.util.Algorithms; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppCallbacks, OnFragmentInteractionListener{ +public class SubscriptionFragment extends BaseOsmAndDialogFragment implements InAppCallbacks, OnFragmentInteractionListener { public static final String TAG = "SubscriptionFragment"; @@ -40,11 +35,9 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In private String userName; private String email; - private String country; + private CountryItem selectedCountryItem; - ArrayList regionNames = new ArrayList<>(); - private CountrySearchSelectionFragment searchSelectionFragment - = new CountrySearchSelectionFragment(); + private CountrySelectionFragment countrySelectionFragment = new CountrySelectionFragment(); @Override public void onCreate(Bundle savedInstanceState) { @@ -73,8 +66,6 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In } }); - initCountries(); - userName = settings.BILLING_USER_NAME.get(); final EditText userNameEdit = (EditText) view.findViewById(R.id.userNameEdit); if (!Algorithms.isEmpty(userName)) { @@ -87,52 +78,62 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In emailEdit.setText(email); } - country = settings.BILLING_USER_COUNTRY.get(); + countrySelectionFragment.initCountries(getMyApplication()); + String countryDownloadName = settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.get(); + if (Algorithms.isEmpty(countryDownloadName)) { + selectedCountryItem = countrySelectionFragment.getCountryItems().get(0); + } else { + selectedCountryItem = countrySelectionFragment.getCountryItem(countryDownloadName); + } + final EditText selectCountryEdit = (EditText) view.findViewById(R.id.selectCountryEdit); - if (!Algorithms.isEmpty(country)) { - selectCountryEdit.setText(country); + if (selectedCountryItem != null) { + selectCountryEdit.setText(selectedCountryItem.getLocalName()); } selectCountryEdit.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { - SearchSelectionFragment countrySearchSelectionFragment = - searchSelectionFragment; - countrySearchSelectionFragment + CountrySelectionFragment countryCountrySelectionFragment = + countrySelectionFragment; + countryCountrySelectionFragment .show(getChildFragmentManager(), "CountriesSearchSelectionFragment"); } return false; } }); - updatePrice(); + updatePrice(view); - Button subscribeButton = (Button) view.findViewById(R.id.subscribeButton); + final Button subscribeButton = (Button) view.findViewById(R.id.subscribeButton); + final CheckBox hideUserNameCheckbox = (CheckBox) view.findViewById(R.id.hideUserNameCheckbox); + boolean hideUserName = settings.BILLING_HIDE_USER_NAME.get(); + 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(); - country = selectCountryEdit.getText().toString().trim(); + String countryName = selectedCountryItem != null ? selectedCountryItem.getLocalName() : ""; + String countryDownloadName = selectedCountryItem != null ? selectedCountryItem.getDownloadName() : ""; - if (Algorithms.isEmpty(userName)) { - getMyApplication().showToastMessage("Please enter visible name"); - return; - } if (Algorithms.isEmpty(email) || !AndroidUtils.isValidEmail(email)) { getMyApplication().showToastMessage("Please enter valid E-mail address"); return; } + 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(country); + settings.BILLING_USER_COUNTRY.set(countryName); + settings.BILLING_USER_COUNTRY_DOWNLOAD_NAME.set(countryDownloadName); + settings.BILLING_HIDE_USER_NAME.set(hideUserNameCheckbox.isChecked()); - final WorldRegion world = getMyApplication().getRegions().getWorldRegion(); - String countryParam = country.equals(world.getLocaleName()) ? "" : country; - - inAppHelper.purchaseLiveUpdates(getActivity(), email, userName, countryParam); + inAppHelper.purchaseLiveUpdates(getActivity(), email, userName, countryDownloadName); } } }); @@ -165,7 +166,7 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In @Override public void onGetItems() { - updatePrice(); + updatePrice(getView()); } @Override @@ -201,18 +202,21 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In } @Override - public void onSearchResult(String name) { + public void onSearchResult(CountryItem item) { + selectedCountryItem = item; View view = getView(); if (view != null) { EditText selectCountryEdit = (EditText) view.findViewById(R.id.selectCountryEdit); if (selectCountryEdit != null) { - selectCountryEdit.setText(name); + selectCountryEdit.setText(item.getLocalName()); } } } - private void updatePrice() { - View view = getView(); + private void updatePrice(View view) { + if (view == null) { + view = getView(); + } if (view != null) { TextView priceTextView = (TextView) view.findViewById(R.id.priceTextView); if (InAppHelper.getLiveUpdatesPrice() != null) { @@ -220,79 +224,4 @@ public class SubscriptionFragment extends BaseOsmAndDialogFragment implements In } } } - - private void initCountries() { - final WorldRegion root = getMyApplication().getRegions().getWorldRegion(); - ArrayList groups = new ArrayList<>(); - groups.add(root); - processGroup(root, groups, getActivity()); - Collections.sort(groups, new Comparator() { - @Override - public int compare(WorldRegion lhs, WorldRegion rhs) { - if (lhs == root) { - return -1; - } - if (rhs == root) { - return 1; - } - return getHumanReadableName(lhs).compareTo(getHumanReadableName(rhs)); - } - }); - for (WorldRegion group : groups) { - String name = getHumanReadableName(group); - regionNames.add(name); - } - } - - private static void processGroup(WorldRegion group, - List nameList, - Context context) { - if (group.isRegionMapDownload()) { - nameList.add(group); - } - - if (group.getSubregions() != null) { - for (WorldRegion g : group.getSubregions()) { - processGroup(g, nameList, context); - } - } - } - - private static String getHumanReadableName(WorldRegion group) { - String name; - if (group.getLevel() > 2 || (group.getLevel() == 2 - && group.getSuperregion().getRegionId().equals(WorldRegion.RUSSIA_REGION_ID))) { - WorldRegion parent = group.getSuperregion(); - WorldRegion parentsParent = group.getSuperregion().getSuperregion(); - if (group.getLevel() == 3) { - if (parentsParent.getRegionId().equals(WorldRegion.RUSSIA_REGION_ID)) { - name = parentsParent.getLocaleName() + " " + group.getLocaleName(); - } else if (!parent.getRegionId().equals(WorldRegion.UNITED_KINGDOM_REGION_ID)) { - name = parent.getLocaleName() + " " + group.getLocaleName(); - } else { - name = group.getLocaleName(); - } - } else { - name = parent.getLocaleName() + " " + group.getLocaleName(); - } - } else { - name = group.getLocaleName(); - } - if (name == null) { - name = ""; - } - return name; - } - - public static class CountrySearchSelectionFragment extends SearchSelectionFragment { - @Override - protected ArrayList getList() { - return ((SubscriptionFragment) getParentFragment()).regionNames; - } - - @Override - protected int getListItemIcon() { - return R.drawable.ic_map; - } - } }