Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
local.properties
app/release/*
app/build/*
app/backup_build/*
.gradle/*
build/*
.idea/*
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,48 @@ Wireless debugging can sometimes be tricky. Here are some common issues and how
```bash
adb uninstall atorch.statspuzzles
```

## Generating and Testing a Release App Bundle

Here's how to generate a signed Android App Bundle (AAB) for release and test it on a physical device.

### 1. Generate a Signed App Bundle

To create a release-ready App Bundle, you'll need a signing key. If you don't have one, you can generate one using `keytool`. Make sure you have configured your `app/build.gradle` to use your keystore for release builds.

Once your signing configuration is set up, run the following command:

```bash
./gradlew bundleRelease
```

This will generate a signed AAB file at `app/build/outputs/bundle/release/app-release.aab`.

### 2. Test the App Bundle on Your Device

You can't install an AAB file directly. You need to use `bundletool` to generate a set of APKs and install them on your device.

1. **Download `bundletool`:**
Download the `bundletool` jar from the [Android Developer website](https://developer.android.com/studio/command-line/bundletool).

2. **Connect your device:**
Make sure your device is connected via Wi-Fi debugging as described in the "Running the App on a Physical Device (Wireless Debugging)" section.

3. **Generate APKs from the App Bundle:**
Use `bundletool` to build the APKs. You will need to provide your keystore information.

```bash
java -jar /path/to/bundletool.jar build-apks --bundle=app/build/outputs/bundle/release/app-release.aab --output=app.apks \
--ks=/path/to/your/keystore.jks \
--ks-pass=pass:YOUR_KEYSTORE_PASSWORD \
--ks-key-alias=YOUR_KEY_ALIAS \
--key-pass=pass:YOUR_KEY_PASSWORD
```
**Important:** Replace the placeholder values (`/path/to/bundletool.jar`, `/path/to/your/keystore.jks`, `YOUR_KEYSTORE_PASSWORD`, `YOUR_KEY_ALIAS`, `YOUR_KEY_PASSWORD`) with your actual information.

4. **Install the APKs on your device:**
```bash
java -jar /path/to/bundletool.jar install-apks --apks=app.apks
```

`bundletool` will install the correct APKs for your device's architecture. You can now test the release version of your app.
25 changes: 24 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
apply plugin: 'com.android.application'

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}

android {
compileSdkVersion 35

signingConfigs {
release {
if (localPropertiesFile.exists()) {
keyAlias localProperties['signing.key.alias']
keyPassword localProperties['signing.key.password']
storeFile file(localProperties['signing.store.file'])
storePassword localProperties['signing.store.password']
}
}
}

defaultConfig {
applicationId "atorch.statspuzzles"
minSdkVersion 19
targetSdkVersion 34
targetSdkVersion 35
versionCode 32
versionName "4.0"

Expand All @@ -17,6 +36,10 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
// Only apply the signing config if the local.properties file exists (it will not on github)
if (project.rootProject.file('local.properties').exists()) {
signingConfig signingConfigs.release
}
}
}
namespace 'atorch.statspuzzles'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class PuzzleSelectionTest {
@Test
public void mainActivityLoads() {
Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
Espresso.onView(ViewMatchers.withText(context.getString(R.string.app_name)))
Espresso.onView(ViewMatchers.withText(context.getString(R.string.button_intro)))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
}

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<activity
android:name=".PuzzleSelection"
android:label="@string/app_name"
android:theme="@style/AppTheme.ActionBar"
android:theme="@style/AppTheme"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/atorch/statspuzzles/PuzzleSelection.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

public class PuzzleSelection extends AppCompatActivity {

Expand All @@ -29,6 +30,9 @@ public void startPuzzle(View view) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_puzzle_selection);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
updateCounter();
AppRater.app_launched(this);
}
Expand Down
53 changes: 22 additions & 31 deletions app/src/main/java/atorch/statspuzzles/SolvePuzzle.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.ShareActionProvider;
import androidx.core.view.MenuItemCompat;


import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
Expand All @@ -48,7 +47,7 @@

public class SolvePuzzle extends AppCompatActivity {
// Following example at https://developer.android.com/training/sharing/shareaction.html
private ShareActionProvider mShareActionProvider;


public static final String PUZZLE_INDEX = "atorch.statspuzzles.PUZZLE_INDEX";
public static final String LEVEL = "atorch.statspuzzles.LEVEL";
Expand All @@ -65,6 +64,10 @@ public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_solve_puzzle);

androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);

ActionBar actionBar = getSupportActionBar();
actionBar.setHomeButtonEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
Expand All @@ -79,13 +82,7 @@ public void onCreate(Bundle savedInstanceState) {
puzzlePager = findViewById(R.id.pager);
puzzlePager.setAdapter(new AppSectionsPagerAdapter(this, level, res));

puzzlePager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int puzzleIndex) {
super.onPageSelected(puzzleIndex);
prepareSharePuzzle(res.getPuzzle(level, puzzleIndex));
}
});


puzzlePager.setCurrentItem(indexFirstUnsolvedPuzzle());
}
Expand All @@ -101,35 +98,29 @@ private int indexFirstUnsolvedPuzzle() {
return n - 1; // Everything solved, return last index
}

private void prepareSharePuzzle(String puzzleStatement) {
String text = puzzleStatement + "\n\n" + getString(R.string.app_link);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, text);
shareIntent.setType("text/plain");
if (mShareActionProvider != null) {
// Should be called whenever new fragment is displayed
mShareActionProvider.setShareIntent(shareIntent);
}
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.solve_puzzle, menu);
MenuItem item = menu.findItem(R.id.menu_item_share);

// Following http://stackoverflow.com/questions/19118051/unable-to-cast-action-provider-to-share-action-provider
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
if (mShareActionProvider == null) {
// Following http://stackoverflow.com/questions/19358510/why-menuitemcompat-getactionprovider-returns-null
mShareActionProvider = new ShareActionProvider(this);
MenuItemCompat.setActionProvider(item, mShareActionProvider);
}
prepareSharePuzzle(res.getPuzzle(level, puzzlePager.getCurrentItem()));
return true; // Return true to display menu

}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_item_share) {
String puzzleStatement = res.getPuzzle(level, puzzlePager.getCurrentItem());
String text = puzzleStatement + "\n\n" + getString(R.string.app_link);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, text);
shareIntent.setType("text/plain");
startActivity(Intent.createChooser(shareIntent, null));
return true;
}
return super.onOptionsItemSelected(item);
}

private static class Res {

// Level -1 is the introduction / how to.
Expand Down
26 changes: 24 additions & 2 deletions app/src/main/res/layout/activity_puzzle_selection.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,29 @@
android:layout_width="match_parent"
android:layout_height="match_parent">

<ScrollView
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />

</com.google.android.material.appbar.AppBarLayout>

<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">

Expand All @@ -30,6 +48,7 @@
android:paddingTop="@dimen/activity_vertical_margin_half" >

<Button
style="@style/GreyButton"
android:layout_width="0dp"
android:id="@+id/button_intro"
android:layout_height="wrap_content"
Expand Down Expand Up @@ -57,6 +76,7 @@
android:paddingTop="@dimen/activity_vertical_margin_half" >

<Button
style="@style/GreyButton"
android:layout_width="0dp"
android:id="@+id/button_0"
android:layout_height="wrap_content"
Expand Down Expand Up @@ -84,6 +104,7 @@
android:paddingTop="@dimen/activity_vertical_margin_half" >

<Button
style="@style/GreyButton"
android:id="@+id/button_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
Expand Down Expand Up @@ -111,6 +132,7 @@
android:paddingTop="@dimen/activity_vertical_margin_half" >

<Button
style="@style/GreyButton"
android:id="@+id/button_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
Expand Down
31 changes: 28 additions & 3 deletions app/src/main/res/layout/activity_solve_puzzle.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

</androidx.viewpager2.widget.ViewPager2>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />

</com.google.android.material.appbar.AppBarLayout>

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/appBarLayout"
app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
7 changes: 3 additions & 4 deletions app/src/main/res/layout/fragment_solve_puzzle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
android:gravity="start"
android:textAlignment="viewStart" />
<Button android:id="@+id/submit_answer"
style="@style/GreyButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_submit_answer" />
Expand All @@ -90,9 +91,7 @@
</LinearLayout>

<Button android:gravity="center_horizontal"
style="?android:attr/borderlessButtonStyle"
android:layout_marginTop="@dimen/activity_vertical_margin_double"
android:visibility="gone"
style="@style/BlackTextButton"
android:id="@+id/button_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand All @@ -101,7 +100,7 @@
android:text="@string/button_hint" />

<Button android:gravity="center_horizontal"
style="?android:attr/borderlessButtonStyle"
style="@style/BlackTextButton"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:id="@+id/button_gemini_hint"
android:layout_width="match_parent"
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-ar/strings.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">ألغاز الاحتمالات</string>
<string name="new_in_this_update">هذا الإصدار 3.9، تم إطلاقه في سبتمبر 2022 — يحتوي الآن على أكثر من تسعين لغزاً، بدون إعلانات، وقد تمت ترجمته إلى ثلاث لغات الإسبانية والألمانية والعربية. استمتع!
<string name="new_in_this_update">هذا هو الإصدار 4.0، الذي تم إصداره في أكتوبر 2025 - الآن مع أكثر من تسعين لغزًا، وصفر إعلانات، وترجمات باللغات الإسبانية والألمانية والعربية. استمتع!
\n\nبعض الألغاز في هذا التطبيق ستكون صعبة إذا لم تكن قد درست الاحتمالات. هل تحتاج إلى مراجعة؟ ألق نظرة على\u00A0<a href="https://chance.dartmouth.edu/teaching_aids/books_articles/probabilityccc_book/book-5-17-03.pdf">كتاب دارتموث</a> وهذه\u00A0<a href="https://ocw.mit.edu/courses/mathematics/18-440-probability-and-random-variables-spring-2014/lecture-notes/">ملاحظات MIT</a>. يمكنك أيضاً قراءة بعض مسائل الاحتمالات على\u00A0<a href="https://math.stackexchange.com/questions/tagged/probability">math.stackexchange.com</a>. إذا كنت تفضل مشاهدة المحاضرات على يوتيوب، جرب\u00A0<a href="https://www.youtube.com/playlist?list=PLUl4u3cNGP60hI9ATjSFgLZpbNJ7myAg6">هذه</a> أو\u00A0<a href="https://www.youtube.com/playlist?list=PLUl4u3cNGP60A3XMwZ5sep719_nh95qOe">هذه</a>.
\n\nهذا التطبيق مليء بألغاز الرياضيات، ويستخدم mXparser الإصدار 4.2.0 من Mariusz Gromada لترجمة التعبيرات الرياضية إلى أرقام: سيفهم .2، 0.2، 20٪، أو 1/5. يفهم المحلل أيضاً المضروب والمعاملات الثنائية: جرب كتابة 5!/(3!*2!) أو\u00A0<a href="https://en.wikipedia.org/wiki/Binomial_coefficient">C(5,3)</a> بحرف C كبير لـ "5 اختيار 3." يمكنك أيضاً كتابة e بحرف صغير لأساس اللوغاريتم الطبيعي. قم بزيارة\u00A0<a href="http://mathparser.org">mathparser.org</a> لمزيد من المعلومات.
\n\nإذا كنت ترغب في المساهمة في التطبيق (أو إلقاء نظرة على الحلول)، ألق نظرة على\u00A0<a href="https://github.com/atorch/probability_puzzles">مستودع github</a>!</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<resources>
<string name="app_name">Wahrscheinlichkeitsrätsel</string>
<string name="new_in_this_update">Dies ist Version 4.0, veröffentlicht im März 2025\u00A0– jetzt mit mehr als 90 Rätseln (und null Werbung). Viel Spaß!\n\nEinige der Rätsel in dieser App sind schwierig, wenn du Wahrscheinlichkeitsrechnung nicht gelernt hast. Brauchst du eine Auffrischung? Dann könnten dir die <a href="https://www.youtube.com/results?search_query=daniel+jung+stochastik">YouTube-Videos von Daniel Jung</a> helfen.\n\nDie App nutzt Mariusz Gromadas mXparser in Version 4.2.0, damit du in den Antworten auch Rechnungen schreiben kannst. Der Parser versteht Zahlen wie .2, 0.2, 20\% oder auch 1/5. Fakultät und Binomialkoeffizienten gehen auch: Schreib 5!/(3!*2!), oder C(5, 3) mit einem großen C für „3 aus 5“. Du kannst auch den Kleinbuchstaben e für die Basis des natürlichen Logarithmus schreiben. Besuch <a href="https://mathparser.org">mathparser.org</a> für weitere Informationen.\n\nWenn du bei der App mitmachen willst (oder die Lösungen spicken), schau beim\u00A0<a href="https://github.com/atorch/probability_puzzles">GitHub-Repo</a> der App vorbei!</string>
<string name="new_in_this_update">Dies ist Version 4.0, veröffentlicht im Oktober 2025\u00A0– jetzt mit mehr als 90 Rätseln (und null Werbung). Viel Spaß!\n\nEinige der Rätsel in dieser App sind schwierig, wenn du Wahrscheinlichkeitsrechnung nicht gelernt hast. Brauchst du eine Auffrischung? Dann könnten dir die <a href="https://www.youtube.com/results?search_query=daniel+jung+stochastik">YouTube-Videos von Daniel Jung</a> helfen.\n\nDie App nutzt Mariusz Gromadas mXparser in Version 4.2.0, damit du in den Antworten auch Rechnungen schreiben kannst. Der Parser versteht Zahlen wie .2, 0.2, 20\% oder auch 1/5. Fakultät und Binomialkoeffizienten gehen auch: Schreib 5!/(3!*2!), oder C(5, 3) mit einem großen C für „3 aus 5“. Du kannst auch den Kleinbuchstaben e für die Basis des natürlichen Logarithmus schreiben. Besuch <a href="https://mathparser.org">mathparser.org</a> für weitere Informationen.\n\nWenn du bei der App mitmachen willst (oder die Lösungen spicken), schau beim\u00A0<a href="https://github.com/atorch/probability_puzzles">GitHub-Repo</a> der App vorbei!</string>

<string name="app_link">Fordere dich mit Wahrscheinlichkeitsrätseln heraus\u00A0– installier die App auf https://play.google.com/store/apps/details?id=atorch.statspuzzles</string>

Expand Down
Loading
Loading