Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e14378bf authored by Saurabh Shah's avatar Saurabh Shah Committed by Linux Build Service Account
Browse files

frameworks/base: Add support for low resolution rendering

This change is a combination of following changes:

1) frameworks/base: Handle custom activityTrigger flags
    * Take necessary action needed for each vendor specific flag
    set as part of activityTrigger.
    * If the HW acceleration has to be enabled for a particular
    activity, populate the neccessary activityInfo flags.
    * If the resolution needs to be overridden for SurfaceView
    of a specific app, set the overrideRes to 1 in applicationInfo.
    Author: Raj Kamal<rkamal@codeaurora.org>
    Change-Id: Ic835ec1f2ebcc016542ace4050bfef5fb32f20a0

2) frameworks/base: Add support to render certain apps at lower
                    resolution.
    Add support to render certain apps at a resolution lower than the
    primary display device resolution. This would reduce the load on
    GPU and would help in saving power
    Author: Uday Kiran jandhyala<ukiran@codeaurora.org>
    Change-Id: I7004a145f3048aafbfb456451e08ea5ba229cfe9

3)  frameworks/base: Bail out early if Resolution override disabled

    There is a f/w bug that causes the resources to be not initialized
    leading to a crash in ResolutionOverride. This change bails out
    early before calling getResources(), if Resolution override is
    disabled. Also adds null checks for getResources() for cases where
    the feature is enabled.
    Author: Saurabh Shah<saurshah@codeaurora.org>
    Change-Id: I3fa362a153fb39d933b1aa17a5fac8affdd041d8

This change also moves out custom functionality related to
overriding resolution from SurfaceView, to a new class
ResolutionOverride.

Change-Id: Icabc17b9462a347c9c452cc53222ea7dcb6f336b
parent 4d9ec135
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -541,6 +541,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
     */
    public int privateFlags;

    /**
     * Boolean indicating whether the resolution of the SurfaceView associated
     * with this appplication can be overriden.
     * {@hide}
     */
    public int overrideRes = 0;

    /**
     * The required smallest screen width the application can run on.  If 0,
     * nothing has been specified.  Comes from
@@ -897,6 +904,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        theme = orig.theme;
        flags = orig.flags;
        privateFlags = orig.privateFlags;
        overrideRes = orig.overrideRes;
        requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
        compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
        largestWidthLimitDp = orig.largestWidthLimitDp;
@@ -953,6 +961,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        dest.writeInt(theme);
        dest.writeInt(flags);
        dest.writeInt(privateFlags);
        dest.writeInt(overrideRes);
        dest.writeInt(requiresSmallestWidthDp);
        dest.writeInt(compatibleWidthLimitDp);
        dest.writeInt(largestWidthLimitDp);
@@ -1009,6 +1018,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        theme = source.readInt();
        flags = source.readInt();
        privateFlags = source.readInt();
        overrideRes = source.readInt();
        requiresSmallestWidthDp = source.readInt();
        compatibleWidthLimitDp = source.readInt();
        largestWidthLimitDp = source.readInt();
@@ -1214,6 +1224,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
    /** {@hide} */ public void setResourcePath(String resourcePath) { scanPublicSourceDir = resourcePath; }
    /** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; }
    /** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; }
    /** {@hide} */ public void setOverrideRes(int overrideResolution) { overrideRes = overrideResolution; }

    /** {@hide} */ public String getCodePath() { return scanSourceDir; }
    /** {@hide} */ public String getBaseCodePath() { return sourceDir; }
