commit b1e9596b5eae87fe7b3a5a0ee8d03233f7de822a
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Jul 9 23:48:38 2020 +0100

    Display the 'Privacy Policy' dialog (only if locale is set to ZH - chinese requirement)

diff --git a/src/main/java/org/distorted/dialogs/RubikDialogAbout.java b/src/main/java/org/distorted/dialogs/RubikDialogAbout.java
index 559aefd3..5fa2a8ea 100644
--- a/src/main/java/org/distorted/dialogs/RubikDialogAbout.java
+++ b/src/main/java/org/distorted/dialogs/RubikDialogAbout.java
@@ -79,20 +79,10 @@ public class RubikDialogAbout extends AppCompatDialogFragment
     final View view = inflater.inflate(R.layout.dialog_about, null);
     TextView text = view.findViewById(R.id.about_version);
     String appName = getString(R.string.app_name);
-    String appVers;
 
-    try
-      {
-      PackageInfo pInfo = act.getPackageManager().getPackageInfo( act.getPackageName(), 0);
-      appVers = pInfo.versionName;
-      }
-    catch (PackageManager.NameNotFoundException e)
-      {
-      appVers = "1.2.2";
-      }
 
     text.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-    text.setText(getString(R.string.ap_placeholder,appName, appVers));
+    text.setText(getString(R.string.ap_placeholder,appName, getAppVers(act)));
 
     MovementMethod mm = LinkMovementMethod.getInstance();
     TextView text1 = view.findViewById(R.id.about_section1);
@@ -105,6 +95,18 @@ public class RubikDialogAbout extends AppCompatDialogFragment
     text3.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
     text3.setMovementMethod(mm);
 
+    TextView text4 = view.findViewById(R.id.about_section4);
+
+    if( RubikActivity.localeIsChinese() )
+      {
+      text4.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+      text4.setMovementMethod(mm);
+      }
+    else
+      {
+      text4.setVisibility(View.GONE);
+      }
+
     builder.setView(view);
 
     Dialog dialog = builder.create();
@@ -128,4 +130,19 @@ public class RubikDialogAbout extends AppCompatDialogFragment
 
     return dialog;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private String getAppVers(FragmentActivity act)
+    {
+    try
+      {
+      PackageInfo pInfo = act.getPackageManager().getPackageInfo( act.getPackageName(), 0);
+      return pInfo.versionName;
+      }
+    catch (PackageManager.NameNotFoundException e)
+      {
+      return "unknown";
+      }
+    }
   }
diff --git a/src/main/java/org/distorted/dialogs/RubikDialogPrivacy.java b/src/main/java/org/distorted/dialogs/RubikDialogPrivacy.java
new file mode 100644
index 00000000..f6e03409
--- /dev/null
+++ b/src/main/java/org/distorted/dialogs/RubikDialogPrivacy.java
@@ -0,0 +1,110 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is free software: you can redistribute it and/or modify                            //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Magic Cube is distributed in the hope that it will be useful,                                 //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.dialogs;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.method.LinkMovementMethod;
+import android.text.method.MovementMethod;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatDialogFragment;
+import androidx.fragment.app.FragmentActivity;
+
+import org.distorted.main.R;
+import org.distorted.main.RubikActivity;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class RubikDialogPrivacy extends AppCompatDialogFragment
+  {
+  @NonNull
+  @Override
+  public Dialog onCreateDialog(Bundle savedInstanceState)
+    {
+    final RubikActivity ract = (RubikActivity)getContext();
+
+    FragmentActivity act = getActivity();
+    LayoutInflater inflater = act.getLayoutInflater();
+    AlertDialog.Builder builder = new AlertDialog.Builder(act);
+
+    DisplayMetrics displaymetrics = new DisplayMetrics();
+    act.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
+    final float titleSize= displaymetrics.widthPixels * RubikActivity.MENU_BIG_TEXT_SIZE;
+    final float butSize  = displaymetrics.widthPixels * RubikActivity.MENU_MEDIUM_TEXT_SIZE;
+
+    TextView tv = (TextView) inflater.inflate(R.layout.dialog_title, null);
+    tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleSize);
+    tv.setText(R.string.privacy_policy);
+    builder.setCustomTitle(tv);
+
+    MovementMethod mm = LinkMovementMethod.getInstance();
+    final View view = inflater.inflate(R.layout.dialog_privacy, null);
+    TextView text = view.findViewById(R.id.privacy_string);
+    text.setMovementMethod(mm);
+
+    builder.setCancelable(true);
+
+    builder.setPositiveButton( R.string.accept, new DialogInterface.OnClickListener()
+      {
+      @Override
+      public void onClick(DialogInterface dialog, int which)
+        {
+        if( ract!=null ) ract.acceptPrivacy();
+        }
+      });
+
+    builder.setNegativeButton( R.string.decline, new DialogInterface.OnClickListener()
+      {
+      @Override
+      public void onClick(DialogInterface dialog, int which)
+        {
+        if( ract!=null ) ract.declinePrivacy();
+        }
+      });
+
+    builder.setView(view);
+
+    final Dialog dialog = builder.create();
+    dialog.setCanceledOnTouchOutside(false);
+
+    dialog.setOnShowListener(new DialogInterface.OnShowListener()
+      {
+      @Override
+      public void onShow(DialogInterface dialog)
+        {
+        Button btnPositive = ((AlertDialog)dialog).getButton(Dialog.BUTTON_POSITIVE);
+        btnPositive.setTextSize(TypedValue.COMPLEX_UNIT_PX, butSize);
+        Button btnNegative = ((AlertDialog)dialog).getButton(Dialog.BUTTON_NEGATIVE);
+        btnNegative.setTextSize(TypedValue.COMPLEX_UNIT_PX, butSize);
+        }
+      });
+
+    return dialog;
+    }
+  }
diff --git a/src/main/java/org/distorted/main/RubikActivity.java b/src/main/java/org/distorted/main/RubikActivity.java
index fa98e3de..73e522af 100644
--- a/src/main/java/org/distorted/main/RubikActivity.java
+++ b/src/main/java/org/distorted/main/RubikActivity.java
@@ -20,7 +20,9 @@
 package org.distorted.main;
 
 import android.content.SharedPreferences;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.LocaleList;
 import android.preference.PreferenceManager;
 import androidx.appcompat.app.AppCompatActivity;
 
