android系統適配通知欄背景的一種方案

android系統適配通知欄背景的一種方案

現狀:

           目前android碎片化嚴重,不少廠商會針對android系統底層進行改造,通知欄也不例外,相似小米手機或者華爲的一些手機,通知欄就不是原生android的,有些通知欄的背景是黑色,有些通知欄的背景是白色,因此在應用中須要自定義通知欄的時候,很難去適配機器自身通知欄的樣式,目前不少應用在實現自定義通知欄的時候,爲了適配全部機型,一般會在自定義通知欄的時候加一層背景,例以下面的360:java

  

如何進行對各類手機適配呢

       適配的方式大概有兩種,一種簡單粗暴:爲自定義通知設置固定的背景(上圖中的360衛士就這麼幹的),好比黑色。那麼內容天然就是白色或近似白色。這樣,在全部的手機上都能正常顯示,不會出如今黑色背景通知欄上顯示良好,到了白色背景通知欄上就幾乎啥也看不見。使用這種方案的應用太多了。我我的很不推崇這種方式,這樣會使得自定義通知在將近一半的手機上顯示得很突兀,和系統的通知欄不夠沉浸,影響總體美觀。另外一種方案就稍微合理一些:經過讀取系統的通知欄樣式文件,獲取到title和content的顏色,進而將這個顏色設置到自定義通知上。讀取通知欄樣式文件自己有兼容性問題,不一樣Android版本的樣式文件有變,具體可參考這篇博客 通知欄設置系統字體顏色 ,這種方式也不是在全部手機上生效,實際測試發現,仍是有小部分機型無法讀取或是讀取到的是錯誤的。拿到title和content的顏色後,還能夠經過算法(後面細說)判斷這個顏色是近似白色仍是近似黑色,進而能判斷出通知欄的背景是近似黑色仍是近似白色,這樣就能根據不一樣的通知欄背景加載不一樣的自定義通知佈局。進而作到良好的適配。android

代碼實現

/**
 * 通知欄的幫助類,提供查詢手機是否禁止通知欄,判斷通知欄背景顏色
 * Created by dengqu on 2016/12/12.
 */
public class NotificationsUtils {
    private final static String TAG = NotificationsUtils.class.getSimpleName();
    private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";
    private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
    private static final double COLOR_THRESHOLD = 180.0;
    private static int titleColor;

    /**
     * 判斷應用通知欄是否開啓權限
     *
     * @param context
     * @return
     */
    public static boolean isNotificationEnabled(Context context) {
        try {
            if (AndroidConfig.getAndroidVersion() >= Build.VERSION_CODES.KITKAT) {
                AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
                ApplicationInfo appInfo = context.getApplicationInfo();
                String pkg = context.getApplicationContext().getPackageName();
                int uid = appInfo.uid;
                Class appOpsClass = null;
                appOpsClass = Class.forName(AppOpsManager.class.getName());
                Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class);
                Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION);
                int value = (int) opPostNotificationValue.get(Integer.class);
                return ((int) checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED);
            }
        } catch (Exception e) {
            XLLog.e(TAG, e);
        }
        return true;
    }

    /**
     * 判斷通知欄背景顏色,如今手機通知欄大部分不是白色就是黑色背景
     *
     * @param context
     * @return
     */
    public static boolean isDarkNotiFicationBar(Context context) {
        return !isColorSimilar(Color.BLACK, getNotificationColor(context));
    }

    private static int getNotificationColor(Context context) {
        if (context instanceof AppCompatActivity) {
            return getNotificationColorCompat(context);
        } else {
            return getNotificationColorInternal(context);
        }
    }

    private static boolean isColorSimilar(int baseColor, int color) {
        int simpleBaseColor = baseColor | 0xff000000;
        int simpleColor = color | 0xff000000;
        int baseRed = Color.red(simpleBaseColor) - Color.red(simpleColor);
        int baseGreen = Color.green(simpleBaseColor) - Color.green(simpleColor);
        int baseBlue = Color.blue(simpleBaseColor) - Color.blue(simpleColor);
        double value = Math.sqrt(baseRed * baseRed + baseGreen * baseGreen + baseBlue * baseBlue);
        if (value < COLOR_THRESHOLD) {
            return true;
        }
        return false;
    }

    private static int getNotificationColorInternal(Context context) {
        final String DUMMY_TITLE = "DUMMY_TITLE";
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setContentText(DUMMY_TITLE);
        Notification notification = builder.build();
        ViewGroup notificationRoot = (ViewGroup) notification.contentView.apply(context, new FrameLayout(context));
        final TextView titleView = (TextView) notificationRoot.findViewById(android.R.id.title);
        if (titleView == null) {
            iteratoryView(notificationRoot, new Filter() {
                @Override
                public void filter(View view) {
                    if (view instanceof TextView) {
                        TextView textView = (TextView) view;
                        if (DUMMY_TITLE.equals(textView.getText().toString())) {
                            titleColor = textView.getCurrentTextColor();
                        }
                    }
                }
            });
            return titleColor;
        } else {
            return titleView.getCurrentTextColor();
        }

    }

    private static int getNotificationColorCompat(Context context) {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        Notification notification = builder.build();
        int layoutId = notification.contentView.getLayoutId();
        ViewGroup notificationRoot = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null);
        final TextView titleView = (TextView) notificationRoot.findViewById(android.R.id.title);
        if (titleView == null) {
            final List<TextView> textViews = new ArrayList<>();
            iteratoryView(notificationRoot, new Filter() {
                @Override
                public void filter(View view) {
                    textViews.add((TextView) view);
                }
            });

            float minTextSize = Integer.MIN_VALUE;
            int index = 0;
            for (int i = 0, j = textViews.size(); i < j; i++) {
                float currentSize = textViews.get(i).getTextSize();
                if (currentSize > minTextSize) {
                    minTextSize = currentSize;
                    index = i;
                }
            }
            return textViews.get(index).getCurrentTextColor();
        } else {
            return titleView.getCurrentTextColor();
        }
    }

    private static void iteratoryView(View view, Filter filter) {
        if (view == null || filter == null) {
            return;
        }
        filter.filter(view);
        if (view instanceof ViewGroup) {
            ViewGroup container = (ViewGroup) view;
            for (int i = 0, j = container.getChildCount(); i < j; i++) {
                View child = container.getChildAt(i);
                iteratoryView(child, filter);
            }
        }
    }

    private interface Filter {
        void filter(View view);
    }
}
相關文章
相關標籤/搜索