@@ -1221,4 +1232,5 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
    /** {@hide} */ public String getResourcePath() { return scanPublicSourceDir; }
    /** {@hide} */ public String getBaseResourcePath() { return publicSourceDir; }
    /** {@hide} */ public String[] getSplitResourcePaths() { return splitSourceDirs; }
    /** {@hide} */ public int canOverrideRes() { return overrideRes; }
}
+143 −0
Original line number Diff line number Diff line
/* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above
*       copyright notice, this list of conditions and the following
*       disclaimer in the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of The Linux Foundation nor the names of its
*       contributors may be used to endorse or promote products derived
*       from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

package android.util;

import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Matrix;
import android.os.SystemProperties;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;

/** @hide */
public class ResolutionOverride {
    /** @hide */
    static private final boolean DEBUG = false;
    static private final String TAG = "ResolutionOverride";
    private static final String RES_OVERRIDE = "persist.debug.app_res_override";
    private boolean mIsEnabled = false;
    private int mOverrideXres = 0;
    private int mOverrideYres = 0;

    /** @hide */
    public ResolutionOverride(SurfaceView view) {
        boolean enable = (view.getContext().getApplicationInfo().canOverrideRes() == 1);
        String resStr = SystemProperties.get(RES_OVERRIDE, null);

        if (!enable || resStr == null || resStr.length() == 0 ||
                view.getResources() == null) {
            return;
        }

        int orientation = view.getResources().getConfiguration().orientation;

        if(orientation == Configuration.ORIENTATION_PORTRAIT ||
                orientation == Configuration.ORIENTATION_LANDSCAPE) {
            resStr = resStr.toLowerCase();
            final int pos = resStr.indexOf('x');
            if (pos > 0 && resStr.lastIndexOf('x') == pos) {
                try {
                    mOverrideXres = Integer.parseInt(resStr.substring(0, pos));
                    mOverrideYres = Integer.parseInt(resStr.substring(pos + 1));
                } catch (NumberFormatException ex) {
                    Log.e(TAG, "Error in extracting the overriding xres and yres");
                }
            }

            if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
                int tmp = mOverrideXres;
                mOverrideXres = mOverrideYres;
                mOverrideYres = tmp;
            }

            if(mOverrideXres > 0 && mOverrideYres > 0) {
                mIsEnabled = true;
                if (DEBUG) Log.i(TAG, "Orientation: " + orientation +
                        " Overriding resolution to" + " xres: " + mOverrideXres
                        + " yres: " + mOverrideYres);
            }
        }
    }

    /** @hide */
    public void setFixedSize(SurfaceView view) {
        if(!mIsEnabled) {
            return;
        }

        view.getHolder().setFixedSize(mOverrideXres, mOverrideYres);
    }

    /** @hide */
    public void handleTouch(SurfaceView view, MotionEvent ev) {
        if(!mIsEnabled) {
            return;
        }

        Matrix matrix = new Matrix();
        //mOverride{Xres, Yres} are already swapped if orientation is landscape
        float xscale = (mOverrideXres * 1.0f) / view.getWidth();
        float yscale = (mOverrideYres * 1.0f) / view.getHeight();

        if (DEBUG) Log.i(TAG, "Before overriding the touch event x/y : " + ev);
        matrix.postScale(xscale, yscale);
        ev.transform(matrix);
        if (DEBUG) Log.i(TAG, "After overriding the touch event x/y : " + ev);
    }

    /** @hide */
    public void handleResize(final SurfaceView surfaceView) {
        if(!mIsEnabled) {
            return;
        }

        /* Change the visibility to GONE and back to VISIBLE and post it
         * on the main thread for the touch events to be effective on the
         * changed SurfaceView with the new dimensions
         */
        surfaceView.post(new Runnable() {
            @Override
            public void run() {
                surfaceView.setVisibility(View.GONE);
            }
        });

        surfaceView.postDelayed(new Runnable() {
            @Override
            public void run() {
                surfaceView.setVisibility(View.VISIBLE);
            }
        }, 100);
    }
};
+18 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.os.SystemClock;
import android.os.ParcelFileDescriptor;
import android.util.AttributeSet;
import android.util.Log;
import android.util.ResolutionOverride;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -189,6 +190,7 @@ public class SurfaceView extends View {
    private Translator mTranslator;
    private int mWindowInsetLeft;
    private int mWindowInsetTop;
    ResolutionOverride mResolutionOverride = null;

    private boolean mGlobalListenersAdded;

@@ -214,6 +216,8 @@ public class SurfaceView extends View {

    private void init() {
        setWillNotDraw(true);
        mResolutionOverride = new ResolutionOverride(this);
        mResolutionOverride.setFixedSize(this);
    }

    /**
@@ -306,6 +310,16 @@ public class SurfaceView extends View {
        setMeasuredDimension(width, height);
    }

    /**
     * Transforms the touch events to the new resolution coordinate system
     * if the resolution has changed
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        mResolutionOverride.handleTouch(this, ev);
        return super.dispatchTouchEvent(ev);
    }

    /** @hide */
    @Override
    protected boolean setFrame(int left, int top, int right, int bottom) {
@@ -809,10 +823,13 @@ public class SurfaceView extends View {
                Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
                Configuration newConfig, Rect backDropRect, boolean forceLayout,
                boolean alwaysConsumeNavBar) {
            SurfaceView surfaceView = mSurfaceView.get();
            final SurfaceView surfaceView = mSurfaceView.get();
            if (surfaceView != null) {
                if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
                        + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);

                surfaceView.mResolutionOverride.handleResize(surfaceView);

                surfaceView.mSurfaceLock.lock();
                try {
                    if (reportDraw) {
+22 −7
Original line number Diff line number Diff line
@@ -31,12 +31,19 @@ package com.android.internal.app;

import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.util.Log;

public class ActivityTrigger
{
    private static final String TAG = "ActivityTrigger";

    private static final int FLAG_OVERRIDE_RESOLUTION = 1;
    private static final int FLAG_HARDWARE_ACCELERATED =
            ActivityInfo.FLAG_HARDWARE_ACCELERATED;


    /** &hide */
    public ActivityTrigger() {
        //Log.d(TAG, "ActivityTrigger initialized");
@@ -48,23 +55,31 @@ public class ActivityTrigger
    }

    /** &hide */
    public int activityStartTrigger(Intent intent, int flags) {
    public void activityStartTrigger(Intent intent, ActivityInfo acInfo, ApplicationInfo appInfo) {
        ComponentName cn = intent.getComponent();
        int overrideFlags = 0;
        String activity = null;

        if(cn != null)
            activity = cn.flattenToString();
        flags = native_at_startActivity(activity, flags);
        return flags;
            activity = cn.flattenToString() + "/" + appInfo.versionCode;

        overrideFlags = native_at_startActivity(activity, overrideFlags);

        if((overrideFlags & FLAG_HARDWARE_ACCELERATED) != 0) {
            acInfo.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
        }
        if((overrideFlags & FLAG_OVERRIDE_RESOLUTION) != 0) {
            appInfo.setOverrideRes(1);
        }
    }

    /** &hide */
    public void activityResumeTrigger(Intent intent) {
    public void activityResumeTrigger(Intent intent, ActivityInfo acInfo, ApplicationInfo appInfo) {
        ComponentName cn = intent.getComponent();
        String activity = null;

        if (cn != null)
            activity = cn.flattenToString();
            activity = cn.flattenToString() + "/" + appInfo.versionCode;
        native_at_resumeActivity(activity);
    }

+2 −2
Original line number Diff line number Diff line
@@ -2237,7 +2237,7 @@ final class ActivityStack {

        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);

        mActivityTrigger.activityResumeTrigger(next.intent);
        mActivityTrigger.activityResumeTrigger(next.intent, next.info, next.appInfo);

        // If we are currently pausing an activity, then don't do anything
        // until that is done.
@@ -2706,7 +2706,7 @@ final class ActivityStack {
        task.setFrontOfTask();

        r.putInHistory();
        r.info.flags = mActivityTrigger.activityStartTrigger(r.intent, r.info.flags);
        mActivityTrigger.activityStartTrigger(r.intent, r.info, r.appInfo);
        if (!isHomeStack() || numActivities() > 0) {
            // We want to show the starting preview window if we are
            // switching to a new task, or the next activity's process is