Compare commits

..

8 Commits

Author SHA1 Message Date
copilot-swe-agent[bot] 385f516d63 Improve variable naming for clarity
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-02-02 18:46:50 +00:00
copilot-swe-agent[bot] 6c89845cf9 Consume IME insets and use adjustPan for keyboard handling
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-02-02 18:46:10 +00:00
copilot-swe-agent[bot] ee73ccf6ef Improve code comment clarity
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-02-02 17:25:51 +00:00
copilot-swe-agent[bot] c9b6bb15e6 Simplify inset calculation and improve documentation
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-02-02 17:25:02 +00:00
copilot-swe-agent[bot] e810f27ac2 Apply navigation bar insets while excluding IME keyboard insets
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-02-02 17:23:26 +00:00
copilot-swe-agent[bot] eeee1637c3 Fix soft keyboard double-padding by excluding bottom insets
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-02-02 17:15:40 +00:00
copilot-swe-agent[bot] 521adebda2 Fix WebxdcActivity soft keyboard extra margin issue
Co-authored-by: adbenitez <24558636+adbenitez@users.noreply.github.com>
2026-02-02 16:56:59 +00:00
copilot-swe-agent[bot] b759203e93 Initial plan 2026-02-02 16:53:51 +00:00
7 changed files with 88 additions and 39 deletions
+1
View File
@@ -360,6 +360,7 @@
<activity android:name=".WebxdcActivity"
android:label=""
android:theme="@style/TextSecure.LightTheme"
android:windowSoftInputMode="adjustPan"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
</activity>
@@ -569,11 +569,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} else if (itemId == R.id.menu_show_map) {
WebxdcActivity.openMaps(this, chatId);
return true;
} else if (itemId == R.id.menu_audio_call) {
CallUtil.startCall(this, chatId, true);
return true;
} else if (itemId == R.id.menu_video_call) {
CallUtil.startCall(this, chatId, false);
} else if (itemId == R.id.menu_start_call) {
CallUtil.startCall(this, chatId);
return true;
} else if (itemId == R.id.menu_all_media) {
handleAllMedia();
@@ -77,7 +77,8 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity
findViewById(R.id.status_bar_background).setBackgroundResource(R.drawable.search_toolbar_shadow);
} else {
// add padding to avoid content hidden behind system bars
ViewUtil.applyWindowInsets(findViewById(R.id.content_container));
// Use applyWindowInsetsExcludingIme to respect navigation bars but not keyboard
ViewUtil.applyWindowInsetsExcludingIme(findViewById(R.id.content_container));
}
webView.setWebViewClient(new WebViewClient() {
@@ -19,40 +19,23 @@ public class CallUtil {
private static final String TAG = CallUtil.class.getSimpleName();
public static void startCall(Activity activity, int chatId) {
startCall(activity, chatId, false);
}
public static void startCall(Activity activity, int chatId, boolean audioOnly) {
String[] permissions = audioOnly
? new String[] { Manifest.permission.RECORD_AUDIO }
: new String[] { Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO };
String permissionExplanation = audioOnly
? activity.getString(R.string.perm_explain_access_to_mic_for_calls_denied)
: activity.getString(R.string.perm_explain_access_to_camera_and_mic_denied);
Permissions.with(activity)
.request(permissions)
.request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
.ifNecessary()
.withPermanentDenialDialog(permissionExplanation)
.withPermanentDenialDialog(activity.getString(R.string.perm_explain_access_to_camera_denied))
.onAllGranted(() -> {
int accId = DcHelper.getContext(activity).getAccountId();
startCall(activity, accId, chatId, audioOnly);
startCall(activity, accId, chatId);
})
.execute();
}
public static void startCall(Context context, int accId, int chatId) {
startCall(context, accId, chatId, false);
}
public static void startCall(Context context, int accId, int chatId, boolean audioOnly) {
Intent intent = new Intent(context, CallActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra(CallActivity.EXTRA_ACCOUNT_ID, accId);
intent.putExtra(CallActivity.EXTRA_CHAT_ID, chatId);
String hash = audioOnly ? "?disableVideoCompletely#startCall" : "#startCall";
intent.putExtra(CallActivity.EXTRA_HASH, hash);
intent.putExtra(CallActivity.EXTRA_HASH, "#startCall");
context.startActivity(intent);
}
@@ -316,6 +316,23 @@ public class ViewUtil {
return Insets.max(systemBars, displayCutout);
}
/**
* Get combined insets from status bar, navigation bar and display cutout areas,
* excluding the IME (soft keyboard).
*
* @param windowInsets The window insets to extract from
* @return Combined insets excluding IME
*/
private static Insets getCombinedInsetsExcludingIme(@NonNull WindowInsetsCompat windowInsets) {
Insets systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
Insets displayCutout = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout());
// Combine systemBars (which excludes IME) with displayCutout using max to handle notches/cutouts
Insets combined = Insets.max(systemBars, displayCutout);
return combined;
}
/**
* Apply window insets to a view by adding margin to avoid drawing it behind system bars.
* Convenience method that applies insets to all sides.
@@ -451,6 +468,67 @@ public class ViewUtil {
}
}
/**
* Apply window insets to a view by adding padding to avoid drawing elements behind system bars,
* excluding IME (soft keyboard) insets. This is useful for views that should respect navigation
* bars but handle keyboard resizing through the window's soft input mode.
*
* This method stores the original padding values in view tags to ensure that
* padding doesn't accumulate on multiple inset applications.
*
* Note: This feature is only enabled on API 30+ (Android 11+) where WindowInsets APIs
* work correctly. On older API levels, the method returns early and the view will use
* default system bar handling (content may be drawn behind system bars).
*
* @param view The view to apply insets to
*/
public static void applyWindowInsetsExcludingIme(@NonNull View view) {
// Only enable on API 30+ where WindowInsets APIs work correctly
if (!isEdgeToEdgeSupported()) return;
// Store the original padding as a tag only if not already stored
// This prevents losing the true original padding on subsequent calls
if (view.getTag(R.id.tag_window_insets_padding_left) == null) {
view.setTag(R.id.tag_window_insets_padding_left, view.getPaddingLeft());
view.setTag(R.id.tag_window_insets_padding_top, view.getPaddingTop());
view.setTag(R.id.tag_window_insets_padding_right, view.getPaddingRight());
view.setTag(R.id.tag_window_insets_padding_bottom, view.getPaddingBottom());
}
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
Insets insets = getCombinedInsetsExcludingIme(windowInsets);
// Retrieve the original padding values from tags with null checks
Integer leftTag = (Integer) v.getTag(R.id.tag_window_insets_padding_left);
Integer topTag = (Integer) v.getTag(R.id.tag_window_insets_padding_top);
Integer rightTag = (Integer) v.getTag(R.id.tag_window_insets_padding_right);
Integer bottomTag = (Integer) v.getTag(R.id.tag_window_insets_padding_bottom);
int basePaddingLeft = leftTag != null ? leftTag : 0;
int basePaddingTop = topTag != null ? topTag : 0;
int basePaddingRight = rightTag != null ? rightTag : 0;
int basePaddingBottom = bottomTag != null ? bottomTag : 0;
v.setPadding(
basePaddingLeft + insets.left,
basePaddingTop + insets.top,
basePaddingRight + insets.right,
basePaddingBottom + insets.bottom
);
// Consume IME insets to prevent them from affecting child views (like WebView)
// This stops the double-padding issue where both window resize and inset padding occur
WindowInsetsCompat withoutIme = new WindowInsetsCompat.Builder(windowInsets)
.setInsets(WindowInsetsCompat.Type.ime(), Insets.NONE)
.build();
return withoutIme;
});
// Request the initial insets to be dispatched if the view is attached
if (view.isAttachedToWindow()) {
ViewCompat.requestApplyInsets(view);
}
}
/**
* Apply the top status bar inset as the height of a view.
*/
+1 -8
View File
@@ -28,14 +28,7 @@
<item android:id="@+id/menu_start_call"
android:title="@string/start_call"
android:icon="@drawable/ic_videocam_white_24dp"
app:showAsAction="always">
<menu>
<item android:id="@+id/menu_audio_call"
android:title="@string/start_audio_call" />
<item android:id="@+id/menu_video_call"
android:title="@string/start_video_call" />
</menu>
</item>
app:showAsAction="always" />
<item android:id="@+id/menu_all_media"
android:title="@string/apps_and_media"
-4
View File
@@ -380,8 +380,6 @@
<!-- the action "to call someone", used as a tooltip for the "phone" icon. not: "the call" -->
<string name="start_call">Call</string>
<string name="start_audio_call">Audio Call</string>
<string name="start_video_call">Video Call</string>
<!-- the action "to answer" or to "accept" or to "pick up" a call. not: "the answer" -->
<string name="answer_call">Answer</string>
<!-- the action "to decline" a call, not: "the decline" -->
@@ -1039,8 +1037,6 @@
<string name="perm_explain_access_to_camera_denied">To take photos or capture videos, go to the app settings, select \"Permissions\", and enable \"Camera\".</string>
<!-- give the user an idea where to find the "Microphone" option. the hint is only shown if access was initially denied by the user. pick up wordings really used on the systems, but do not be overly precise: things shift around often and there are too many system we support to track every detail and click path -->
<string name="perm_explain_access_to_mic_denied">To send audio messages, go to system or app settings, select "Permissions" or "Privacy &amp; Security", and enable \"Microphone\".</string>
<string name="perm_explain_access_to_camera_and_mic_denied">To make video calls, go to the app settings, select \"Permissions\", and enable \"Camera\" and \"Microphone\".</string>
<string name="perm_explain_access_to_mic_for_calls_denied">To make audio calls, go to system or app settings, select "Permissions" or "Privacy &amp; Security", and enable \"Microphone\".</string>
<string name="perm_explain_access_to_storage_denied">To receive or send files, go to the app settings, select \"Permissions\", and enable \"Storage\".</string>
<string name="perm_explain_access_to_location_denied">To attach a location, go to the app settings, select \"Permissions\", and enable \"Location\".</string>
<string name="perm_explain_access_to_notifications_denied">To receive notifications, go to \"System Settings / Apps / Delta Chat\" and enable \"Notifications\".</string>