diff --git a/app/src/main/java/com/termux/api/apis/WallpaperAPI.java b/app/src/main/java/com/termux/api/apis/WallpaperAPI.java index 3a8efe62..b0ebc44f 100644 --- a/app/src/main/java/com/termux/api/apis/WallpaperAPI.java +++ b/app/src/main/java/com/termux/api/apis/WallpaperAPI.java @@ -6,6 +6,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Rect; import android.os.IBinder; import com.termux.api.util.ResultReturner; @@ -20,6 +21,9 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class WallpaperAPI { @@ -40,6 +44,18 @@ public static void onReceive(final Context context, final Intent intent) { */ public static class WallpaperService extends Service { protected static final int DOWNLOAD_TIMEOUT = 30; + protected static final Pattern CROP_PATTERN = Pattern.compile( + "^(\\d+)?" // width + + "(?:([x:])(\\d+))?" // height + + "(?:\\+(\\d+)\\+(\\d+))?" // offset + + "(%?)$" // relative + ); + protected enum CROP_GROUPS { // in accordance with above arrangement + WIDTH, + SEPARATOR, HEIGHT, + XOFFSET, YOFFSET, + PERCENT + } private static final String LOG_TAG = "WallpaperService"; @@ -122,16 +138,96 @@ protected void onWallpaperResult(final Intent intent, WallpaperResult result) { if (result.wallpaper != null) { try { - int flag = intent.hasExtra("lockscreen") ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM; - wallpaperManager.setBitmap(result.wallpaper, null, true, flag); + int which = WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK; + if (intent.hasExtra("lockscreen")) { + which = intent.getBooleanExtra("lockscreen", false) ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM; + } + Rect crop = null; + try { + crop = calculateWallpaperCrop(result.wallpaper, intent.getStringExtra("crop")); + } catch (IllegalArgumentException e) { + result.error = "-c ignored: " + e.getMessage(); + } + wallpaperManager.setBitmap(result.wallpaper, crop, true, which); result.message = "Wallpaper set successfully!"; - } catch (IOException e) { + } catch (IOException | IllegalArgumentException e) { result.error = "Error setting wallpaper: " + e.getMessage(); } } postWallpaperResult(context, intent, result); } + private Rect calculateWallpaperCrop(Bitmap wallpaper, String cropString) throws IllegalArgumentException { + if (cropString == null) { + return null; + } + Matcher cropMatch = CROP_PATTERN.matcher(cropString); + if (cropMatch.matches()) { + MatchResult cropResult = cropMatch.toMatchResult(); + int oldWidth = wallpaper.getWidth(); + int oldHeight = wallpaper.getHeight(); + double oldRatio = (double) oldWidth / (double) oldHeight; + Rect crop = new Rect(); + String w = cropResult.group(CROP_GROUPS.WIDTH.ordinal()); + String sep = cropResult.group(CROP_GROUPS.SEPARATOR.ordinal()); + String h = cropResult.group(CROP_GROUPS.HEIGHT.ordinal()); + String x = cropResult.group(CROP_GROUPS.XOFFSET.ordinal()); + String y = cropResult.group(CROP_GROUPS.YOFFSET.ordinal()); + boolean relative = "%".equals(cropResult.group(CROP_GROUPS.PERCENT.ordinal())); + if (":".equals(sep)) { + if (w == null) { + throw new IllegalArgumentException("Aspect ratio needs both width and height!"); + } + int width = Integer.parseInt(w); + int height = Integer.parseInt(h); + double ratio = (double) width / (double) height; + if (ratio > oldRatio) { + crop.bottom = (int) ((double) oldWidth / ratio); + crop.right = oldWidth; + } else { + crop.bottom = oldHeight; + crop.right = (int) ((double) oldHeight * ratio); + } + } else if ("x".equals(sep) || w != null) { + double width = 0; + double height = 0; + if (w != null) { + width = Double.parseDouble(w); + height = width / oldRatio; + } + if (h != null) { + height = Double.parseDouble(h); + if (w == null) { + width = height * oldRatio; + } + } + if (relative) { + crop.right = (int) (oldWidth * width / 100); + crop.bottom = (int) (oldHeight * height / 100); + } else { + crop.right = (int) width; + crop.bottom = (int) height; + } + } else { + throw new IllegalArgumentException("No size or aspect ratio given!"); + } + if (x != null) { + double xOff = Double.parseDouble(x); + double yOff = Double.parseDouble(y); + if (relative) { + xOff = (oldWidth-crop.width()) * xOff / 100; + yOff = (oldHeight-crop.height()) * yOff / 100; + } + crop.offset((int) xOff, (int) yOff); + } else { + crop.offset((oldWidth - crop.width())/2, (oldHeight - crop.height())/2); + } + return crop; + } else { + throw new IllegalArgumentException("Cannot parse crop geometry!"); + } + } + protected void postWallpaperResult(final Context context, final Intent intent, final WallpaperResult result) { ResultReturner.returnData(context, intent, out -> { out.append(result.message).append("\n");