diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java index 50712e423..f91014d68 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java @@ -7,6 +7,8 @@ import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; + +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.graphics.ColorUtils; import androidx.core.graphics.drawable.DrawableCompat; import androidx.core.widget.TextViewCompat; @@ -19,6 +21,7 @@ import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; @@ -49,7 +52,12 @@ public class LoyaltyCardViewActivity extends AppCompatActivity ImportURIHelper importURIHelper; Settings settings; + String cardIdString; + BarcodeFormat format; + boolean backgroundNeedsDarkIcons; + boolean barcodeIsFullscreen = false; + ViewGroup.LayoutParams barcodeImageState; private void extractIntentFields(Intent intent) { @@ -104,6 +112,21 @@ public class LoyaltyCardViewActivity extends AppCompatActivity collapsingToolbarLayout = findViewById(R.id.collapsingToolbarLayout); rotationEnabled = true; + + // Allow making barcode fullscreen on tap + barcodeImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(barcodeIsFullscreen) + { + setFullscreen(false); + } + else + { + setFullscreen(true); + } + } + }); } @Override @@ -122,6 +145,15 @@ public class LoyaltyCardViewActivity extends AppCompatActivity Log.i(TAG, "To view card: " + loyaltyCardId); + if(barcodeIsFullscreen) + { + // Completely reset state + // + // This prevents the barcode from taking up the entire screen + // on resume and thus being stretched out of proportion. + recreate(); + } + // The brightness value is on a scale from [0, ..., 1], where // '1' is the brightest. We attempt to maximize the brightness // to help barcode readers scan the barcode. @@ -143,8 +175,8 @@ public class LoyaltyCardViewActivity extends AppCompatActivity } String formatString = loyaltyCard.barcodeType; - final BarcodeFormat format = !formatString.isEmpty() ? BarcodeFormat.valueOf(formatString) : null; - final String cardIdString = loyaltyCard.cardId; + format = !formatString.isEmpty() ? BarcodeFormat.valueOf(formatString) : null; + cardIdString = loyaltyCard.cardId; cardIdFieldView.setText(loyaltyCard.cardId); TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(cardIdFieldView, @@ -244,6 +276,18 @@ public class LoyaltyCardViewActivity extends AppCompatActivity } } + @Override + public void onBackPressed() { + if (barcodeIsFullscreen) + { + setFullscreen(false); + return; + } + + super.onBackPressed(); + return; + } + @Override public boolean onCreateOptionsMenu(Menu menu) { @@ -321,4 +365,72 @@ public class LoyaltyCardViewActivity extends AppCompatActivity setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); } } + + /** + * When enabled, hides the status bar and moves the barcode to the top of the screen. + * + * The purpose of this function is to make sure the barcode can be scanned from the phone + * by machines which offer no space to insert the complete device. + */ + private void setFullscreen(boolean enable) + { + ActionBar actionBar = getSupportActionBar(); + if(enable && !barcodeIsFullscreen) + { + // Save previous barcodeImage state + barcodeImageState = barcodeImage.getLayoutParams(); + + // Hide actionbar + if(actionBar != null) + { + actionBar.hide(); + } + + // Hide collapsingToolbar + collapsingToolbarLayout.setVisibility(View.GONE); + + // Set Android to fullscreen mode + getWindow().getDecorView().setSystemUiVisibility( + getWindow().getDecorView().getSystemUiVisibility() + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_FULLSCREEN + ); + + // Make barcode take all space + barcodeImage.setLayoutParams(new ConstraintLayout.LayoutParams( + ConstraintLayout.LayoutParams.MATCH_PARENT, + ConstraintLayout.LayoutParams.MATCH_PARENT + )); + + // Move barcode to top + barcodeImage.setScaleType(ImageView.ScaleType.FIT_START); + + // Set current state + barcodeIsFullscreen = true; + } + else if(!enable && barcodeIsFullscreen) + { + // Show actionbar + if(actionBar != null) + { + actionBar.show(); + } + + // Show collapsingToolbar + collapsingToolbarLayout.setVisibility(View.VISIBLE); + + // Unset fullscreen mode + getWindow().getDecorView().setSystemUiVisibility( + getWindow().getDecorView().getSystemUiVisibility() + & ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + & ~View.SYSTEM_UI_FLAG_FULLSCREEN + ); + + // Turn barcode back to normal + barcodeImage.setLayoutParams(barcodeImageState); + + // Set current state + barcodeIsFullscreen = false; + } + } } diff --git a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java index e139de488..4c45e3cca 100644 --- a/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java +++ b/app/src/test/java/protect/card_locker/LoyaltyCardViewActivityTest.java @@ -1,6 +1,7 @@ package protect.card_locker; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; @@ -22,6 +23,7 @@ import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; +import android.widget.ImageView; import android.widget.TextView; import androidx.core.widget.TextViewCompat; import com.google.zxing.BarcodeFormat; @@ -35,7 +37,6 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowActivity; import org.robolectric.shadows.ShadowLog; @@ -686,6 +687,69 @@ public class LoyaltyCardViewActivityTest } } + @Test + public void checkBarcodeFullscreenWorkflow() + { + ActivityController activityController = createActivityWithLoyaltyCard(false); + + Activity activity = (Activity)activityController.get(); + DBHelper db = new DBHelper(activity); + db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE); + + activityController.start(); + activityController.visible(); + activityController.resume(); + + assertEquals(false, activity.isFinishing()); + + ImageView barcodeImage = activity.findViewById(R.id.barcode); + View collapsingToolbarLayout = activity.findViewById(R.id.collapsingToolbarLayout); + + // Android should not be in fullscreen mode + int uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility(); + assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions); + assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions); + + // Elements should be visible + assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility()); + + // Click barcode to toggle fullscreen + barcodeImage.performClick(); + + // Android should be in fullscreen mode + uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility(); + assertEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions); + assertEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions); + + // Elements should not be visible + assertEquals(View.GONE, collapsingToolbarLayout.getVisibility()); + + // Clicking barcode again should deactivate fullscreen mode + barcodeImage.performClick(); + uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility(); + assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions); + assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions); + assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility()); + + // Another click back to fullscreen + barcodeImage.performClick(); + uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility(); + assertEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions); + assertEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions); + assertEquals(View.GONE, collapsingToolbarLayout.getVisibility()); + + // In full screen mode, back button should disable fullscreen + activity.onBackPressed(); + uiOptions = activity.getWindow().getDecorView().getSystemUiVisibility(); + assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY, uiOptions); + assertNotEquals(uiOptions | View.SYSTEM_UI_FLAG_FULLSCREEN, uiOptions); + assertEquals(View.VISIBLE, collapsingToolbarLayout.getVisibility()); + + // Pressing back when not in full screen should finish activity + activity.onBackPressed(); + assertEquals(true, activity.isFinishing()); + } + @Test public void importCard() {