1. 程式人生 > >Android 8.1上狀態列新增截圖功能

Android 8.1上狀態列新增截圖功能

1.需求

客戶要求在狀態列新增截圖功能。。

實現效果如下:

實現步驟

步驟1

在配置檔案alps\vendor\mediatek\proprietary\packages\apps\SystemUI\res\values\config.xml新增\screenshot 顯示

一個是固定位置顯示, 另一個是編輯時候的顯示

<string name="quick_settings_tiles_default" translatable="false">
        wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,screenshot
    </string>

    <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
    <string name="quick_settings_tiles_stock" translatable="false">
        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night,screenshot
    </string>

步驟2

在\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\qs\tileimpl\QSFactoryImpl.java新增如下程式碼.

import com.android.systemui.qs.tiles.ScreenShotTile;

public class QSFactoryImpl implements QSFactory {

    ......

    public QSTile createTile(String tileSpec) {
        ......
		else if (tileSpec.equals("screenshot")) return new ScreenShotTile(mHost);
		......
    }
	......
}

步驟3

在alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\qs\tiles目錄下新增一個類,ScreenShotTile.java

package com.android.systemui.qs.tiles;
import com.android.systemui.R;
import android.os.Message;
import android.os.Handler;
import android.content.Context;
import android.content.Intent;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.screenshot.GlobalScreenshot;
import android.os.RemoteException;
import com.android.systemui.statusbar.policy.ScreenShotController;
import android.os.Messenger;
import com.android.systemui.qs.QSHost;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.Dependency;
public class ScreenShotTile extends QSTileImpl<BooleanState> {  
    private static final String TAG = "ScreenShotTile";  
    private static final int SCREEN_SHOT_MESSAGE = 10000;  
    private static GlobalScreenshot mScreenshot;  
	 private final ScreenShotController mScreenShotController;
	 private final ActivityStarter mActivityStarter;
      
    Handler mHandler = new Handler() {  
        public void handleMessage(Message msg) {  
            switch (msg.what) {  
            case SCREEN_SHOT_MESSAGE:  
                final Messenger callback = msg.replyTo;  
                if (mScreenshot == null) {  
                    mScreenshot = new GlobalScreenshot(mContext);  
                }  
                mScreenshot.takeScreenshot(new Runnable() {  
                    @Override public void run() {  
                        Message reply = Message.obtain(null, 1);  
                        try {  
                            if(callback != null){  
                                callback.send(reply);  
                            }  
                        }catch(RemoteException e){  
                        }  
                    }  
                }, msg.arg1 > 0, msg.arg2 > 0);  
                break;                      
            default:  
                break;  
            }  
        }  
    };  
      
    public ScreenShotTile(QSHost host) {  
        super(host);  
		mScreenShotController=Dependency.get(ScreenShotController.class);
		 mActivityStarter = Dependency.get(ActivityStarter.class);
    }  
  
    @Override  
    public BooleanState newTileState() {  
        return new BooleanState();  
    }  
  
    
	
	@Override
    public void handleSetListening(boolean listening) {
        
    }
  
    @Override  
    protected void handleClick() {
		//mActivityStarter.postStartActivityDismissingKeyguard(
         //           new Intent(), 0);//此方法會自動解鎖
		mHost.collapsePanelsForce();
		Message msg = mHandler.obtainMessage(SCREEN_SHOT_MESSAGE);  
        mHandler.sendMessageDelayed(msg,1000);  
        
        		 
    }  
    @Override  
    protected void handleLongClick() {  
	//mActivityStarter.postStartActivityDismissingKeyguard(
     //               new Intent(), 0);////此方法會自動解鎖
	 mHost.collapsePanelsForce();
     Message msg = mHandler.obtainMessage(SCREEN_SHOT_MESSAGE);  
        mHandler.sendMessageDelayed(msg,1000);  					
       		
    }  
	
	@Override
    public CharSequence getTileLabel() {
        return mContext.getString(R.string.screenshot);
    }
	
	@Override
    public Intent getLongClickIntent() {
        return new Intent();
    }
  
    @Override  
    protected void handleUpdateState(BooleanState state, Object arg) {  
        state.value=false;  
        //state.autoMirrorDrawable=false;  
        state.label = mContext.getString(R.string.screenshot);
        state.icon = ResourceIcon.get(R.drawable.ic_qs_screenshot);
	   //state.visible = true;
}		
@Override
 public int getMetricsCategory(){ 
return MetricsEvent.QS_SCREEN_SHOT; 
} 
}

步驟4

新增一個介面alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\policy\ScreenShotController.java

package com.android.systemui.statusbar.policy;    
    
public interface ScreenShotController{    
        boolean isSupportScreenShot();    
}

步驟5

實現介面ScreenShotController.java

alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\policy\ScreenShotControllerImpl.java

package com.android.systemui.statusbar.policy;    
import android.content.Context;    
public class ScreenShotControllerImpl implements ScreenShotController{    
   private static final String TAG="ScreenShotControllerImpl";    
   private final Context mContext;    
   public ScreenShotControllerImpl(Context context)
   {    mContext=context;    
   }    
   @Override    
   public boolean isSupportScreenShot()
   {     
      return true;    
   }    
}    

步驟6

在alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\Dependency.java定義


import com.android.systemui.statusbar.policy.ScreenShotController;
import com.android.systemui.statusbar.policy.ScreenShotControllerImpl;
......

