Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.incallui.videosurface.impl;
     18 
     19 import android.graphics.Point;
     20 import android.graphics.SurfaceTexture;
     21 import android.view.Surface;
     22 import android.view.TextureView;
     23 import android.view.View;
     24 import com.android.dialer.common.LogUtil;
     25 import com.android.incallui.videosurface.protocol.VideoSurfaceDelegate;
     26 import com.android.incallui.videosurface.protocol.VideoSurfaceTexture;
     27 import java.util.Locale;
     28 import java.util.Objects;
     29 
     30 /**
     31  * Represents a {@link TextureView} and its associated {@link SurfaceTexture} and {@link Surface}.
     32  * Used to manage the lifecycle of these objects across device orientation changes.
     33  */
     34 public class VideoSurfaceTextureImpl implements VideoSurfaceTexture {
     35   @SurfaceType private final int surfaceType;
     36   private VideoSurfaceDelegate delegate;
     37   private TextureView textureView;
     38   private Surface savedSurface;
     39   private SurfaceTexture savedSurfaceTexture;
     40   private Point surfaceDimensions;
     41   private Point sourceVideoDimensions;
     42   private boolean isDoneWithSurface;
     43 
     44   public VideoSurfaceTextureImpl(@SurfaceType int surfaceType) {
     45     this.surfaceType = surfaceType;
     46   }
     47 
     48   @Override
     49   public void setDelegate(VideoSurfaceDelegate delegate) {
     50     LogUtil.i("VideoSurfaceTextureImpl.setDelegate", "delegate: " + delegate + " " + toString());
     51     this.delegate = delegate;
     52   }
     53 
     54   @Override
     55   public int getSurfaceType() {
     56     return surfaceType;
     57   }
     58 
     59   @Override
     60   public Surface getSavedSurface() {
     61     return savedSurface;
     62   }
     63 
     64   @Override
     65   public void setSurfaceDimensions(Point surfaceDimensions) {
     66     LogUtil.i(
     67         "VideoSurfaceTextureImpl.setSurfaceDimensions",
     68         "surfaceDimensions: " + surfaceDimensions + " " + toString());
     69     this.surfaceDimensions = surfaceDimensions;
     70     if (surfaceDimensions != null && savedSurfaceTexture != null) {
     71       savedSurfaceTexture.setDefaultBufferSize(surfaceDimensions.x, surfaceDimensions.y);
     72     }
     73   }
     74 
     75   @Override
     76   public Point getSurfaceDimensions() {
     77     return surfaceDimensions;
     78   }
     79 
     80   @Override
     81   public void setSourceVideoDimensions(Point sourceVideoDimensions) {
     82     this.sourceVideoDimensions = sourceVideoDimensions;
     83   }
     84 
     85   @Override
     86   public Point getSourceVideoDimensions() {
     87     return sourceVideoDimensions;
     88   }
     89 
     90   @Override
     91   public void attachToTextureView(TextureView textureView) {
     92     if (this.textureView == textureView) {
     93       return;
     94     }
     95     LogUtil.i("VideoSurfaceTextureImpl.attachToTextureView", toString());
     96 
     97     if (this.textureView != null) {
     98       this.textureView.setOnClickListener(null);
     99       this.textureView.setSurfaceTextureListener(null);
    100     }
    101 
    102     this.textureView = textureView;
    103     textureView.setSurfaceTextureListener(new SurfaceTextureListener());
    104     textureView.setOnClickListener(new OnClickListener());
    105 
    106     boolean areSameSurfaces = Objects.equals(savedSurfaceTexture, textureView.getSurfaceTexture());
    107     LogUtil.i("VideoSurfaceTextureImpl.attachToTextureView", "areSameSurfaces: " + areSameSurfaces);
    108     if (savedSurfaceTexture != null && !areSameSurfaces) {
    109       textureView.setSurfaceTexture(savedSurfaceTexture);
    110       if (surfaceDimensions != null && createSurface(surfaceDimensions.x, surfaceDimensions.y)) {
    111         onSurfaceCreated();
    112       }
    113     }
    114     isDoneWithSurface = false;
    115   }
    116 
    117   @Override
    118   public void setDoneWithSurface() {
    119     LogUtil.i("VideoSurfaceTextureImpl.setDoneWithSurface", toString());
    120     isDoneWithSurface = true;
    121     if (textureView != null && textureView.isAvailable()) {
    122       return;
    123     }
    124     if (savedSurface != null) {
    125       onSurfaceReleased();
    126       savedSurface.release();
    127       savedSurface = null;
    128     }
    129     if (savedSurfaceTexture != null) {
    130       savedSurfaceTexture.release();
    131       savedSurfaceTexture = null;
    132     }
    133   }
    134 
    135   private boolean createSurface(int width, int height) {
    136     LogUtil.i(
    137         "VideoSurfaceTextureImpl.createSurface",
    138         "width: " + width + ", height: " + height + " " + toString());
    139     savedSurfaceTexture.setDefaultBufferSize(width, height);
    140     if (savedSurface != null) {
    141       savedSurface.release();
    142     }
    143     savedSurface = new Surface(savedSurfaceTexture);
    144     return true;
    145   }
    146 
    147   private void onSurfaceCreated() {
    148     if (delegate != null) {
    149       delegate.onSurfaceCreated(this);
    150     } else {
    151       LogUtil.e("VideoSurfaceTextureImpl.onSurfaceCreated", "delegate is null. " + toString());
    152     }
    153   }
    154 
    155   private void onSurfaceReleased() {
    156     if (delegate != null) {
    157       delegate.onSurfaceReleased(this);
    158     } else {
    159       LogUtil.e("VideoSurfaceTextureImpl.onSurfaceReleased", "delegate is null. " + toString());
    160     }
    161   }
    162 
    163   @Override
    164   public String toString() {
    165     return String.format(
    166         Locale.US,
    167         "VideoSurfaceTextureImpl<%s%s%s%s>",
    168         (surfaceType == SURFACE_TYPE_LOCAL ? "local, " : "remote, "),
    169         (savedSurface == null ? "no-surface, " : ""),
    170         (savedSurfaceTexture == null ? "no-texture, " : ""),
    171         (surfaceDimensions == null
    172             ? "(-1 x -1)"
    173             : (surfaceDimensions.x + " x " + surfaceDimensions.y)));
    174   }
    175 
    176   private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
    177     @Override
    178     public void onSurfaceTextureAvailable(SurfaceTexture newSurfaceTexture, int width, int height) {
    179       LogUtil.i(
    180           "SurfaceTextureListener.onSurfaceTextureAvailable",
    181           "newSurfaceTexture: "
    182               + newSurfaceTexture
    183               + " "
    184               + VideoSurfaceTextureImpl.this.toString());
    185 
    186       // Where there is no saved {@link SurfaceTexture} available, use the newly created one.
    187       // If a saved {@link SurfaceTexture} is available, we are re-creating after an
    188       // orientation change.
    189       boolean surfaceCreated;
    190       if (savedSurfaceTexture == null) {
    191         savedSurfaceTexture = newSurfaceTexture;
    192         surfaceCreated = createSurface(width, height);
    193       } else {
    194         // A saved SurfaceTexture was found.
    195         LogUtil.i(
    196             "SurfaceTextureListener.onSurfaceTextureAvailable", "replacing with cached surface...");
    197         textureView.setSurfaceTexture(savedSurfaceTexture);
    198         surfaceCreated = true;
    199       }
    200 
    201       // Inform the delegate that the surface is available.
    202       if (surfaceCreated) {
    203         onSurfaceCreated();
    204       }
    205     }
    206 
    207     @Override
    208     public boolean onSurfaceTextureDestroyed(SurfaceTexture destroyedSurfaceTexture) {
    209       LogUtil.i(
    210           "SurfaceTextureListener.onSurfaceTextureDestroyed",
    211           "destroyedSurfaceTexture: "
    212               + destroyedSurfaceTexture
    213               + " "
    214               + VideoSurfaceTextureImpl.this.toString());
    215       if (delegate != null) {
    216         delegate.onSurfaceDestroyed(VideoSurfaceTextureImpl.this);
    217       } else {
    218         LogUtil.e("SurfaceTextureListener.onSurfaceTextureDestroyed", "delegate is null");
    219       }
    220 
    221       if (isDoneWithSurface) {
    222         onSurfaceReleased();
    223         if (savedSurface != null) {
    224           savedSurface.release();
    225           savedSurface = null;
    226         }
    227       }
    228       return isDoneWithSurface;
    229     }
    230 
    231     @Override
    232     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}
    233 
    234     @Override
    235     public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
    236   }
    237 
    238   private class OnClickListener implements View.OnClickListener {
    239     @Override
    240     public void onClick(View view) {
    241       if (delegate != null) {
    242         delegate.onSurfaceClick(VideoSurfaceTextureImpl.this);
    243       } else {
    244         LogUtil.e("OnClickListener.onClick", "delegate is null");
    245       }
    246     }
    247   }
    248 }
    249