@@ -29,6 +31,7 @@ import android.util.DisplayMetrics;
 import com.google.firebase.analytics.FirebaseAnalytics;
 
 import org.distorted.dialogs.RubikDialogError;
+import org.distorted.dialogs.RubikDialogPrivacy;
 import org.distorted.effects.BaseEffect;
 import org.distorted.library.main.DistortedLibrary;
 
@@ -39,6 +42,8 @@ import org.distorted.objects.RubikObjectList;
 import org.distorted.states.RubikState;
 import org.distorted.states.RubikStatePlay;
 
+import java.util.Locale;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class RubikActivity extends AppCompatActivity
@@ -62,6 +67,7 @@ public class RubikActivity extends AppCompatActivity
     private boolean mJustStarted;
     private FirebaseAnalytics mFirebaseAnalytics;
     private static int mScreenWidth, mScreenHeight;
+    private boolean mPolicyAccepted, mIsChinese;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -79,6 +85,8 @@ public class RubikActivity extends AppCompatActivity
       getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
       mScreenWidth =displaymetrics.widthPixels;
       mScreenHeight=displaymetrics.heightPixels;
+
+      mIsChinese = localeIsChinese();
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -141,6 +149,8 @@ public class RubikActivity extends AppCompatActivity
         play.setObjectAndSize(this,obj,s);
         view.getPreRender().changeObject(obj,s);
         }
+
+      if( mIsChinese && !mPolicyAccepted ) PrivacyPolicy();
       }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -159,6 +169,8 @@ public class RubikActivity extends AppCompatActivity
       SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
       SharedPreferences.Editor editor = preferences.edit();
 
