在android 4.4 版本中狀態欄是在一個apk中(SystemUI.apk),查看layout/gemini_status_bar_expanded.xml源文件
xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:systemui=”http://schemas.android.com/apk/res/com.android.systemui”
android:id=”@+id/notification_panel”
android:layout_width=”0dp”
android:layout_height=”wrap_content”
android:background=”@drawable/notification_panel_bg”
android:paddingTop=”@dimen/notification_panel_padding_top”
android:layout_marginStart=”@dimen/notification_panel_margin_left”
>
android:id=”@+id/handle”
android:layout_width=”match_parent”
android:layout_height=”@dimen/close_handle_height”
android:background=”@drawable/status_bar_close”
android:visibility=”invisible”
/>
layout=”@layout/gemini_carrier_label”
android:layout_height=”@dimen/carrier_label_height”
android:layout_width=”match_parent”
android:layout_marginBottom=”@dimen/close_handle_height”
android:layout_gravity=”bottom”
/>
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:layout_marginBottom=”@dimen/close_handle_underlap”
android:orientation=”vertical”
android:animateLayoutChanges=”false”
>
android:layout_width=”match_parent”
android:layout_height=”@dimen/notification_panel_header_height”
/>
android:id=”@+id/toolBarSwitchPanel”
android:layout_width=”match_parent”
android:layout_height=”103dip”
android:background=”@drawable/notification_header_bg”>
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
>
android:layout=”@layout/flip_settings”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
/>
android:id=”@+id/scroll”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:fadingEdge=”none”
android:overScrollMode=”ifContentScrolls”
>
android:id=”@+id/latestItems”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
systemui:rowHeight=”@dimen/notification_row_min_height”
/>
可知我們只要設置NotificationPanelView的背景即可,而這個NotificationPanelView在PhoneStatusBar.java文件中的makeStatusBarView方法中初始化。現在采用的方法是將屏幕截屏后將獲取到的Bitmap模糊化作為NotificationPanelView背景。當用戶點擊最上面的狀態欄時就會觸發事件,而我們獲取到這個事件,並在這時截取屏幕。仔細看代碼可以得到用戶在點擊上方狀態欄時就會觸發在PhoneStatusBarView.java中的onTouchEvent方法添加如下代碼,其中考慮到橫豎屏轉化的問題得調用getResources().getConfiguration().orientation 判斷是橫屏還是豎屏。
if (event.getAction() == MotionEvent.ACTION_DOWN) {
BitmapDrawable mBitmapDrawable;
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
mBitmapDrawable = new BitmapDrawable(getResources(), darkBitmap(fastBlur(shot())));
}else{
mBitmapDrawable = new BitmapDrawable(getResources(), darkBitmap(fastBlur(rotateBitmap(shot()))));
}
mBitmapDrawable.setTileModeXY(TileMode.REPEAT , TileMode.REPEAT);
mBar.mNotificationPanel.setBackground(mBitmapDrawable);
}
需要的截屏類,和截屏后處理的代碼如下:
public static boolean leftOrRightLandscape = true;
private Bitmap shot() {
DisplayMetrics dm = getResources().getDisplayMetrics();
int width , height;
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
width = dm.widthPixels;
height = dm.heightPixels;
}else{
width = dm.heightPixels;
height = dm.widthPixels;
}
Bitmap mBitmap = SurfaceControl.screenshot(width, height);
return mBitmap;
}
private Bitmap fastBlur(Bitmap bkg) {
float scaleFactor = 8;
float radius = 2;
Bitmap overlay = Bitmap.createBitmap(
(int) (bkg.getWidth() / scaleFactor),
(int) (bkg.getHeight() / scaleFactor),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.translate(0, 0);
canvas.scale(1 / scaleFactor, 1 / scaleFactor);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bkg, 0, 0, paint);
overlay = FastBlur.doBlur(overlay, (int) radius, true);
DisplayMetrics dm = getResources().getDisplayMetrics();
int width = bkg.getWidth();
int height = bkg.getHeight();
Bitmap mBitmap = overlay.createScaledBitmap(overlay, width, height, true);
return mBitmap;
}
private Bitmap darkBitmap(Bitmap srcBitmap){
int imgHeight, imgWidth;
imgHeight = srcBitmap.getHeight();
imgWidth = srcBitmap.getWidth();
Bitmap dstBitmap = Bitmap.createBitmap(imgWidth, imgHeight, Config.ARGB_8888);
Bitmap bmp = Bitmap.createBitmap(imgWidth, imgHeight,
Config.ARGB_8888);
float contrast = (float) (30 / 100.0);
ColorMatrix cMatrix = new ColorMatrix();
cMatrix.set(new float[] { contrast, 0, 0, 0, 0, 0,
contrast, 0, 0, 0,
0, 0, contrast, 0, 0, 0, 0, 0, 1, 0 });
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));
Canvas canvas = new Canvas(bmp);
canvas.drawBitmap(srcBitmap, 0, 0, paint);
return bmp;
}
private Bitmap rotateBitmap(Bitmap bmp){
Bitmap mbmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(),
Config.ARGB_8888);
Canvas canvas = new Canvas(mbmp);
canvas.drawBitmap(bmp, 0, 0, null);
Matrix matrix = new Matrix();
matrix.postScale(1f, 1f);
if(leftOrRightLandscape == true){
matrix.postRotate(90);
}else{
matrix.postRotate(-90);
}
Bitmap dstbmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(),matrix, true);
canvas.drawBitmap(dstbmp, 0, 0, null);
return dstbmp;
}
因為橫屏截取屏幕時,截取到的Bitmap會被旋轉,這里需要考慮到將獲取到的Bitmap轉換方向,此處還必須的考慮是左旋還是右旋到的橫屏,轉屏的方向不一樣的話,那么得到的Bitmap也不一樣。在SystemUIService.java中添加如下代碼:
private OrientationEventListener mOrientationListener;
private boolean mScreenProtrait = true;
private boolean mCurrentOrient = false;
private final void startOrientationChangeListener() {
mOrientationListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int rotation) {
if ((rotation >= 0) && (rotation <= 180)) {// portrait
mCurrentOrient = true;
if (mCurrentOrient != mScreenProtrait) {
mScreenProtrait = mCurrentOrient;
PhoneStatusBarView.leftOrRightLandscape = true;
}
} else if ((rotation > 180) && (rotation < 360)) {// landscape
mCurrentOrient = false;
if (mCurrentOrient != mScreenProtrait) {
mScreenProtrait = mCurrentOrient;
PhoneStatusBarView.leftOrRightLandscape = false;
}
}
}
};
mOrientationListener.enable();
}
並在onCreate方法中添加startOrientationChangeListener();
這里是調用的android.view.OrientationEventListener這個監聽屏幕轉換方向的類,獲取到屏幕的轉換的度數之后就可以判斷是否左旋還是右旋,並將布爾數值賦給PhoneStatusBarView類中的屬性,用戶在點擊狀態欄就會將Bitmap旋轉為合適的度數,具體代碼看上面。
此處還得注意的一個地方是,當用戶將狀態欄展開后再轉化屏幕方向就會出現一個問題,因為背景圖還是以前的圖,而如果又重新截屏的話那截取到的是含有展開狀態欄的。所以必須的在這種情況下屏幕方向轉換時,將展開的狀態欄退回。可以將PhoneStatusBar的onConfigurationChanged方法中添加animateCollapsePanels();
附:效果圖如下: