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

Commit c70bd192 authored by Jim Miller's avatar Jim Miller Committed by Android (Google) Code Review
Browse files

Merge "Fix 2797185: Integrate 3D RecentApps View into system."

parents d7c2f623 e6ad1a8b
Loading
Loading
Loading
Loading
+27 −5
Original line number Diff line number Diff line
@@ -16,21 +16,26 @@

package com.android.internal.widget;

import com.android.internal.R;
import com.android.internal.widget.CarouselRS.CarouselCallback;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Bitmap.Config;
import android.renderscript.FileA3D;
import android.renderscript.Mesh;
import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScriptGL;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

public class CarouselView extends RSSurfaceView {
    private static final boolean USE_DEPTH_BUFFER = true;
    private final int DEFAULT_SLOT_COUNT = 10;
    private final Bitmap DEFAULT_BITMAP = Bitmap.createBitmap(1, 1, Config.RGB_565);
    private static final String TAG = "CarouselView";
@@ -48,18 +53,26 @@ public class CarouselView extends RSSurfaceView {
    private int mSlotCount = DEFAULT_SLOT_COUNT;

    public CarouselView(Context context) {
        super(context);
        this(context, null);
    }

    /**
     * Constructor used when this widget is created from a layout file.
     */
    public CarouselView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        boolean useDepthBuffer = true;
        mRS = createRenderScript(useDepthBuffer);
        mRS = createRenderScript(USE_DEPTH_BUFFER);
        mRenderScript = new CarouselRS();
        mRenderScript.init(mRS, getResources());
        // TODO: add parameters to layout
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        super.surfaceChanged(holder, format, w, h);
        mRS.contextSetSurface(w, h, holder.getSurface());
        //mRS.contextSetSurface(w, h, holder.getSurface());
        mRenderScript.init(mRS, getResources());
        setSlotCount(mSlotCount);
        createCards(mCardCount);
@@ -172,12 +185,21 @@ public class CarouselView extends RSSurfaceView {
    
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if(mRS != null) {
            mRS = null;
            destroyRenderScript();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mRS == null) {
            mRS = createRenderScript(USE_DEPTH_BUFFER);
        }
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int action = event.getAction();
+69 −34
Original line number Diff line number Diff line
@@ -53,19 +53,22 @@ enum {
};

// Client messages *** THIS LIST MUST MATCH THOSE IN CarouselRS.java. ***
const int CMD_CARD_SELECTED = 100;
const int CMD_REQUEST_TEXTURE = 200;
const int CMD_INVALIDATE_TEXTURE = 210;
const int CMD_REQUEST_GEOMETRY = 300;
const int CMD_INVALIDATE_GEOMETRY = 310;
const int CMD_ANIMATION_STARTED = 400;
const int CMD_ANIMATION_FINISHED = 500;
const int CMD_PING = 600;

static const int CMD_CARD_SELECTED = 100;
static const int CMD_REQUEST_TEXTURE = 200;
static const int CMD_INVALIDATE_TEXTURE = 210;
static const int CMD_REQUEST_GEOMETRY = 300;
static const int CMD_INVALIDATE_GEOMETRY = 310;
static const int CMD_ANIMATION_STARTED = 400;
static const int CMD_ANIMATION_FINISHED = 500;
static const int CMD_PING = 600;

// Constants
static const int ANIMATION_SCALE_TIME = 200; // Time it takes to animate selected card, in ms
static const float3 SELECTED_SCALE_FACTOR = { 0.2f, 0.2f, 0.2f }; // increase by this %

// Debug flags
bool debugCamera = false;
bool debugPicking = false;
bool debugCamera = false; // dumps ray/camera coordinate stuff
bool debugPicking = false; // renders picking area on top of geometry

// Exported variables. These will be reflected to Java set_* variables.
Card_t *cards; // array of cards to draw
@@ -96,8 +99,11 @@ rs_matrix4x4 modelviewMatrix;
static float bias; // rotation bias, in radians. Used for animation and dragging.
static bool updateCamera;    // force a recompute of projection and lookat matrices
static bool initialized;
static float3 backgroundColor = { 0.5f, 0.5f, 0.5f };
static float3 backgroundColor = { 0.0f, 0.0f, 0.0f };
static const float FLT_MAX = 1.0e37;
static int currentSelection = -1;
static int64_t touchTime = -1;  // time of first touch (see doStart())
static float touchBias = 0.0f; // bias on first touch

// Default geometry when card.geometry is not set.
static const float3 cardVertices[4] = {
@@ -121,10 +127,12 @@ static PerspectiveCamera camera = {
// Forward references
static int intersectGeometry(Ray* ray, float *bestTime);
static bool makeRayForPixelAt(Ray* ray, float x, float y);
static float deltaTimeInSeconds(int64_t current);

void init() {
    // initializers currently have a problem when the variables are exported, so initialize
    // globals here.
    rsDebug("Renderscript: init()", 0);
    startAngle = 0.0f;
    slotCount = 10;
    visibleSlotCount = 1;
@@ -245,12 +253,24 @@ void setGeometry(int n, rs_mesh geometry)
        cards[n].geometryState = STATE_INVALID;
}

static float3 getAnimatedScaleForSelected()
{
    int64_t dt = (rsUptimeMillis() - touchTime);
    float fraction = (dt < ANIMATION_SCALE_TIME) ? (float) dt / ANIMATION_SCALE_TIME : 1.0f;
    const float3 one = { 1.0f, 1.0f, 1.0f };
    return one + fraction * SELECTED_SCALE_FACTOR;
}

static void getMatrixForCard(rs_matrix4x4* matrix, int i)
{
    float theta = cardPosition(i);
    rsMatrixRotate(matrix, degrees(theta), 0, 1, 0);
    rsMatrixTranslate(matrix, radius, 0, 0);
    rsMatrixRotate(matrix, degrees(-theta + cardRotation), 0, 1, 0);
    if (i == currentSelection) {
        float3 scale = getAnimatedScaleForSelected();
        rsMatrixScale(matrix, scale.x, scale.y, scale.z);
    }
    // TODO: apply custom matrix for cards[i].geometry
}

@@ -353,27 +373,30 @@ void doStart(float x, float y)
    }
    velocityTracker = 0.0f;
    velocityTrackerCount = 0;
    touchTime = rsUptimeMillis();
    touchBias = bias;
    currentSelection = doSelection(x, y);
}


void doStop(float x, float y)
{
    int64_t currentTime = rsUptimeMillis();
    updateAllocationVars();

    if (currentSelection != -1 && (currentTime - touchTime) < ANIMATION_SCALE_TIME) {
        rsDebug("HIT!", currentSelection);
        int data[1];
        data[0] = currentSelection;
        rsSendToClientBlocking(CMD_CARD_SELECTED, data, sizeof(data));
    } else {
        velocity = velocityTrackerCount > 0 ?
                    (velocityTracker / velocityTrackerCount) : 0.0f;  // avg velocity
        if (fabs(velocity) > velocityThreshold) {
            animating = true;
            rsSendToClient(CMD_ANIMATION_STARTED);
    } else {
        const int selection = doSelection(x, y);  // velocity too small; treat as a tap
        if (selection != -1) {
            rsDebug("HIT!", selection);
            int data[1];
            data[0] = selection;
            rsSendToClient(CMD_CARD_SELECTED, data, sizeof(data));
        }
    }
    currentSelection = -1;
    lastTime = rsUptimeMillis();
}

@@ -395,6 +418,14 @@ void doMotion(float x, float y)
        //    velocityTrackerCount = 1;
        //}
    }

    // Drop current selection if user drags position +- a partial slot
    if (currentSelection != -1) {
        const float slotMargin = 0.5f * (2.0f * M_PI / slotCount);
        if (fabs(touchBias - bias) > slotMargin) {
            currentSelection = -1;
        }
    }
    lastTime = currentTime;
}

@@ -431,6 +462,8 @@ rayTriangleIntersect(Ray* ray, float3 p0, float3 p1, float3 p2, float *tout)
    return true;
}

// Creates a ray for an Android pixel coordinate.
// Note that the Y coordinate is opposite of GL rendering coordinates.
static bool makeRayForPixelAt(Ray* ray, float x, float y)
{
    if (debugCamera) {
@@ -444,7 +477,7 @@ static bool makeRayForPixelAt(Ray* ray, float x, float y)
    // TODO: pre-compute lowerLeftRay, du, dv to eliminate most of this math.
    if (true) {
        const float u = x / rsgGetWidth();
        const float v = (y / rsgGetHeight());
        const float v = 1.0f - (y / rsgGetHeight());
        const float aspect = (float) rsgGetWidth() / rsgGetHeight();
        const float tanfov2 = 2.0f * tan(radians(camera.fov / 2.0f));
        float3 dir = normalize(camera.at - camera.from);
@@ -537,9 +570,8 @@ static int intersectGeometry(Ray* ray, float *bestTime)
// This method computes the position of all the cards by updating bias based on a
// simple physics model.
// If the cards are still in motion, returns true.
static bool updateNextPosition()
static bool updateNextPosition(int64_t currentTime)
{
    int64_t currentTime = rsUptimeMillis();
    if (animating) {
        float dt = deltaTimeInSeconds(currentTime);
        if (dt <= 0.0f)
@@ -658,8 +690,7 @@ static void updateCardResources()
            // ask the host to remove the texture
            if (cards[i].textureState == STATE_LOADED) {
                data[0] = i;
                bool enqueued = true;
                rsSendToClientBlocking(CMD_INVALIDATE_TEXTURE, data, sizeof(data));
                bool enqueued = rsSendToClient(CMD_INVALIDATE_TEXTURE, data, sizeof(data));
                if (enqueued) {
                    cards[i].textureState = STATE_INVALID;
                } else {
@@ -669,8 +700,7 @@ static void updateCardResources()
            // ask the host to remove the geometry
            if (cards[i].geometryState == STATE_LOADED) {
                data[0] = i;
                bool enqueued = true;
                rsSendToClientBlocking(CMD_INVALIDATE_GEOMETRY, data, sizeof(data));
                bool enqueued = rsSendToClient(CMD_INVALIDATE_GEOMETRY, data, sizeof(data));
                if (enqueued) {
                    cards[i].geometryState = STATE_INVALID;
                } else {
@@ -699,7 +729,7 @@ static void renderWithRays()
            if (makeRayForPixelAt(&ray, posX, posY)) {
                float bestTime = FLT_MAX;
                if (intersectGeometry(&ray, &bestTime) != -1) {
                    rsgDrawSpriteScreenspace(posX, posY, 0.0f, 2.0f, 2.0f);
                    rsgDrawSpriteScreenspace(posX, h - posY - 1, 0.0f, 2.0f, 2.0f);
                }
            }
        }
@@ -707,8 +737,9 @@ static void renderWithRays()
}

int root() {
    rsgClearDepth(1.0f);
    int64_t currentTime = rsUptimeMillis();

    rsgClearDepth(1.0f);
    rsgBindProgramVertex(vertexProgram);
    rsgBindProgramFragment(fragmentProgram);
    rsgBindProgramStore(programStore);
@@ -735,7 +766,11 @@ int root() {

    updateCameraMatrix(rsgGetWidth(), rsgGetHeight());

    bool stillAnimating = updateNextPosition();
    const bool timeExpired = (currentTime - touchTime) > ANIMATION_SCALE_TIME;
    if (timeExpired) {
        //currentSelection = -1;
    }
    bool stillAnimating = updateNextPosition(currentTime) || !timeExpired;

    cullCards();

+55 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- Title -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="#80FFFFFF"
        android:textStyle="bold"
        android:singleLine="true"
        android:text="@android:string/recent_tasks_title"
        android:visibility="gone"/>

    <!-- This is only intended to be visible when carousel is invisible -->
    <TextView
        android:id="@+id/no_applications_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="@android:string/no_recent_tasks"
        android:visibility="gone"/>

    <com.android.internal.widget.CarouselView
        android:id="@+id/carousel"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1">
    </com.android.internal.widget.CarouselView>

</LinearLayout>
+4 −0
Original line number Diff line number Diff line
@@ -29,5 +29,9 @@
    <bool name="config_enableSlidingTabFirst">false</bool>
    <!-- Enable lockscreen rotation -->
    <bool name="config_enableLockScreenRotation">true</bool>

    <!-- Enables 3d task switcher on xlarge device -->
    <bool name="config_enableRecentApps3D">true</bool>

</resources>
+5 −1
Original line number Diff line number Diff line
@@ -29,5 +29,9 @@
    <dimen name="password_keyboard_key_height_alpha">0.35in</dimen>
    <!-- Default height of a key in the password keyboard for numeric -->
    <dimen name="password_keyboard_key_height_numeric">0.47in</dimen>
</resources>

    <!-- The width that is used when creating thumbnails of applications. -->
    <dimen name="thumbnail_width">256dp</dimen>
    <!-- The height that is used when creating thumbnails of applications. -->
    <dimen name="thumbnail_height">255dp</dimen>
</resources>
Loading