+      editor.putBoolean("policyAccepted", mPolicyAccepted);
+
       for (int i=0; i<BaseEffect.Type.LENGTH; i++)
         {
         BaseEffect.Type.getType(i).savePreferences(editor);
@@ -182,6 +194,8 @@ public class RubikActivity extends AppCompatActivity
       {
       SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
 
+      mPolicyAccepted = preferences.getBoolean("policyAccepted", false);
+
       for (int i=0; i< BaseEffect.Type.LENGTH; i++)
         {
         BaseEffect.Type.getType(i).restorePreferences(preferences);
@@ -198,6 +212,14 @@ public class RubikActivity extends AppCompatActivity
       view.getPreRender().restorePreferences(preferences);
       }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void PrivacyPolicy()
+      {
+      RubikDialogPrivacy priDiag = new RubikDialogPrivacy();
+      priDiag.show(getSupportFragmentManager(), null);
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     void OpenGLError(String message)
@@ -309,21 +331,17 @@ public class RubikActivity extends AppCompatActivity
       {
       if( mScreenHeight<1000 )
         {
-        //android.util.Log.e("view", "returning small, mScrH="+mScreenHeight);
         return 0;
         }
       if( mScreenHeight<1600 )
         {
-        //android.util.Log.e("view", "returning medium, mScrH="+mScreenHeight);
         return 1;
         }
       if( mScreenHeight<1900 )
         {
-        //android.util.Log.e("view", "returning bug, mScrH="+mScreenHeight);
         return 2;
         }
 
-      //android.util.Log.e("view", "returning huge, mScrH="+mScreenHeight);
       return 3;
       }
 
@@ -342,6 +360,38 @@ public class RubikActivity extends AppCompatActivity
         }
       }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void acceptPrivacy()
+      {
+      mPolicyAccepted = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void declinePrivacy()
+      {
+      finish();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public static boolean localeIsChinese()
+      {
+      String language;
+
+      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+        {
+        language= LocaleList.getDefault().get(0).getLanguage();
+        }
+      else
+        {
+        language= Locale.getDefault().getLanguage();
+        }
+
+      return language.equals("zh");
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public boolean isVertical()
diff --git a/src/main/res/layout/dialog_about.xml b/src/main/res/layout/dialog_about.xml
index 40ad9096..1eaad15f 100644
--- a/src/main/res/layout/dialog_about.xml
+++ b/src/main/res/layout/dialog_about.xml
@@ -56,6 +56,17 @@
             android:layout_marginRight="10dp"
             android:text="@string/credits3"/>
 
+        <TextView
+            android:id="@+id/about_section4"
+            android:layout_width="match_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="0.20"
+            android:layout_marginBottom="10dp"
+            android:layout_marginTop="10dp"
+            android:layout_marginLeft="10dp"
+            android:layout_marginRight="10dp"
+            android:text="@string/credits4"/>
+
     </LinearLayout>
 
 </ScrollView>
\ No newline at end of file
diff --git a/src/main/res/layout/dialog_privacy.xml b/src/main/res/layout/dialog_privacy.xml
new file mode 100644
index 00000000..3c9b3d05
--- /dev/null
+++ b/src/main/res/layout/dialog_privacy.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center|fill_horizontal"
+    android:layout_marginLeft="10dp"
+    android:layout_marginRight="10dp"
+    android:layout_marginTop="0dp"
+    android:background="@color/grey"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/privacy_string"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:textSize="24sp"
+        android:text="@string/privacy_policy_text"
+        android:layout_marginTop="10dp"
+        android:layout_marginLeft="10dp"
+        android:layout_marginRight="10dp"
+        android:layout_marginBottom="10dp"/>
+</LinearLayout>
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index e933dd94..f4ce9dcb 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -34,10 +34,15 @@
     <string name="new_name_try_again">您选择的名称,%s,已被使用。请重试：</string>
     <string name="downloading">正在下载……</string>
     <string name="submitting">正在提交……</string>
+    <string name="privacy_policy">隐私政策</string>
+    <string name="privacy_policy_text">Please see and accept our <a href="https://distorted.org/redmine/projects/magic-cube/wiki/%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96">隐私政策</a></string>
+    <string name="accept">Accept</string>
+    <string name="decline">Decline</string>
     <string name="credits1">此应用程式原始码开发使用Distorted图型库。根据<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">通用公共许可版本2</a>或者任何更新版本（根据您的选择）进行许可。</string>
     <string name="credits2">Pretty Patterns by Werner Randelshofer. 請看 <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
-    <string name="credits3">下载代码，浏览教程，学习如何添加自己的图形效果，学习如何编写自己的专案，创造美丽图案，实现自己的求解器，或者报告错误：\n\n<a href="https://distorted.org/redmine/projects/magic-cube/wiki">Distorted.org</a>
+    <string name="credits3">下载代码，浏览教程，学习如何添加自己的图形效果，学习如何编写自己的专案，创造美丽图案，实现自己的求解器，或者报告错误：<a href="https://distorted.org/redmine/projects/magic-cube/wiki">Distorted.org</a>
   </string>
+    <string name="credits4">Please see our <a href="https://distorted.org/redmine/projects/magic-cube/wiki/%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96">隐私政策</a></string>
 
     <string name="solver_generic_error1">此对象和尺寸的求解器尚未实现！</string>
 
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 9617691a..247c9d8a 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -36,9 +36,14 @@
     <string name="new_name_try_again">The name you have chosen, %s, is already taken. Try again:</string>
     <string name="downloading">Downloading…</string>
     <string name="submitting">Submitting…</string>
+    <string name="privacy_policy">Privacy Policy</string>
+    <string name="privacy_policy_text">Please see and accept our <a href="https://distorted.org/redmine/projects/magic-cube/wiki/Privacy_policy">Privacy Policy</a></string>
+    <string name="accept">Accept</string>
+    <string name="decline">Decline</string>
     <string name="credits1">Open Source app developed using the Distorted graphics library. Licensed under <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPL version 2</a> or - at your option - any later version.</string>
     <string name="credits2">Pretty Patterns by Walter Randelshofer. See <a href="http://www.randelshofer.ch">http://www.randelshofer.ch</a></string>
     <string name="credits3">Download code, take a look at tutorials, learn how to add your own graphics effect, learn how to code your own object, contribute a Pretty Pattern, implement your own solver, or report a bug: \n\n<a href="https://distorted.org/redmine/projects/magic-cube/wiki">Distorted.org</a></string>
+    <string name="credits4">Please see our <a href="https://distorted.org/redmine/projects/magic-cube/wiki/Privacy_policy">Privacy Policy</a></string>
 
     <string name="solver_generic_error1">Solver for this object and size not implemented yet!</string>
 