public class Dependency extends SystemUI {
    ......
    @Override
    public void start() {
       ......
		mProviders.put(ScreenShotController.class, () ->
                new ScreenShotControllerImpl(mContext));
		......
    }

   ......
}

步驟7

alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\screenshot\GlobalScreenshot.java修改許可權

class GlobalScreenshot 修改為 public
把
void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
        mDisplay.getRealMetrics(mDisplayMetrics);
        takeScreenshot(finisher, statusBarVisible, navBarVisible, 0, 0, mDisplayMetrics.widthPixels,
                mDisplayMetrics.heightPixels);
    }

改成
public void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
        mDisplay.getRealMetrics(mDisplayMetrics);
        takeScreenshot(finisher, statusBarVisible, navBarVisible, 0, 0, mDisplayMetrics.widthPixels,
                mDisplayMetrics.heightPixels);
    }

步驟8

至此 就可以實現截圖功能了 ,都是有個問題 就是在步驟3說的 ,mActivityStarter.postStartActivityDismissingKeyguard(
                    new Intent(), 0);呼叫此方法會自動解鎖 ,導致在鎖屏介面無法擷取鎖屏介面。

為此 新定義一個方法。

實現步驟3的collapsePanelsForce方法

在alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\qs\QSHost.java新增


public interface QSHost {
    ......
	void collapsePanelsForce();
	......
}

步驟9

在alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\qs\QSTileHost.java裡實現介面

/** Platform implementation of the quick settings tile host **/
public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory> {

	......
	/**
	   note  screen
	*/
	@Override
    public void collapsePanelsForce() {
        mStatusBar.postAnimateCollapsePanelsForce();
    }
	......

}

步驟10

在alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\phone\StatusBar.java 新增如下方法

/**
     * A:@ for screenshot
     * */

    public void animateCollapsePanelsForce() {
        animateCollapsePanelsForce(CommandQueue.FLAG_EXCLUDE_NONE);
    }
	
	/**
     * A:@ for screenshot
     * */
    private final Runnable mAnimateCollapsePanelsForce = new Runnable() {
        @Override
        public void run() {
            animateCollapsePanelsForce();
        }
    };
	
	/**
     * A:@ for screenshot
     * */
    public void postAnimateCollapsePanelsForce() {
        mHandler.post(mAnimateCollapsePanelsForce);
    }
	
	/**
     * A:@ for screenshot
     * */
    public void animateCollapsePanelsForce(int flags) {
        animateCollapsePanelsForce(flags, true /* force */, false /* delayed */,
                1.0f /* speedUpFactor */);
    }


/**
     * A:@for screenshot
     * */
    public void animateCollapsePanelsForce(int flags, boolean force, boolean delayed,
                                      float speedUpFactor) {
        if (!force && mState != StatusBarState.SHADE) {
            runPostCollapseRunnables();
            return;
        }
        if (SPEW) {
            Log.d(TAG, "animateCollapse():"
                    + " mExpandedVisible=" + mExpandedVisible
                    + " flags=" + flags);
        }

        if ((flags & CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL) == 0) {
            if (!mHandler.hasMessages(MSG_HIDE_RECENT_APPS)) {
                mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
                mHandler.sendEmptyMessage(MSG_HIDE_RECENT_APPS);
            }
        }

        if (mStatusBarWindow != null) {
            // release focus immediately to kick off focus change transition
            mStatusBarWindowManager.setStatusBarFocusable(false);

            mStatusBarWindow.cancelExpandHelper();
            System.out.println("tuliyuan mstats is "+mState);
            if(mState == StatusBarState.KEYGUARD) {
                mStatusBarView.collapsePanelForce(true /* animate */, delayed, speedUpFactor);
            }else{
                mStatusBarView.collapsePanel(true /* animate */, delayed, 2.5f);//speedUpFactor ->2.5f
            }
        }
    }

步驟11

在alps\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\phone\PanelBar.java新增如下方法

/**
     * A:@ for screenshot
     * */
    public void collapsePanelForce(boolean animate, boolean delayed, float speedUpFactor) {
        boolean waiting = false;
        PanelView pv = mPanel;
        if (animate && !pv.isFullyCollapsed()) {
            //pv.collapse(true /* delayed */);
            if(pv instanceof NotificationPanelView){
                ((NotificationPanelView)pv).animateCloseQs();
            }else{
                pv.collapse(true,speedUpFactor/* delayed */);
            }
            waiting = true;
        } else {
            pv.resetViews();
            pv.setExpandedFraction(0); // just in case
            pv.cancelPeek();
        }
        if (DEBUG) LOG("collapsePanel: animate=%s waiting=%s", animate, waiting);
        if (!waiting && mState != STATE_CLOSED) {
            // it's possible that nothing animated, so we replicate the termination
            // conditions of panelExpansionChanged here
            go(STATE_CLOSED);
            onPanelCollapsed();
        }
    }

步驟12

在alps\frameworks\base\proto\src\metrics_constants.proto 新增定義

QS_SCREEN_SHOT = 1144;

步驟13 

在資原始檔新增定義

<string name="screenshot">ScreenShot</string>
<string name="screenshot">截圖</string>

步驟14

新增圖片;也可以用向量畫出圖片

ic_qs_screenshot

到此已經實現啦。。。。。。