1 package org.coolreader.crengine; 2 3 import android.content.Context; 4 import android.util.Log; 5 import android.view.View; 6 7 import com.onyx.android.sdk.api.device.epd.EpdController; 8 import com.onyx.android.sdk.api.device.epd.UpdateMode; 9 import com.onyx.android.sdk.device.Device; 10 11 import org.coolreader.CoolReader; 12 13 import java.util.Arrays; 14 import java.util.List; 15 16 public class EinkScreenOnyx implements EinkScreen { 17 18 public static final Logger log = L.create("onyx", Log.VERBOSE); 19 20 private EinkUpdateMode mUpdateMode = EinkUpdateMode.Unspecified; 21 private int mUpdateInterval; 22 private int mRefreshNumber = -1; 23 private boolean mInFastMode = false; 24 private boolean mInA2Mode = false; 25 // Front light levels 26 private List<Integer> mFrontLineLevels = null; 27 private List<Integer> mWarmLightLevels = null; 28 private UpdateMode mOnyxUpdateMode = UpdateMode.None; 29 private int mExtraDelayFullRefresh = 0; 30 31 @Override setupController(EinkUpdateMode mode, int updateInterval, View view)32 public void setupController(EinkUpdateMode mode, int updateInterval, View view) { 33 mUpdateInterval = updateInterval; 34 if (mUpdateMode.equals(mode)) 35 return; 36 log.d("EinkScreenOnyx.setupController(): mode=" + mode); 37 EpdController.enableScreenUpdate(view, true); 38 mRefreshNumber = 0; 39 EpdController.clearApplicationFastMode(); 40 UpdateMode onyxFastUpdateMode = UpdateMode.DU; 41 switch (Device.currentDeviceIndex()) { 42 case Rk32xx: 43 case Rk33xx: 44 case SDM: 45 onyxFastUpdateMode = UpdateMode.DU_QUALITY; 46 break; 47 } 48 switch (Device.currentDeviceIndex()) { 49 // TODO: check other ONYX devices & platforms 50 case SDM: 51 // Hack, use additional delay before full screen update 52 mExtraDelayFullRefresh = 20; 53 break; 54 } 55 switch (mode) { 56 case Regal: // Regal 57 if (mInA2Mode) { 58 onyxEnableA2Mode(view, false); 59 mInA2Mode = false; 60 } 61 if (mInFastMode) { 62 EpdController.applyApplicationFastMode(CoolReader.class.getSimpleName(), false, true); 63 mInFastMode = false; 64 } 65 mOnyxUpdateMode = UpdateMode.REGAL; 66 break; 67 case Clear: // Quality 68 if (mInA2Mode) { 69 onyxEnableA2Mode(view, false); 70 mInA2Mode = false; 71 } 72 if (mInFastMode) { 73 EpdController.applyApplicationFastMode(CoolReader.class.getSimpleName(), false, true); 74 mInFastMode = false; 75 } 76 mOnyxUpdateMode = UpdateMode.GU; 77 break; 78 case Fast: // Fast 79 if (mInA2Mode) { 80 onyxEnableA2Mode(view, false); 81 mInA2Mode = false; 82 } 83 // Enable fast mode (not implemented on RK3026) 84 if (!mInFastMode) { 85 EpdController.applyApplicationFastMode(CoolReader.class.getSimpleName(), true, true, UpdateMode.DU_QUALITY, Integer.MAX_VALUE); 86 mInFastMode = true; 87 } 88 mOnyxUpdateMode = onyxFastUpdateMode; 89 break; 90 case A2: // A2 mode 91 if (mInFastMode) { 92 EpdController.applyApplicationFastMode(CoolReader.class.getSimpleName(), false, true); 93 mInFastMode = false; 94 } 95 if (!mInA2Mode) { 96 onyxEnableA2Mode(view, true); 97 mInA2Mode = true; 98 } 99 mOnyxUpdateMode = onyxFastUpdateMode; 100 break; 101 default: 102 mOnyxUpdateMode = UpdateMode.GU; 103 } 104 if (null != view) { 105 EpdController.setViewDefaultUpdateMode(view, mOnyxUpdateMode); 106 BackgroundThread.instance().executeGUI(view::invalidate); 107 } 108 mUpdateMode = mode; 109 } 110 111 @Override prepareController(View view, boolean isPartially)112 public void prepareController(View view, boolean isPartially) { 113 if (mRefreshNumber == -1) { 114 mRefreshNumber = 0; 115 onyxRepaintEveryThing(view, false); 116 return; 117 } 118 if (mUpdateInterval > 0) { 119 mRefreshNumber++; 120 if (mRefreshNumber >= mUpdateInterval) { 121 mRefreshNumber = 0; 122 return; 123 } 124 } 125 if (mRefreshNumber > 0 || mUpdateInterval == 0) { 126 EpdController.setViewDefaultUpdateMode(view, mOnyxUpdateMode); 127 if (Device.DeviceIndex.Rk32xx == Device.currentDeviceIndex()) { 128 // Hack, without it, the image on rk3288 will not updated. 129 // Found by brute force. 130 EpdController.byPass(0); 131 } 132 } 133 } 134 135 @Override updateController(View view, boolean isPartially)136 public void updateController(View view, boolean isPartially) { 137 if (0 == mRefreshNumber && mUpdateInterval > 0) { 138 if (mExtraDelayFullRefresh > 0) { 139 // Hack, on ONYX devices with SDM platform without this delay full screen refresh runs too early 140 // (before new page appears on screen) 141 // This functions called after android.view.SurfaceHolder.unlockCanvasAndPost() 142 // See https://developer.android.com/reference/android/view/SurfaceHolder#unlockCanvasAndPost(android.graphics.Canvas) 143 // which guarantees that by this time the new image will be on the screen 144 // But in fact on com.onyx.android.sdk.device.Device.DeviceIndex.SDM need extra delay. 145 try { 146 Thread.sleep(mExtraDelayFullRefresh); 147 } catch (InterruptedException ignored) { 148 } 149 } 150 onyxRepaintEveryThing(view, false); 151 } 152 } 153 154 @Override refreshScreen(View view)155 public void refreshScreen(View view) { 156 onyxRepaintEveryThing(view, true); 157 mRefreshNumber = 0; 158 } 159 160 @Override getUpdateMode()161 public EinkUpdateMode getUpdateMode() { 162 return mUpdateMode; 163 } 164 165 @Override getUpdateInterval()166 public int getUpdateInterval() { 167 return mUpdateInterval; 168 } 169 170 @Override getFrontLightValue(Context context)171 public int getFrontLightValue(Context context) { 172 int res = 0; 173 try { 174 if (DeviceInfo.ONYX_HAVE_NATURAL_BACKLIGHT) { 175 res = Device.currentDevice().getColdLightConfigValue(context); 176 } else { 177 res = Device.currentDevice().getFrontLightDeviceValue(context); 178 } 179 } catch (Exception ignored) {} 180 return res; 181 } 182 183 @Override setFrontLightValue(Context context, int value)184 public boolean setFrontLightValue(Context context, int value) { 185 boolean res = false; 186 if (DeviceInfo.ONYX_HAVE_FRONTLIGHT) { 187 if (value >= 0) { 188 Integer alignedValue = Utils.findNearestValue(getFrontLightLevels(context), value); 189 if (null != alignedValue) { 190 if (DeviceInfo.ONYX_HAVE_NATURAL_BACKLIGHT) { 191 res = Device.currentDevice().setColdLightDeviceValue(context, alignedValue); 192 } else { 193 if (Device.currentDevice().setFrontLightDeviceValue(context, alignedValue)) 194 res = Device.currentDevice().setFrontLightConfigValue(context, alignedValue); 195 } 196 } 197 } else { 198 // system default, just ignore 199 } 200 } 201 return res; 202 } 203 204 @Override getWarmLightValue(Context context)205 public int getWarmLightValue(Context context) { 206 int res = 0; 207 try { 208 if (DeviceInfo.ONYX_HAVE_NATURAL_BACKLIGHT) { 209 res = Device.currentDevice().getWarmLightConfigValue(context); 210 } 211 } catch (Exception ignored) {} 212 return res; 213 } 214 215 @Override setWarmLightValue(Context context, int value)216 public boolean setWarmLightValue(Context context, int value) { 217 boolean res = false; 218 if (DeviceInfo.ONYX_HAVE_NATURAL_BACKLIGHT) { 219 if (value >= 0) { 220 Integer alignedValue = Utils.findNearestValue(getWarmLightLevels(context), value); 221 if (null != alignedValue) { 222 res = Device.currentDevice().setWarmLightDeviceValue(context, alignedValue); 223 } 224 } else { 225 // system default, just ignore 226 } 227 } 228 return res; 229 } 230 231 @Override getFrontLightLevels(Context context)232 public List<Integer> getFrontLightLevels(Context context) { 233 if (DeviceInfo.ONYX_HAVE_FRONTLIGHT || DeviceInfo.ONYX_HAVE_NATURAL_BACKLIGHT) { 234 if (null == mFrontLineLevels) { 235 try { 236 mFrontLineLevels = Device.currentDevice().getFrontLightValueList(context); 237 } catch (Exception ignored) { } 238 if (null == mFrontLineLevels || mFrontLineLevels.size() == 0) { 239 Integer[] values = Device.currentDevice().getColdLightValues(context); 240 if (null != values) { 241 mFrontLineLevels = Arrays.asList(values); 242 } 243 } 244 } 245 } 246 return mFrontLineLevels; 247 } 248 249 @Override getWarmLightLevels(Context context)250 public List<Integer> getWarmLightLevels(Context context) { 251 if (DeviceInfo.EINK_HAVE_NATURAL_BACKLIGHT) { 252 if (null == mWarmLightLevels) { 253 if (DeviceInfo.ONYX_HAVE_NATURAL_BACKLIGHT) { 254 Integer[] values = Device.currentDevice().getWarmLightValues(context); 255 if (null != values) { 256 mWarmLightLevels = Arrays.asList(values); 257 } 258 } 259 } 260 } 261 return mWarmLightLevels; 262 } 263 264 265 // private methods onyxRepaintEveryThing(View view, boolean invalidate)266 private void onyxRepaintEveryThing(View view, boolean invalidate) { 267 switch (Device.currentDeviceIndex()) { 268 case Rk31xx: 269 case Rk32xx: 270 case Rk33xx: 271 case SDM: 272 EpdController.repaintEveryThing(UpdateMode.GC); 273 break; 274 default: 275 if (null != view) { 276 EpdController.setViewDefaultUpdateMode(view, UpdateMode.GC); 277 if (invalidate) 278 view.postInvalidate(); 279 } 280 break; 281 } 282 } 283 onyxEnableA2Mode(View view, boolean enable)284 private void onyxEnableA2Mode(View view, boolean enable) { 285 switch (Device.currentDeviceIndex()) { 286 case Rk3026: 287 case imx6: 288 case imx7: 289 if (enable) 290 EpdController.enableA2ForSpecificView(view); 291 else 292 EpdController.disableA2ForSpecificView(view); 293 break; 294 default: 295 EpdController.clearApplicationFastMode(); 296 if (enable) 297 EpdController.applyApplicationFastMode(CoolReader.class.getSimpleName(), true, true, UpdateMode.ANIMATION_QUALITY, Integer.MAX_VALUE); 298 else 299 EpdController.applyApplicationFastMode(CoolReader.class.getSimpleName(), false, true); 300 break; 301 } 302 } 303 } 304