package com.andretissot.firebaseextendednotification; import android.content.Context; import android.content.Intent; import android.content.res.AssetManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.StrictMode; import androidx.core.content.FileProvider; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.UUID; import org.json.*; /** * Created by André Augusto Tissot on 15/10/16. */ public class Options { public Options(JSONObject options, Context context){ this.context = context; this.id = getInt(options, "id", 0); this.title = getString(options, "title"); if(this.title == null){ Resources resource = context.getResources(); this.title = resource.getText(resource.getIdentifier("app_name", "string", context.getPackageName())).toString(); } this.ticker = getString(options, "ticker"); this.autoCancel = getBoolean(options, "autoCancel", true); this.openApp = getBoolean(options, "openApp", false); this.headsUp = getBoolean(options, "headsUp", false); this.summary = getString(options, "summary"); this.text = getString(options, "text"); this.bigText = getString(options, "bigText"); Integer color = getARGB(options, "color"); if(this.doesColor = (color != null)) this.color = color; this.textLines = getStringArray(options, "textLines"); this.vibratePattern = getLongArray(options, "vibrate", null, true); this.doesVibrate = this.vibratePattern!=null || getBoolean(options, "vibrate", true); this.soundUri = getUriOption(options, "sound"); this.doesSound = this.soundUri!=null || getBoolean(options, "sound", true); this.setSmallIconResourceId(options); this.setLargeIconBitmap(options); this.bigPictureBitmap = getBitmapOption(options, "bigPicture"); this.channelId = getString(options, "channelId", "notification"); this.channelName = getString(options, "channelName", "Notification"); this.channelDescription = getString(options, "channelDescription", ""); } protected int id; protected String title; protected String ticker; protected String summary; protected boolean autoCancel; protected boolean openApp; protected boolean headsUp; protected String[] textLines; protected String text; protected String bigText; protected int smallIconResourceId; protected boolean doesVibrate; protected long[] vibratePattern; protected Uri soundUri; protected boolean doesSound; protected int color; protected boolean doesColor; protected Bitmap largeIconBitmap; protected Bitmap bigPictureBitmap; protected Context context; protected String channelName; protected String channelId; protected String channelDescription; public int getId() { return id; } public String getTitle() { return title; } public String getSummary() { return summary; } public boolean doesAutoCancel() { return autoCancel; } public boolean doesOpenApp() { return openApp; } public boolean doesHeadsUp() { return headsUp; } public String[] getTextLines() { return textLines; } public String getText() { return text; } public String getBigText() { return bigText; } public String getTicker() { return ticker; } public int getSmallIconResourceId() { return smallIconResourceId; } public boolean doesVibrate() { return doesVibrate; } public long[] getVibratePattern() { return vibratePattern; } public boolean doesSound() { return doesSound; } public Uri getSoundUri() { return soundUri; } public boolean doesColor() { return doesColor; } public int getColor() { return color; } public Bitmap getLargeIconBitmap() { return largeIconBitmap; } public Bitmap getBigPictureBitmap() { return bigPictureBitmap; } public String getChannelId() { return channelId; } public String getChannelName() { return channelName; } public String getChannelDescription() { return channelDescription; } protected void setSmallIconResourceId(JSONObject options){ String icon = null; if(!options.isNull("smallIcon")){ try { icon = options.getString("smallIcon"); } catch (JSONException e){ e.printStackTrace(); } } if(icon != null) this.smallIconResourceId = getResourceIdForDrawable(icon); if(this.smallIconResourceId == 0) this.smallIconResourceId = getResourceIdForDrawable("icon"); if(this.smallIconResourceId == 0) this.smallIconResourceId = getResourceIdForDrawable("ic_launcher"); if(this.smallIconResourceId == 0) this.smallIconResourceId = android.R.drawable.ic_popup_reminder; } protected void setLargeIconBitmap(JSONObject options){ this.largeIconBitmap = this.getBitmapOption(options, "largeIcon"); if(this.largeIconBitmap == null){ int iconId = getResourceIdForDrawable(context.getPackageName(), "icon"); if (iconId == 0) iconId = getResourceIdForDrawable("android", "icon"); if (iconId == 0) iconId = android.R.drawable.screen_background_dark_transparent; //uses app default this.largeIconBitmap=BitmapFactory.decodeResource(this.context.getResources(), iconId); } } protected Uri getUriOption(JSONObject options, String optionName){ String uriSource = null; if(!options.isNull(optionName)){ try { uriSource = options.getString(optionName); } catch (JSONException e) { e.printStackTrace(); } } if(uriSource == null) return null; if (uriSource.startsWith("res:")) return getUriForResourcePath(uriSource); if (uriSource.startsWith("file:///")) return getUriFromPath(uriSource); if (uriSource.startsWith("file://")) return getUriFromAsset(uriSource); if (uriSource.startsWith("http")) return getUriFromRemote(uriSource); return null; } protected Bitmap getBitmapOption(JSONObject options, String optionName){ Uri iconUri = getUriOption(options, optionName); if(iconUri == null) return null; try { InputStream input = this.context.getContentResolver().openInputStream(iconUri); return BitmapFactory.decodeStream(input); } catch (IOException e) { e.printStackTrace(); } return null; } protected Integer getInt(JSONObject options, String attributeName, Integer defaultValue){ try { return options.getInt(attributeName); } catch (JSONException e){ return defaultValue; } } protected boolean getBoolean(JSONObject options, String attributeName, boolean defaultValue){ if(options.has(attributeName)){ try { return options.getBoolean(attributeName); } catch (JSONException e) { e.printStackTrace(); } } return defaultValue; } protected String getString(JSONObject options, String attributeName){ return getString(options, attributeName, null); } protected String getString(JSONObject options, String attributeName, String defaultValue){ if(options.isNull(attributeName)) return defaultValue; try { String string = options.getString(attributeName); if(string.isEmpty()) return defaultValue; return string; } catch (JSONException e){ e.printStackTrace(); } return defaultValue; } protected Integer getARGB(JSONObject options, String attributeName){ Integer colorInt = getInt(options, attributeName, null); if(colorInt != null) return colorInt; String colorString = getString(options, attributeName); if(colorString == null) return null; if(colorString.charAt(0) == '#') colorString = colorString.substring(1); if(colorString.matches("^[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$")){ try { return Integer.parseInt(colorString, 16); } catch(NumberFormatException e) {} } return null; // other "formats" not yet supported } protected String[] getStringArray(JSONObject options, String attributeName) { if(options.isNull(attributeName)) return null; JSONArray lines; try { lines = options.getJSONArray(attributeName); } catch (JSONException e){ e.printStackTrace(); return null; } String[] stringArray = new String[lines.length()]; for (int i=0;i<lines.length();i++){ if(lines.isNull(i)){ stringArray[i] = null; continue; } try { stringArray[i] = lines.getString(i); } catch (JSONException e) { stringArray[i] = null; } } return stringArray; } protected long[] getLongArray(JSONObject options, String attributeName, long[] defaultValue, boolean supressExceptions){ if(!options.has(attributeName)) return defaultValue; JSONArray lines; try { lines = options.getJSONArray(attributeName); } catch (JSONException e){ if(!supressExceptions) { e.printStackTrace(); } return defaultValue; } long[] longArray = new long[lines.length()]; for (int i=0;i<lines.length();i++){ try { longArray[i] = lines.getLong(i); } catch (JSONException e) { if(!supressExceptions) { e.printStackTrace(); } } } return longArray; } protected int getResourceIdForDrawable(String resourcePath) { int resId = getResourceIdForDrawable(this.context.getPackageName(), resourcePath); if (resId == 0) resId = getResourceIdForDrawable("android", resourcePath); return resId; } protected int getResourceIdForDrawable(String className, String resourcePath) { try { return this.context.getResources().getIdentifier(getBaseName(resourcePath), getResourceTypeName(resourcePath), className); } catch (Exception e) { e.printStackTrace(); } return 0; } protected String getBaseName(String resPath) { if(resPath == null) { return null; } String drawable = resPath; if (drawable.contains("/")) drawable = drawable.substring(drawable.lastIndexOf('/') + 1); if (resPath.contains(".")) drawable = drawable.substring(0, drawable.lastIndexOf('.')); return drawable; } protected String getResourceTypeName(String resPath) { if(resPath == null) { return null; } if(resPath.contains("/")) return resPath.substring(0, resPath.lastIndexOf('/')); return "drawable"; } private Uri getUriForResourcePath(String path) { String resPath = path.replaceFirst("res://", ""); int resId = getResourceIdForDrawable(resPath); File file = getTmpFile(); if (resId == 0) return null; try { Resources res = this.context.getResources(); FileOutputStream outStream = new FileOutputStream(file); InputStream inputStream = res.openRawResource(resId); copyFile(inputStream, outStream); return getProvidedFileUri(file); } catch (Exception e) { e.printStackTrace(); } return null; } private Uri getUriFromPath(String path) { String absPath = path.replaceFirst("file://", ""); File file = new File(absPath); if (file.exists()) return getProvidedFileUri(file); return null; } private Uri getUriFromAsset(String path) { String resPath = path.replaceFirst("file:/", "www"); String fileName = resPath.substring(resPath.lastIndexOf('/') + 1); File file = getTmpFile(fileName); if (file == null) return null; try { AssetManager assets = this.context.getAssets(); FileOutputStream outStream = new FileOutputStream(file); InputStream inputStream = assets.open(resPath); copyFile(inputStream, outStream); return getProvidedFileUri(file); } catch (Exception e) { e.printStackTrace(); } return null; } private File getTmpFile(String name) { File dir = context.getExternalCacheDir(); if (dir == null) return null; String storage = dir.toString() + "/extendednotification"; new File(storage).mkdir(); return new File(storage, name); } private File getTmpFile () { return getTmpFile(UUID.randomUUID().toString()); } private void copyFile(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) out.write(buffer, 0, read); out.flush(); out.close(); } private Uri getProvidedFileUri(File ouputFile){ if (Build.VERSION.SDK_INT >= 24) { Uri uriProvided = FileProvider.getUriForFile(this.context, this.context.getPackageName()+".fbenfileprovider", ouputFile); this.context.grantUriPermission("com.android.systemui", uriProvided, Intent.FLAG_GRANT_READ_URI_PERMISSION); return uriProvided; } return Uri.fromFile(ouputFile); } private Uri getUriFromRemote(String path) { File file = getTmpFile(); if (file == null) return null; try { URL url = new URL(path); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); connection.setRequestProperty("Connection", "close"); connection.setConnectTimeout(5000); connection.connect(); InputStream input = connection.getInputStream(); FileOutputStream outStream = new FileOutputStream(file); copyFile(input, outStream); return getProvidedFileUri(file); } catch (Exception e) { e.printStackTrace(); } return null; } }