Skip to content
Draft
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## XX.XX.XX
* Mitigated an issue where content sizing was handled incorrectly on API level 35 and above.

## 25.4.3
* Improved Health Check metric information.
* Improved Content display mechanics.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ public void setUp() {
@Override public int getBOMDuration() {
return 60;
}

@Override public boolean getUseCutoutArea() {
return false;
}
};

Countly.sharedInstance().setLoggingEnabled(true);
Expand Down
13 changes: 13 additions & 0 deletions sdk/src/main/java/ly/count/android/sdk/ConfigContent.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public class ConfigContent {

int zoneTimerInterval = 30;
ContentCallback globalContentCallback = null;
Boolean cutoutArea = false;

/**
* Set the interval for the automatic content update calls
Expand All @@ -30,4 +31,16 @@ public synchronized ConfigContent setGlobalContentCallback(ContentCallback callb
this.globalContentCallback = callback;
return this;
}

/**
* Enable cutout area support for content
* When enabled, SDK will use cutout area to show content
*
* @return config content to chain calls
* @apiNote This is an EXPERIMENTAL feature, and it can have breaking changes
*/
public synchronized ConfigContent useCutoutArea() {
this.cutoutArea = true;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ interface ConfigurationProvider {
int getBOMRequestAge();

int getBOMDuration();

boolean getUseCutoutArea();
}
13 changes: 1 addition & 12 deletions sdk/src/main/java/ly/count/android/sdk/DeviceInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ of this software and associated documentation files (the "Software"), to deal
import android.os.StatFs;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.File;
Expand Down Expand Up @@ -129,19 +127,10 @@ public String getResolution(@NonNull final Context context) {
return resolution;
}

/**
* Return the display metrics collected from the WindowManager in the specified context.
* @param context context to use to retrieve the current WindowManager
* @return the display metrics of the current default display
*/
@NonNull
@Override
public DisplayMetrics getDisplayMetrics(@NonNull final Context context) {
final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
return metrics;
return UtilsDevice.getDisplayMetrics(context);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,8 @@ public boolean getTrackingEnabled() {
@Override public int getBOMDuration() {
return currentVBOMDuration;
}

@Override public boolean getUseCutoutArea() {
return _cly.config_.content.cutoutArea;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ void fetchContentsInternal(@NonNull String[] categories) {
intent.putExtra(TransparentActivity.CONFIGURATION_LANDSCAPE, placementCoordinates.get(Configuration.ORIENTATION_LANDSCAPE));
intent.putExtra(TransparentActivity.CONFIGURATION_PORTRAIT, placementCoordinates.get(Configuration.ORIENTATION_PORTRAIT));
intent.putExtra(TransparentActivity.ORIENTATION, _cly.context_.getResources().getConfiguration().orientation);
intent.putExtra(TransparentActivity.USE_CUTOUT, configProvider.getUseCutoutArea());

Long id = System.currentTimeMillis();
intent.putExtra(TransparentActivity.ID_CALLBACK, id);
Expand Down Expand Up @@ -226,7 +227,6 @@ private TransparentActivityConfig extractOrientationPlacements(@NonNull JSONObje
int w = orientationPlacements.optInt("w");
int h = orientationPlacements.optInt("h");
L.d("[ModuleContent] extractOrientationPlacements, orientation: [" + orientation + "], x: [" + x + "], y: [" + y + "], w: [" + w + "], h: [" + h + "]");

TransparentActivityConfig config = new TransparentActivityConfig((int) Math.ceil(x * density), (int) Math.ceil(y * density), (int) Math.ceil(w * density), (int) Math.ceil(h * density));
config.url = content;
return config;
Expand Down
71 changes: 46 additions & 25 deletions sdk/src/main/java/ly/count/android/sdk/TransparentActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -33,6 +32,7 @@ public class TransparentActivity extends Activity {
static final String ORIENTATION = "orientation";
static final String WIDGET_INFO = "widget_info";
static final String ID_CALLBACK = "id_callback";
static final String USE_CUTOUT = "use_cutout";
int currentOrientation = 0;
long ID = -1;
TransparentActivityConfig configLandscape = null;
Expand All @@ -47,7 +47,6 @@ protected void onCreate(Bundle savedInstanceState) {

// there is a stripe at the top of the screen for contents
// we eliminate it with hiding the system ui
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
super.onCreate(savedInstanceState);
overridePendingTransition(0, 0);

Expand All @@ -72,13 +71,19 @@ protected void onCreate(Bundle savedInstanceState) {

// Configure window layout parameters
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.gravity = Gravity.TOP | Gravity.LEFT; // try out START
params.gravity = Gravity.TOP | Gravity.START; // try out START
params.x = config.x;
params.y = config.y;
params.height = config.height;
params.width = config.width;
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

boolean useCutoutArea = intent.getBooleanExtra(USE_CUTOUT, false);
if (useCutoutArea && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
// If this is disabled, UtilsDevice line 61 needs to be changed to subtract cutout always
}
getWindow().setAttributes(params);
getWindow().setBackgroundDrawableResource(android.R.color.transparent);

Expand All @@ -94,10 +99,7 @@ protected void onCreate(Bundle savedInstanceState) {
}

private TransparentActivityConfig setupConfig(@Nullable TransparentActivityConfig config) {
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final DisplayMetrics metrics = new DisplayMetrics(); // this gets all
display.getMetrics(metrics);
final DisplayMetrics metrics = UtilsDevice.getDisplayMetrics(this);

if (config == null) {
Log.w(Countly.TAG, "[TransparentActivity] setupConfig, Config is null, using default values with full screen size");
Expand Down Expand Up @@ -148,19 +150,39 @@ public void onConfigurationChanged(android.content.res.Configuration newConfig)
currentOrientation = newConfig.orientation;
}

// CHANGE SCREEN SIZE
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
resizeContent();
}

private void resizeContent() {
// CHANGE SCREEN SIZE
final DisplayMetrics metrics = UtilsDevice.getDisplayMetrics(this);
int scaledWidth = (int) Math.ceil(metrics.widthPixels / metrics.density);
int scaledHeight = (int) Math.ceil(metrics.heightPixels / metrics.density);

// refactor in the future to use the resize_me action
webView.loadUrl("javascript:window.postMessage({type: 'resize', width: " + scaledWidth + ", height: " + scaledHeight + "}, '*');");
}

@Override
public void onDestroy() {
close(new HashMap<>());

if (Countly.sharedInstance().isInitialized()) {
Countly.sharedInstance().moduleContent.notifyAfterContentIsClosed();
}
super.onDestroy();
}

private void hideSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN);
}

private void resizeContentInternal() {
switch (currentOrientation) {
case Configuration.ORIENTATION_LANDSCAPE:
Expand Down Expand Up @@ -274,11 +296,7 @@ private void resizeMeAction(Map<String, Object> query) {
return;
}
try {
final WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
final Display display = wm.getDefaultDisplay();
final DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);

final DisplayMetrics metrics = UtilsDevice.getDisplayMetrics(this);
float density = metrics.density;

JSONObject resizeMeJson = (JSONObject) resizeMe;
Expand Down Expand Up @@ -414,15 +432,18 @@ private WebView createWebView(TransparentActivityConfig config) {
return false;
}
});
client.afterPageFinished = (closeIt) -> {
if (closeIt) {
close(new HashMap<>());
client.afterPageFinished = new WebViewPageLoadedListener() {
@Override public void onPageLoaded(boolean timedOut) {
if (timedOut) {
close(new HashMap<>());

if (Countly.sharedInstance().isInitialized()) {
Countly.sharedInstance().moduleContent.notifyAfterContentIsClosed();
if (Countly.sharedInstance().isInitialized()) {
Countly.sharedInstance().moduleContent.notifyAfterContentIsClosed();
}
} else {
hideSystemUI();
webView.setVisibility(View.VISIBLE);
}
} else {
webView.setVisibility(View.VISIBLE);
}
};
webView.setWebViewClient(client);
Expand Down
109 changes: 109 additions & 0 deletions sdk/src/main/java/ly/count/android/sdk/UtilsDevice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package ly.count.android.sdk;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.annotation.NonNull;

final class UtilsDevice {
private UtilsDevice() {
}

@NonNull
static DisplayMetrics getDisplayMetrics(@NonNull final Context context) {
final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
final DisplayMetrics metrics = new DisplayMetrics();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
applyWindowMetrics(context, wm, metrics);
} else {
applyLegacyMetrics(wm, metrics);
}
return metrics;
}

@TargetApi(Build.VERSION_CODES.R)
private static void applyWindowMetrics(@NonNull Context context,
@NonNull WindowManager wm,
@NonNull DisplayMetrics outMetrics) {
final WindowMetrics windowMetrics = wm.getCurrentWindowMetrics();
final WindowInsets windowInsets = windowMetrics.getWindowInsets();

boolean useCutoutArea = false;

if (Countly.sharedInstance().isInitialized()) {
useCutoutArea = Countly.sharedInstance().config_.configProvider.getUseCutoutArea();
}

// Always respect status bar & cutout (they affect safe area even in fullscreen)
int types = 0;
boolean usePhysicalScreenSize = !(context instanceof Activity);

// If not activity, we can't know system UI visibility, so always use physical screen size
if (!usePhysicalScreenSize) {
// Only subtract navigation bar insets when navigation bar is actually visible
if (windowInsets.isVisible(WindowInsets.Type.navigationBars())) {
types |= WindowInsets.Type.navigationBars();
}

if (windowInsets.isVisible(WindowInsets.Type.statusBars())) {
types |= WindowInsets.Type.statusBars();
}

if (useCutoutArea) {
boolean drawUnderCutout;
WindowManager.LayoutParams params = ((Activity) context).getWindow().getAttributes();
drawUnderCutout = params.layoutInDisplayCutoutMode
== WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;

// Only subtract display cutout insets when not allowed to draw under the cutout
if (!drawUnderCutout && windowInsets.isVisible(WindowInsets.Type.displayCutout())) {
types |= WindowInsets.Type.displayCutout();
}

// Only subtract display cutout insets when not allowed to draw under the cutout
if (windowInsets.isVisible(WindowInsets.Type.displayCutout())) {
types |= WindowInsets.Type.displayCutout();
}
}
}

if (!useCutoutArea) {
// Cutout is always respected as safe area for now even in fullscreen mode
if (windowInsets.isVisible(WindowInsets.Type.displayCutout())) {
types |= WindowInsets.Type.displayCutout();
}
}

final Insets insets = windowInsets.getInsets(types);
final Rect bounds = windowMetrics.getBounds();
final int width = bounds.width() - insets.left - insets.right;
final int height = bounds.height() - insets.top - insets.bottom;

outMetrics.widthPixels = width;
outMetrics.heightPixels = height;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
outMetrics.density = windowMetrics.getDensity();
} else {
// Fallback: use resource-based density
outMetrics.density = context.getResources().getDisplayMetrics().density;
}
}

@SuppressWarnings("deprecation")
private static void applyLegacyMetrics(@NonNull WindowManager wm,
@NonNull DisplayMetrics outMetrics) {
final Display display = wm.getDefaultDisplay();
display.getRealMetrics(outMetrics);
//getMetrics gives us size minus navigation bar
}
}
Loading